From cd7484d05cd4b7a9d741fe8bf6c4525406ed7620 Mon Sep 17 00:00:00 2001 From: Chung-Lin Tang Date: Fri, 14 Jan 2022 21:58:34 +0800 Subject: openmp: Fix ICE in [PR103705] Fix ICE for cases like: #pragma omp target update from(s[0].a[0:1]) where multiple ARRAY_REF nodes exist and require more than one peeling during [c_]finish_omp_clauses. PR c++/103705 gcc/c/ChangeLog: * c-typeck.c (c_finish_omp_clauses): Also continue peeling off of outer node for ARRAY_REFs. gcc/cp/ChangeLog: * semantics.c (finish_omp_clauses): Also continue peeling off of outer node for ARRAY_REFs. gcc/testsuite/ChangeLog: * c-c++-common/gomp/pr103705.c: New test. --- gcc/c/c-typeck.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc/c') diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 8b492cf..ac6618e 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -14929,7 +14929,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) t = TREE_OPERAND (t, 0); } } - while (TREE_CODE (t) == COMPONENT_REF); + while (TREE_CODE (t) == COMPONENT_REF + || TREE_CODE (t) == ARRAY_REF); if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && OMP_CLAUSE_MAP_IMPLICIT (c) -- cgit v1.1 From 617db51d7ebef18912c158a890728e164f2d8927 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 15 Jan 2022 00:16:27 +0000 Subject: Daily bump. --- gcc/c/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/c') diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index c3933da..8463f0d 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2022-01-14 Chung-Lin Tang + + PR c++/103705 + * c-typeck.c (c_finish_omp_clauses): Also continue peeling off of + outer node for ARRAY_REFs. + 2022-01-01 Jakub Jelinek PR objc/103639 -- cgit v1.1 From 450c85b81f4dd67bf6211d307afdc0f3c07ef44f Mon Sep 17 00:00:00 2001 From: Andrew Stubbs Date: Thu, 16 Dec 2021 15:30:05 +0000 Subject: OpenMP: allow requires dynamic_allocators There's no need to reject the dynamic_allocators requires directive because we actually do support the feature, and it doesn't have to actually "do" anything. gcc/c/ChangeLog: * c-parser.c (c_parser_omp_requires): Don't "sorry" dynamic_allocators. gcc/cp/ChangeLog: * parser.c (cp_parser_omp_requires): Don't "sorry" dynamic_allocators. gcc/fortran/ChangeLog: * openmp.c (gfc_match_omp_requires): Don't "sorry" dynamic_allocators. gcc/testsuite/ChangeLog: * gfortran.dg/gomp/requires-8.f90: Reinstate dynamic allocators requirement. --- gcc/c/c-parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/c') diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 6ada004..20774f7 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -22583,7 +22583,7 @@ c_parser_omp_requires (c_parser *parser) c_parser_skip_to_pragma_eol (parser, false); return; } - if (p) + if (p && this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS) sorry_at (cloc, "%qs clause on % directive not " "supported yet", p); if (p) -- cgit v1.1 From 5c69acb32329d49e58c26fa41ae74229a52b9106 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 14 Jan 2022 16:56:44 +0100 Subject: 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. --- gcc/c/c-aux-info.c | 569 -- gcc/c/c-aux-info.cc | 569 ++ gcc/c/c-convert.c | 207 - gcc/c/c-convert.cc | 207 + gcc/c/c-decl.c | 12469 ------------------------- gcc/c/c-decl.cc | 12469 +++++++++++++++++++++++++ gcc/c/c-errors.c | 163 - gcc/c/c-errors.cc | 163 + gcc/c/c-fold.c | 698 -- gcc/c/c-fold.cc | 698 ++ gcc/c/c-lang.c | 72 - gcc/c/c-lang.cc | 72 + gcc/c/c-objc-common.c | 396 - gcc/c/c-objc-common.cc | 396 + gcc/c/c-parser.c | 23404 ----------------------------------------------- gcc/c/c-parser.cc | 23404 +++++++++++++++++++++++++++++++++++++++++++++++ gcc/c/c-typeck.c | 16079 -------------------------------- gcc/c/c-typeck.cc | 16079 ++++++++++++++++++++++++++++++++ gcc/c/gccspec.c | 107 - gcc/c/gccspec.cc | 107 + gcc/c/gimple-parser.c | 2453 ----- gcc/c/gimple-parser.cc | 2453 +++++ 22 files changed, 56617 insertions(+), 56617 deletions(-) delete mode 100644 gcc/c/c-aux-info.c create mode 100644 gcc/c/c-aux-info.cc delete mode 100644 gcc/c/c-convert.c create mode 100644 gcc/c/c-convert.cc delete mode 100644 gcc/c/c-decl.c create mode 100644 gcc/c/c-decl.cc delete mode 100644 gcc/c/c-errors.c create mode 100644 gcc/c/c-errors.cc delete mode 100644 gcc/c/c-fold.c create mode 100644 gcc/c/c-fold.cc delete mode 100644 gcc/c/c-lang.c create mode 100644 gcc/c/c-lang.cc delete mode 100644 gcc/c/c-objc-common.c create mode 100644 gcc/c/c-objc-common.cc delete mode 100644 gcc/c/c-parser.c create mode 100644 gcc/c/c-parser.cc delete mode 100644 gcc/c/c-typeck.c create mode 100644 gcc/c/c-typeck.cc delete mode 100644 gcc/c/gccspec.c create mode 100644 gcc/c/gccspec.cc delete mode 100644 gcc/c/gimple-parser.c create mode 100644 gcc/c/gimple-parser.cc (limited to 'gcc/c') diff --git a/gcc/c/c-aux-info.c b/gcc/c/c-aux-info.c deleted file mode 100644 index bf01315..0000000 --- a/gcc/c/c-aux-info.c +++ /dev/null @@ -1,569 +0,0 @@ -/* Generate information regarding function declarations and definitions based - on information stored in GCC's tree structure. This code implements the - -aux-info option. - Copyright (C) 1989-2022 Free Software Foundation, Inc. - Contributed by Ron Guilmette (rfg@segfault.us.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 -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "c-tree.h" - -enum formals_style { - ansi, - k_and_r_names, - k_and_r_decls -}; - - -static const char *data_type; - -static char *affix_data_type (const char *) ATTRIBUTE_MALLOC; -static const char *gen_formal_list_for_type (tree, formals_style); -static const char *gen_formal_list_for_func_def (tree, formals_style); -static const char *gen_type (const char *, tree, formals_style); -static const char *gen_decl (tree, int, formals_style); - -/* Given a string representing an entire type or an entire declaration - which only lacks the actual "data-type" specifier (at its left end), - affix the data-type specifier to the left end of the given type - specification or object declaration. - - Because of C language weirdness, the data-type specifier (which normally - goes in at the very left end) may have to be slipped in just to the - right of any leading "const" or "volatile" qualifiers (there may be more - than one). Actually this may not be strictly necessary because it seems - that GCC (at least) accepts ` const foo;' and treats it the - same as `const foo;' but people are accustomed to seeing - `const char *foo;' and *not* `char const *foo;' so we try to create types - that look as expected. */ - -static char * -affix_data_type (const char *param) -{ - char *const type_or_decl = ASTRDUP (param); - char *p = type_or_decl; - char *qualifiers_then_data_type; - char saved; - - /* Skip as many leading const's or volatile's as there are. */ - - for (;;) - { - if (startswith (p, "volatile ")) - { - p += 9; - continue; - } - if (startswith (p, "const ")) - { - p += 6; - continue; - } - break; - } - - /* p now points to the place where we can insert the data type. We have to - add a blank after the data-type of course. */ - - if (p == type_or_decl) - return concat (data_type, " ", type_or_decl, NULL); - - saved = *p; - *p = '\0'; - qualifiers_then_data_type = concat (type_or_decl, data_type, NULL); - *p = saved; - return reconcat (qualifiers_then_data_type, - qualifiers_then_data_type, " ", p, NULL); -} - -/* Given a tree node which represents some "function type", generate the - source code version of a formal parameter list (of some given style) for - this function type. Return the whole formal parameter list (including - a pair of surrounding parens) as a string. Note that if the style - we are currently aiming for is non-ansi, then we just return a pair - of empty parens here. */ - -static const char * -gen_formal_list_for_type (tree fntype, formals_style style) -{ - const char *formal_list = ""; - tree formal_type; - - if (style != ansi) - return "()"; - - formal_type = TYPE_ARG_TYPES (fntype); - while (formal_type && TREE_VALUE (formal_type) != void_type_node) - { - const char *this_type; - - if (*formal_list) - formal_list = concat (formal_list, ", ", NULL); - - this_type = gen_type ("", TREE_VALUE (formal_type), ansi); - formal_list - = ((strlen (this_type)) - ? concat (formal_list, affix_data_type (this_type), NULL) - : concat (formal_list, data_type, NULL)); - - formal_type = TREE_CHAIN (formal_type); - } - - /* If we got to here, then we are trying to generate an ANSI style formal - parameters list. - - New style prototyped ANSI formal parameter lists should in theory always - contain some stuff between the opening and closing parens, even if it is - only "void". - - The brutal truth though is that there is lots of old K&R code out there - which contains declarations of "pointer-to-function" parameters and - these almost never have fully specified formal parameter lists associated - with them. That is, the pointer-to-function parameters are declared - with just empty parameter lists. - - In cases such as these, protoize should really insert *something* into - the vacant parameter lists, but what? It has no basis on which to insert - anything in particular. - - Here, we make life easy for protoize by trying to distinguish between - K&R empty parameter lists and new-style prototyped parameter lists - that actually contain "void". In the latter case we (obviously) want - to output the "void" verbatim, and that what we do. In the former case, - we do our best to give protoize something nice to insert. - - This "something nice" should be something that is still valid (when - re-compiled) but something that can clearly indicate to the user that - more typing information (for the parameter list) should be added (by - hand) at some convenient moment. - - The string chosen here is a comment with question marks in it. */ - - if (!*formal_list) - { - if (prototype_p (fntype)) - /* assert (TREE_VALUE (TYPE_ARG_TYPES (fntype)) == void_type_node); */ - formal_list = "void"; - else - formal_list = "/* ??? */"; - } - else - { - /* If there were at least some parameters, and if the formals-types-list - petered out to a NULL (i.e. without being terminated by a - void_type_node) then we need to tack on an ellipsis. */ - if (!formal_type) - formal_list = concat (formal_list, ", ...", NULL); - } - - return concat (" (", formal_list, ")", NULL); -} - -/* Generate a parameter list for a function definition (in some given style). - - Note that this routine has to be separate (and different) from the code that - generates the prototype parameter lists for function declarations, because - in the case of a function declaration, all we have to go on is a tree node - representing the function's own "function type". This can tell us the types - of all of the formal parameters for the function, but it cannot tell us the - actual *names* of each of the formal parameters. We need to output those - parameter names for each function definition. - - This routine gets a pointer to a tree node which represents the actual - declaration of the given function, and this DECL node has a list of formal - parameter (variable) declarations attached to it. These formal parameter - (variable) declaration nodes give us the actual names of the formal - parameters for the given function definition. - - This routine returns a string which is the source form for the entire - function formal parameter list. */ - -static const char * -gen_formal_list_for_func_def (tree fndecl, formals_style style) -{ - const char *formal_list = ""; - tree formal_decl; - - formal_decl = DECL_ARGUMENTS (fndecl); - while (formal_decl) - { - const char *this_formal; - - if (*formal_list && ((style == ansi) || (style == k_and_r_names))) - formal_list = concat (formal_list, ", ", NULL); - this_formal = gen_decl (formal_decl, 0, style); - if (style == k_and_r_decls) - formal_list = concat (formal_list, this_formal, "; ", NULL); - else - formal_list = concat (formal_list, this_formal, NULL); - formal_decl = TREE_CHAIN (formal_decl); - } - if (style == ansi) - { - if (!DECL_ARGUMENTS (fndecl)) - formal_list = concat (formal_list, "void", NULL); - if (stdarg_p (TREE_TYPE (fndecl))) - formal_list = concat (formal_list, ", ...", NULL); - } - if ((style == ansi) || (style == k_and_r_names)) - formal_list = concat (" (", formal_list, ")", NULL); - return formal_list; -} - -/* Generate a string which is the source code form for a given type (t). This - routine is ugly and complex because the C syntax for declarations is ugly - and complex. This routine is straightforward so long as *no* pointer types, - array types, or function types are involved. - - In the simple cases, this routine will return the (string) value which was - passed in as the "ret_val" argument. Usually, this starts out either as an - empty string, or as the name of the declared item (i.e. the formal function - parameter variable). - - This routine will also return with the global variable "data_type" set to - some string value which is the "basic" data-type of the given complete type. - This "data_type" string can be concatenated onto the front of the returned - string after this routine returns to its caller. - - In complicated cases involving pointer types, array types, or function - types, the C declaration syntax requires an "inside out" approach, i.e. if - you have a type which is a "pointer-to-function" type, you need to handle - the "pointer" part first, but it also has to be "innermost" (relative to - the declaration stuff for the "function" type). Thus, is this case, you - must prepend a "(*" and append a ")" to the name of the item (i.e. formal - variable). Then you must append and prepend the other info for the - "function type" part of the overall type. - - To handle the "innermost precedence" rules of complicated C declarators, we - do the following (in this routine). The input parameter called "ret_val" - is treated as a "seed". Each time gen_type is called (perhaps recursively) - some additional strings may be appended or prepended (or both) to the "seed" - string. If yet another (lower) level of the GCC tree exists for the given - type (as in the case of a pointer type, an array type, or a function type) - then the (wrapped) seed is passed to a (recursive) invocation of gen_type() - this recursive invocation may again "wrap" the (new) seed with yet more - declarator stuff, by appending, prepending (or both). By the time the - recursion bottoms out, the "seed value" at that point will have a value - which is (almost) the complete source version of the declarator (except - for the data_type info). Thus, this deepest "seed" value is simply passed - back up through all of the recursive calls until it is given (as the return - value) to the initial caller of the gen_type() routine. All that remains - to do at this point is for the initial caller to prepend the "data_type" - string onto the returned "seed". */ - -static const char * -gen_type (const char *ret_val, tree t, formals_style style) -{ - tree chain_p; - - /* If there is a typedef name for this type, use it. */ - if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL) - data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); - else - { - switch (TREE_CODE (t)) - { - case POINTER_TYPE: - if (TYPE_ATOMIC (t)) - ret_val = concat ("_Atomic ", ret_val, NULL); - if (TYPE_READONLY (t)) - ret_val = concat ("const ", ret_val, NULL); - if (TYPE_VOLATILE (t)) - ret_val = concat ("volatile ", ret_val, NULL); - - ret_val = concat ("*", ret_val, NULL); - - if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) - ret_val = concat ("(", ret_val, ")", NULL); - - ret_val = gen_type (ret_val, TREE_TYPE (t), style); - - return ret_val; - - case ARRAY_TYPE: - if (!COMPLETE_TYPE_P (t) || TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST) - ret_val = gen_type (concat (ret_val, "[]", NULL), - TREE_TYPE (t), style); - else if (int_size_in_bytes (t) == 0) - ret_val = gen_type (concat (ret_val, "[0]", NULL), - TREE_TYPE (t), style); - else - { - char buff[23]; - sprintf (buff, "[" HOST_WIDE_INT_PRINT_DEC"]", - int_size_in_bytes (t) - / int_size_in_bytes (TREE_TYPE (t))); - ret_val = gen_type (concat (ret_val, buff, NULL), - TREE_TYPE (t), style); - } - break; - - case FUNCTION_TYPE: - ret_val = gen_type (concat (ret_val, - gen_formal_list_for_type (t, style), - NULL), - TREE_TYPE (t), style); - break; - - case IDENTIFIER_NODE: - data_type = IDENTIFIER_POINTER (t); - break; - - /* The following three cases are complicated by the fact that a - user may do something really stupid, like creating a brand new - "anonymous" type specification in a formal argument list (or as - part of a function return type specification). For example: - - int f (enum { red, green, blue } color); - - In such cases, we have no name that we can put into the prototype - to represent the (anonymous) type. Thus, we have to generate the - whole darn type specification. Yuck! */ - - case RECORD_TYPE: - if (TYPE_NAME (t)) - data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); - else - { - data_type = ""; - chain_p = TYPE_FIELDS (t); - while (chain_p) - { - data_type = concat (data_type, gen_decl (chain_p, 0, ansi), - NULL); - chain_p = TREE_CHAIN (chain_p); - data_type = concat (data_type, "; ", NULL); - } - data_type = concat ("{ ", data_type, "}", NULL); - } - data_type = concat ("struct ", data_type, NULL); - break; - - case UNION_TYPE: - if (TYPE_NAME (t)) - data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); - else - { - data_type = ""; - chain_p = TYPE_FIELDS (t); - while (chain_p) - { - data_type = concat (data_type, gen_decl (chain_p, 0, ansi), - NULL); - chain_p = TREE_CHAIN (chain_p); - data_type = concat (data_type, "; ", NULL); - } - data_type = concat ("{ ", data_type, "}", NULL); - } - data_type = concat ("union ", data_type, NULL); - break; - - case ENUMERAL_TYPE: - if (TYPE_NAME (t)) - data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); - else - { - data_type = ""; - chain_p = TYPE_VALUES (t); - while (chain_p) - { - data_type = concat (data_type, - IDENTIFIER_POINTER (TREE_PURPOSE (chain_p)), NULL); - chain_p = TREE_CHAIN (chain_p); - if (chain_p) - data_type = concat (data_type, ", ", NULL); - } - data_type = concat ("{ ", data_type, " }", NULL); - } - data_type = concat ("enum ", data_type, NULL); - break; - - case TYPE_DECL: - data_type = IDENTIFIER_POINTER (DECL_NAME (t)); - break; - - case INTEGER_TYPE: - case FIXED_POINT_TYPE: - data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); - /* Normally, `unsigned' is part of the deal. Not so if it comes - with a type qualifier. */ - if (TYPE_UNSIGNED (t) && TYPE_QUALS (t)) - data_type = concat ("unsigned ", data_type, NULL); - break; - - case OPAQUE_TYPE: - case REAL_TYPE: - data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); - break; - - case VOID_TYPE: - data_type = "void"; - break; - - case ERROR_MARK: - data_type = "[ERROR]"; - break; - - default: - gcc_unreachable (); - } - } - if (TYPE_ATOMIC (t)) - ret_val = concat ("_Atomic ", ret_val, NULL); - if (TYPE_READONLY (t)) - ret_val = concat ("const ", ret_val, NULL); - if (TYPE_VOLATILE (t)) - ret_val = concat ("volatile ", ret_val, NULL); - if (TYPE_RESTRICT (t)) - ret_val = concat ("restrict ", ret_val, NULL); - return ret_val; -} - -/* Generate a string (source) representation of an entire entity declaration - (using some particular style for function types). - - The given entity may be either a variable or a function. - - If the "is_func_definition" parameter is nonzero, assume that the thing - we are generating a declaration for is a FUNCTION_DECL node which is - associated with a function definition. In this case, we can assume that - an attached list of DECL nodes for function formal arguments is present. */ - -static const char * -gen_decl (tree decl, int is_func_definition, formals_style style) -{ - const char *ret_val; - - if (DECL_NAME (decl)) - ret_val = IDENTIFIER_POINTER (DECL_NAME (decl)); - else - ret_val = ""; - - /* If we are just generating a list of names of formal parameters, we can - simply return the formal parameter name (with no typing information - attached to it) now. */ - - if (style == k_and_r_names) - return ret_val; - - /* Note that for the declaration of some entity (either a function or a - data object, like for instance a parameter) if the entity itself was - declared as either const or volatile, then const and volatile properties - are associated with just the declaration of the entity, and *not* with - the `type' of the entity. Thus, for such declared entities, we have to - generate the qualifiers here. */ - - if (TREE_THIS_VOLATILE (decl)) - ret_val = concat ("volatile ", ret_val, NULL); - if (TREE_READONLY (decl)) - ret_val = concat ("const ", ret_val, NULL); - - data_type = ""; - - /* For FUNCTION_DECL nodes, there are two possible cases here. First, if - this FUNCTION_DECL node was generated from a function "definition", then - we will have a list of DECL_NODE's, one for each of the function's formal - parameters. In this case, we can print out not only the types of each - formal, but also each formal's name. In the second case, this - FUNCTION_DECL node came from an actual function declaration (and *not* - a definition). In this case, we do nothing here because the formal - argument type-list will be output later, when the "type" of the function - is added to the string we are building. Note that the ANSI-style formal - parameter list is considered to be a (suffix) part of the "type" of the - function. */ - - if (TREE_CODE (decl) == FUNCTION_DECL && is_func_definition) - { - ret_val = concat (ret_val, gen_formal_list_for_func_def (decl, ansi), - NULL); - - /* Since we have already added in the formals list stuff, here we don't - add the whole "type" of the function we are considering (which - would include its parameter-list info), rather, we only add in - the "type" of the "type" of the function, which is really just - the return-type of the function (and does not include the parameter - list info). */ - - ret_val = gen_type (ret_val, TREE_TYPE (TREE_TYPE (decl)), style); - } - else - ret_val = gen_type (ret_val, TREE_TYPE (decl), style); - - ret_val = affix_data_type (ret_val); - - if (TREE_CODE (decl) != FUNCTION_DECL && C_DECL_REGISTER (decl)) - ret_val = concat ("register ", ret_val, NULL); - if (TREE_PUBLIC (decl)) - ret_val = concat ("extern ", ret_val, NULL); - if (TREE_CODE (decl) == FUNCTION_DECL && !TREE_PUBLIC (decl)) - ret_val = concat ("static ", ret_val, NULL); - - return ret_val; -} - -extern FILE *aux_info_file; - -/* Generate and write a new line of info to the aux-info (.X) file. This - routine is called once for each function declaration, and once for each - function definition (even the implicit ones). */ - -void -gen_aux_info_record (tree fndecl, int is_definition, int is_implicit, - int is_prototyped) -{ - if (flag_gen_aux_info) - { - static int compiled_from_record = 0; - expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (fndecl)); - - /* Each output .X file must have a header line. Write one now if we - have not yet done so. */ - - if (!compiled_from_record++) - { - /* The first line tells which directory file names are relative to. - Currently, -aux-info works only for files in the working - directory, so just use a `.' as a placeholder for now. */ - fprintf (aux_info_file, "/* compiled from: . */\n"); - } - - /* Write the actual line of auxiliary info. */ - - fprintf (aux_info_file, "/* %s:%d:%c%c */ %s;", - xloc.file, xloc.line, - (is_implicit) ? 'I' : (is_prototyped) ? 'N' : 'O', - (is_definition) ? 'F' : 'C', - gen_decl (fndecl, is_definition, ansi)); - - /* If this is an explicit function declaration, we need to also write - out an old-style (i.e. K&R) function header, just in case the user - wants to run unprotoize. */ - - if (is_definition) - { - fprintf (aux_info_file, " /*%s %s*/", - gen_formal_list_for_func_def (fndecl, k_and_r_names), - gen_formal_list_for_func_def (fndecl, k_and_r_decls)); - } - - fprintf (aux_info_file, "\n"); - } -} diff --git a/gcc/c/c-aux-info.cc b/gcc/c/c-aux-info.cc new file mode 100644 index 0000000..bf01315 --- /dev/null +++ b/gcc/c/c-aux-info.cc @@ -0,0 +1,569 @@ +/* Generate information regarding function declarations and definitions based + on information stored in GCC's tree structure. This code implements the + -aux-info option. + Copyright (C) 1989-2022 Free Software Foundation, Inc. + Contributed by Ron Guilmette (rfg@segfault.us.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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "c-tree.h" + +enum formals_style { + ansi, + k_and_r_names, + k_and_r_decls +}; + + +static const char *data_type; + +static char *affix_data_type (const char *) ATTRIBUTE_MALLOC; +static const char *gen_formal_list_for_type (tree, formals_style); +static const char *gen_formal_list_for_func_def (tree, formals_style); +static const char *gen_type (const char *, tree, formals_style); +static const char *gen_decl (tree, int, formals_style); + +/* Given a string representing an entire type or an entire declaration + which only lacks the actual "data-type" specifier (at its left end), + affix the data-type specifier to the left end of the given type + specification or object declaration. + + Because of C language weirdness, the data-type specifier (which normally + goes in at the very left end) may have to be slipped in just to the + right of any leading "const" or "volatile" qualifiers (there may be more + than one). Actually this may not be strictly necessary because it seems + that GCC (at least) accepts ` const foo;' and treats it the + same as `const foo;' but people are accustomed to seeing + `const char *foo;' and *not* `char const *foo;' so we try to create types + that look as expected. */ + +static char * +affix_data_type (const char *param) +{ + char *const type_or_decl = ASTRDUP (param); + char *p = type_or_decl; + char *qualifiers_then_data_type; + char saved; + + /* Skip as many leading const's or volatile's as there are. */ + + for (;;) + { + if (startswith (p, "volatile ")) + { + p += 9; + continue; + } + if (startswith (p, "const ")) + { + p += 6; + continue; + } + break; + } + + /* p now points to the place where we can insert the data type. We have to + add a blank after the data-type of course. */ + + if (p == type_or_decl) + return concat (data_type, " ", type_or_decl, NULL); + + saved = *p; + *p = '\0'; + qualifiers_then_data_type = concat (type_or_decl, data_type, NULL); + *p = saved; + return reconcat (qualifiers_then_data_type, + qualifiers_then_data_type, " ", p, NULL); +} + +/* Given a tree node which represents some "function type", generate the + source code version of a formal parameter list (of some given style) for + this function type. Return the whole formal parameter list (including + a pair of surrounding parens) as a string. Note that if the style + we are currently aiming for is non-ansi, then we just return a pair + of empty parens here. */ + +static const char * +gen_formal_list_for_type (tree fntype, formals_style style) +{ + const char *formal_list = ""; + tree formal_type; + + if (style != ansi) + return "()"; + + formal_type = TYPE_ARG_TYPES (fntype); + while (formal_type && TREE_VALUE (formal_type) != void_type_node) + { + const char *this_type; + + if (*formal_list) + formal_list = concat (formal_list, ", ", NULL); + + this_type = gen_type ("", TREE_VALUE (formal_type), ansi); + formal_list + = ((strlen (this_type)) + ? concat (formal_list, affix_data_type (this_type), NULL) + : concat (formal_list, data_type, NULL)); + + formal_type = TREE_CHAIN (formal_type); + } + + /* If we got to here, then we are trying to generate an ANSI style formal + parameters list. + + New style prototyped ANSI formal parameter lists should in theory always + contain some stuff between the opening and closing parens, even if it is + only "void". + + The brutal truth though is that there is lots of old K&R code out there + which contains declarations of "pointer-to-function" parameters and + these almost never have fully specified formal parameter lists associated + with them. That is, the pointer-to-function parameters are declared + with just empty parameter lists. + + In cases such as these, protoize should really insert *something* into + the vacant parameter lists, but what? It has no basis on which to insert + anything in particular. + + Here, we make life easy for protoize by trying to distinguish between + K&R empty parameter lists and new-style prototyped parameter lists + that actually contain "void". In the latter case we (obviously) want + to output the "void" verbatim, and that what we do. In the former case, + we do our best to give protoize something nice to insert. + + This "something nice" should be something that is still valid (when + re-compiled) but something that can clearly indicate to the user that + more typing information (for the parameter list) should be added (by + hand) at some convenient moment. + + The string chosen here is a comment with question marks in it. */ + + if (!*formal_list) + { + if (prototype_p (fntype)) + /* assert (TREE_VALUE (TYPE_ARG_TYPES (fntype)) == void_type_node); */ + formal_list = "void"; + else + formal_list = "/* ??? */"; + } + else + { + /* If there were at least some parameters, and if the formals-types-list + petered out to a NULL (i.e. without being terminated by a + void_type_node) then we need to tack on an ellipsis. */ + if (!formal_type) + formal_list = concat (formal_list, ", ...", NULL); + } + + return concat (" (", formal_list, ")", NULL); +} + +/* Generate a parameter list for a function definition (in some given style). + + Note that this routine has to be separate (and different) from the code that + generates the prototype parameter lists for function declarations, because + in the case of a function declaration, all we have to go on is a tree node + representing the function's own "function type". This can tell us the types + of all of the formal parameters for the function, but it cannot tell us the + actual *names* of each of the formal parameters. We need to output those + parameter names for each function definition. + + This routine gets a pointer to a tree node which represents the actual + declaration of the given function, and this DECL node has a list of formal + parameter (variable) declarations attached to it. These formal parameter + (variable) declaration nodes give us the actual names of the formal + parameters for the given function definition. + + This routine returns a string which is the source form for the entire + function formal parameter list. */ + +static const char * +gen_formal_list_for_func_def (tree fndecl, formals_style style) +{ + const char *formal_list = ""; + tree formal_decl; + + formal_decl = DECL_ARGUMENTS (fndecl); + while (formal_decl) + { + const char *this_formal; + + if (*formal_list && ((style == ansi) || (style == k_and_r_names))) + formal_list = concat (formal_list, ", ", NULL); + this_formal = gen_decl (formal_decl, 0, style); + if (style == k_and_r_decls) + formal_list = concat (formal_list, this_formal, "; ", NULL); + else + formal_list = concat (formal_list, this_formal, NULL); + formal_decl = TREE_CHAIN (formal_decl); + } + if (style == ansi) + { + if (!DECL_ARGUMENTS (fndecl)) + formal_list = concat (formal_list, "void", NULL); + if (stdarg_p (TREE_TYPE (fndecl))) + formal_list = concat (formal_list, ", ...", NULL); + } + if ((style == ansi) || (style == k_and_r_names)) + formal_list = concat (" (", formal_list, ")", NULL); + return formal_list; +} + +/* Generate a string which is the source code form for a given type (t). This + routine is ugly and complex because the C syntax for declarations is ugly + and complex. This routine is straightforward so long as *no* pointer types, + array types, or function types are involved. + + In the simple cases, this routine will return the (string) value which was + passed in as the "ret_val" argument. Usually, this starts out either as an + empty string, or as the name of the declared item (i.e. the formal function + parameter variable). + + This routine will also return with the global variable "data_type" set to + some string value which is the "basic" data-type of the given complete type. + This "data_type" string can be concatenated onto the front of the returned + string after this routine returns to its caller. + + In complicated cases involving pointer types, array types, or function + types, the C declaration syntax requires an "inside out" approach, i.e. if + you have a type which is a "pointer-to-function" type, you need to handle + the "pointer" part first, but it also has to be "innermost" (relative to + the declaration stuff for the "function" type). Thus, is this case, you + must prepend a "(*" and append a ")" to the name of the item (i.e. formal + variable). Then you must append and prepend the other info for the + "function type" part of the overall type. + + To handle the "innermost precedence" rules of complicated C declarators, we + do the following (in this routine). The input parameter called "ret_val" + is treated as a "seed". Each time gen_type is called (perhaps recursively) + some additional strings may be appended or prepended (or both) to the "seed" + string. If yet another (lower) level of the GCC tree exists for the given + type (as in the case of a pointer type, an array type, or a function type) + then the (wrapped) seed is passed to a (recursive) invocation of gen_type() + this recursive invocation may again "wrap" the (new) seed with yet more + declarator stuff, by appending, prepending (or both). By the time the + recursion bottoms out, the "seed value" at that point will have a value + which is (almost) the complete source version of the declarator (except + for the data_type info). Thus, this deepest "seed" value is simply passed + back up through all of the recursive calls until it is given (as the return + value) to the initial caller of the gen_type() routine. All that remains + to do at this point is for the initial caller to prepend the "data_type" + string onto the returned "seed". */ + +static const char * +gen_type (const char *ret_val, tree t, formals_style style) +{ + tree chain_p; + + /* If there is a typedef name for this type, use it. */ + if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL) + data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); + else + { + switch (TREE_CODE (t)) + { + case POINTER_TYPE: + if (TYPE_ATOMIC (t)) + ret_val = concat ("_Atomic ", ret_val, NULL); + if (TYPE_READONLY (t)) + ret_val = concat ("const ", ret_val, NULL); + if (TYPE_VOLATILE (t)) + ret_val = concat ("volatile ", ret_val, NULL); + + ret_val = concat ("*", ret_val, NULL); + + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) + ret_val = concat ("(", ret_val, ")", NULL); + + ret_val = gen_type (ret_val, TREE_TYPE (t), style); + + return ret_val; + + case ARRAY_TYPE: + if (!COMPLETE_TYPE_P (t) || TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST) + ret_val = gen_type (concat (ret_val, "[]", NULL), + TREE_TYPE (t), style); + else if (int_size_in_bytes (t) == 0) + ret_val = gen_type (concat (ret_val, "[0]", NULL), + TREE_TYPE (t), style); + else + { + char buff[23]; + sprintf (buff, "[" HOST_WIDE_INT_PRINT_DEC"]", + int_size_in_bytes (t) + / int_size_in_bytes (TREE_TYPE (t))); + ret_val = gen_type (concat (ret_val, buff, NULL), + TREE_TYPE (t), style); + } + break; + + case FUNCTION_TYPE: + ret_val = gen_type (concat (ret_val, + gen_formal_list_for_type (t, style), + NULL), + TREE_TYPE (t), style); + break; + + case IDENTIFIER_NODE: + data_type = IDENTIFIER_POINTER (t); + break; + + /* The following three cases are complicated by the fact that a + user may do something really stupid, like creating a brand new + "anonymous" type specification in a formal argument list (or as + part of a function return type specification). For example: + + int f (enum { red, green, blue } color); + + In such cases, we have no name that we can put into the prototype + to represent the (anonymous) type. Thus, we have to generate the + whole darn type specification. Yuck! */ + + case RECORD_TYPE: + if (TYPE_NAME (t)) + data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); + else + { + data_type = ""; + chain_p = TYPE_FIELDS (t); + while (chain_p) + { + data_type = concat (data_type, gen_decl (chain_p, 0, ansi), + NULL); + chain_p = TREE_CHAIN (chain_p); + data_type = concat (data_type, "; ", NULL); + } + data_type = concat ("{ ", data_type, "}", NULL); + } + data_type = concat ("struct ", data_type, NULL); + break; + + case UNION_TYPE: + if (TYPE_NAME (t)) + data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); + else + { + data_type = ""; + chain_p = TYPE_FIELDS (t); + while (chain_p) + { + data_type = concat (data_type, gen_decl (chain_p, 0, ansi), + NULL); + chain_p = TREE_CHAIN (chain_p); + data_type = concat (data_type, "; ", NULL); + } + data_type = concat ("{ ", data_type, "}", NULL); + } + data_type = concat ("union ", data_type, NULL); + break; + + case ENUMERAL_TYPE: + if (TYPE_NAME (t)) + data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); + else + { + data_type = ""; + chain_p = TYPE_VALUES (t); + while (chain_p) + { + data_type = concat (data_type, + IDENTIFIER_POINTER (TREE_PURPOSE (chain_p)), NULL); + chain_p = TREE_CHAIN (chain_p); + if (chain_p) + data_type = concat (data_type, ", ", NULL); + } + data_type = concat ("{ ", data_type, " }", NULL); + } + data_type = concat ("enum ", data_type, NULL); + break; + + case TYPE_DECL: + data_type = IDENTIFIER_POINTER (DECL_NAME (t)); + break; + + case INTEGER_TYPE: + case FIXED_POINT_TYPE: + data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); + /* Normally, `unsigned' is part of the deal. Not so if it comes + with a type qualifier. */ + if (TYPE_UNSIGNED (t) && TYPE_QUALS (t)) + data_type = concat ("unsigned ", data_type, NULL); + break; + + case OPAQUE_TYPE: + case REAL_TYPE: + data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); + break; + + case VOID_TYPE: + data_type = "void"; + break; + + case ERROR_MARK: + data_type = "[ERROR]"; + break; + + default: + gcc_unreachable (); + } + } + if (TYPE_ATOMIC (t)) + ret_val = concat ("_Atomic ", ret_val, NULL); + if (TYPE_READONLY (t)) + ret_val = concat ("const ", ret_val, NULL); + if (TYPE_VOLATILE (t)) + ret_val = concat ("volatile ", ret_val, NULL); + if (TYPE_RESTRICT (t)) + ret_val = concat ("restrict ", ret_val, NULL); + return ret_val; +} + +/* Generate a string (source) representation of an entire entity declaration + (using some particular style for function types). + + The given entity may be either a variable or a function. + + If the "is_func_definition" parameter is nonzero, assume that the thing + we are generating a declaration for is a FUNCTION_DECL node which is + associated with a function definition. In this case, we can assume that + an attached list of DECL nodes for function formal arguments is present. */ + +static const char * +gen_decl (tree decl, int is_func_definition, formals_style style) +{ + const char *ret_val; + + if (DECL_NAME (decl)) + ret_val = IDENTIFIER_POINTER (DECL_NAME (decl)); + else + ret_val = ""; + + /* If we are just generating a list of names of formal parameters, we can + simply return the formal parameter name (with no typing information + attached to it) now. */ + + if (style == k_and_r_names) + return ret_val; + + /* Note that for the declaration of some entity (either a function or a + data object, like for instance a parameter) if the entity itself was + declared as either const or volatile, then const and volatile properties + are associated with just the declaration of the entity, and *not* with + the `type' of the entity. Thus, for such declared entities, we have to + generate the qualifiers here. */ + + if (TREE_THIS_VOLATILE (decl)) + ret_val = concat ("volatile ", ret_val, NULL); + if (TREE_READONLY (decl)) + ret_val = concat ("const ", ret_val, NULL); + + data_type = ""; + + /* For FUNCTION_DECL nodes, there are two possible cases here. First, if + this FUNCTION_DECL node was generated from a function "definition", then + we will have a list of DECL_NODE's, one for each of the function's formal + parameters. In this case, we can print out not only the types of each + formal, but also each formal's name. In the second case, this + FUNCTION_DECL node came from an actual function declaration (and *not* + a definition). In this case, we do nothing here because the formal + argument type-list will be output later, when the "type" of the function + is added to the string we are building. Note that the ANSI-style formal + parameter list is considered to be a (suffix) part of the "type" of the + function. */ + + if (TREE_CODE (decl) == FUNCTION_DECL && is_func_definition) + { + ret_val = concat (ret_val, gen_formal_list_for_func_def (decl, ansi), + NULL); + + /* Since we have already added in the formals list stuff, here we don't + add the whole "type" of the function we are considering (which + would include its parameter-list info), rather, we only add in + the "type" of the "type" of the function, which is really just + the return-type of the function (and does not include the parameter + list info). */ + + ret_val = gen_type (ret_val, TREE_TYPE (TREE_TYPE (decl)), style); + } + else + ret_val = gen_type (ret_val, TREE_TYPE (decl), style); + + ret_val = affix_data_type (ret_val); + + if (TREE_CODE (decl) != FUNCTION_DECL && C_DECL_REGISTER (decl)) + ret_val = concat ("register ", ret_val, NULL); + if (TREE_PUBLIC (decl)) + ret_val = concat ("extern ", ret_val, NULL); + if (TREE_CODE (decl) == FUNCTION_DECL && !TREE_PUBLIC (decl)) + ret_val = concat ("static ", ret_val, NULL); + + return ret_val; +} + +extern FILE *aux_info_file; + +/* Generate and write a new line of info to the aux-info (.X) file. This + routine is called once for each function declaration, and once for each + function definition (even the implicit ones). */ + +void +gen_aux_info_record (tree fndecl, int is_definition, int is_implicit, + int is_prototyped) +{ + if (flag_gen_aux_info) + { + static int compiled_from_record = 0; + expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (fndecl)); + + /* Each output .X file must have a header line. Write one now if we + have not yet done so. */ + + if (!compiled_from_record++) + { + /* The first line tells which directory file names are relative to. + Currently, -aux-info works only for files in the working + directory, so just use a `.' as a placeholder for now. */ + fprintf (aux_info_file, "/* compiled from: . */\n"); + } + + /* Write the actual line of auxiliary info. */ + + fprintf (aux_info_file, "/* %s:%d:%c%c */ %s;", + xloc.file, xloc.line, + (is_implicit) ? 'I' : (is_prototyped) ? 'N' : 'O', + (is_definition) ? 'F' : 'C', + gen_decl (fndecl, is_definition, ansi)); + + /* If this is an explicit function declaration, we need to also write + out an old-style (i.e. K&R) function header, just in case the user + wants to run unprotoize. */ + + if (is_definition) + { + fprintf (aux_info_file, " /*%s %s*/", + gen_formal_list_for_func_def (fndecl, k_and_r_names), + gen_formal_list_for_func_def (fndecl, k_and_r_decls)); + } + + fprintf (aux_info_file, "\n"); + } +} diff --git a/gcc/c/c-convert.c b/gcc/c/c-convert.c deleted file mode 100644 index 5e92759..0000000 --- a/gcc/c/c-convert.c +++ /dev/null @@ -1,207 +0,0 @@ -/* Language-level data type conversion for GNU C. - Copyright (C) 1987-2022 Free Software Foundation, Inc. - -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 -. */ - - -/* This file contains the functions for converting C expressions - to different data types. The only entry point is `convert'. - Every language front end must have a `convert' function - but what kind of conversions it does will depend on the language. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "target.h" -#include "c-tree.h" -#include "convert.h" -#include "langhooks.h" -#include "ubsan.h" -#include "stringpool.h" -#include "attribs.h" -#include "asan.h" - -/* Change of width--truncation and extension of integers or reals-- - is represented with NOP_EXPR. Proper functioning of many things - assumes that no other conversions can be NOP_EXPRs. - - Conversion between integer and pointer is represented with CONVERT_EXPR. - Converting integer to real uses FLOAT_EXPR - and real to integer uses FIX_TRUNC_EXPR. - - Here is a list of all the functions that assume that widening and - narrowing is always done with a NOP_EXPR: - In convert.c, convert_to_integer. - In c-typeck.c, build_binary_op (boolean ops), and - c_common_truthvalue_conversion. - In expr.c: expand_expr, for operands of a MULT_EXPR. - In fold-const.c: fold. - In tree.c: get_narrower and get_unwidened. */ - -/* Subroutines of `convert'. */ - - - -/* Create an expression whose value is that of EXPR, - converted to type TYPE. The TREE_TYPE of the value - is always TYPE. This function implements all reasonable - conversions; callers should filter out those that are - not permitted by the language being compiled. - INIT_CONST is true if the conversion is for arithmetic types for a static - initializer and folding must apply accordingly (discarding floating-point - exceptions and assuming the default rounding mode is in effect). */ - -static tree -c_convert (tree type, tree expr, bool init_const) -{ - tree e = expr; - enum tree_code code = TREE_CODE (type); - const char *invalid_conv_diag; - tree ret; - location_t loc = EXPR_LOCATION (expr); - - if (type == error_mark_node - || error_operand_p (expr)) - return error_mark_node; - - if ((invalid_conv_diag - = targetm.invalid_conversion (TREE_TYPE (expr), type))) - { - error (invalid_conv_diag); - return error_mark_node; - } - - if (type == TREE_TYPE (expr)) - return expr; - ret = targetm.convert_to_type (type, expr); - if (ret) - return ret; - - STRIP_TYPE_NOPS (e); - - if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)) - && (TREE_CODE (TREE_TYPE (expr)) != COMPLEX_TYPE - || TREE_CODE (e) == COMPLEX_EXPR)) - return fold_convert_loc (loc, type, expr); - if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) - return error_mark_node; - if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) - { - error ("void value not ignored as it ought to be"); - return error_mark_node; - } - - switch (code) - { - case VOID_TYPE: - return fold_convert_loc (loc, type, e); - - case INTEGER_TYPE: - case ENUMERAL_TYPE: - if (sanitize_flags_p (SANITIZE_FLOAT_CAST) - && current_function_decl != NULL_TREE - && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE - && COMPLETE_TYPE_P (type)) - { - expr = save_expr (expr); - expr = c_fully_fold (expr, init_const, NULL); - tree check = ubsan_instrument_float_cast (loc, type, expr); - expr = fold_build1 (FIX_TRUNC_EXPR, type, expr); - if (check == NULL_TREE) - return expr; - return fold_build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr); - } - ret = convert_to_integer (type, e); - goto maybe_fold; - - case BOOLEAN_TYPE: - return fold_convert_loc - (loc, type, c_objc_common_truthvalue_conversion (input_location, expr)); - - case POINTER_TYPE: - case REFERENCE_TYPE: - ret = convert_to_pointer (type, e); - goto maybe_fold; - - case REAL_TYPE: - ret = convert_to_real (type, e); - goto maybe_fold; - - case FIXED_POINT_TYPE: - ret = convert_to_fixed (type, e); - goto maybe_fold; - - case COMPLEX_TYPE: - ret = convert_to_complex (type, e); - goto maybe_fold; - - case VECTOR_TYPE: - if (gnu_vector_type_p (type) - || gnu_vector_type_p (TREE_TYPE (e)) - /* Allow conversions between compatible non-GNU vector types - when -flax-vector-conversions is passed. The whole purpose - of the option is to bend the normal type rules and accept - nonconforming code. */ - || (flag_lax_vector_conversions - && VECTOR_TYPE_P (TREE_TYPE (e)) - && vector_types_convertible_p (type, TREE_TYPE (e), false))) - { - ret = convert_to_vector (type, e); - goto maybe_fold; - } - break; - - case RECORD_TYPE: - case UNION_TYPE: - if (lang_hooks.types_compatible_p (type, TREE_TYPE (expr))) - return e; - break; - - default: - break; - - maybe_fold: - if (TREE_CODE (ret) != C_MAYBE_CONST_EXPR) - ret = init_const ? fold_init (ret) : fold (ret); - return ret; - } - - error ("conversion to non-scalar type requested"); - return error_mark_node; -} - -/* Create an expression whose value is that of EXPR, converted to type TYPE. - The TREE_TYPE of the value is always TYPE. This function implements all - reasonable conversions; callers should filter out those that are not - permitted by the language being compiled. */ - -tree -convert (tree type, tree expr) -{ - return c_convert (type, expr, false); -} - -/* Create an expression whose value is that of EXPR, converted to type TYPE, in - a static initializer. The TREE_TYPE of the value is always TYPE. This - function implements all reasonable conversions; callers should filter out - those that are not permitted by the language being compiled. */ - -tree -convert_init (tree type, tree expr) -{ - return c_convert (type, expr, true); -} diff --git a/gcc/c/c-convert.cc b/gcc/c/c-convert.cc new file mode 100644 index 0000000..5e92759 --- /dev/null +++ b/gcc/c/c-convert.cc @@ -0,0 +1,207 @@ +/* Language-level data type conversion for GNU C. + Copyright (C) 1987-2022 Free Software Foundation, Inc. + +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 +. */ + + +/* This file contains the functions for converting C expressions + to different data types. The only entry point is `convert'. + Every language front end must have a `convert' function + but what kind of conversions it does will depend on the language. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "c-tree.h" +#include "convert.h" +#include "langhooks.h" +#include "ubsan.h" +#include "stringpool.h" +#include "attribs.h" +#include "asan.h" + +/* Change of width--truncation and extension of integers or reals-- + is represented with NOP_EXPR. Proper functioning of many things + assumes that no other conversions can be NOP_EXPRs. + + Conversion between integer and pointer is represented with CONVERT_EXPR. + Converting integer to real uses FLOAT_EXPR + and real to integer uses FIX_TRUNC_EXPR. + + Here is a list of all the functions that assume that widening and + narrowing is always done with a NOP_EXPR: + In convert.c, convert_to_integer. + In c-typeck.c, build_binary_op (boolean ops), and + c_common_truthvalue_conversion. + In expr.c: expand_expr, for operands of a MULT_EXPR. + In fold-const.c: fold. + In tree.c: get_narrower and get_unwidened. */ + +/* Subroutines of `convert'. */ + + + +/* Create an expression whose value is that of EXPR, + converted to type TYPE. The TREE_TYPE of the value + is always TYPE. This function implements all reasonable + conversions; callers should filter out those that are + not permitted by the language being compiled. + INIT_CONST is true if the conversion is for arithmetic types for a static + initializer and folding must apply accordingly (discarding floating-point + exceptions and assuming the default rounding mode is in effect). */ + +static tree +c_convert (tree type, tree expr, bool init_const) +{ + tree e = expr; + enum tree_code code = TREE_CODE (type); + const char *invalid_conv_diag; + tree ret; + location_t loc = EXPR_LOCATION (expr); + + if (type == error_mark_node + || error_operand_p (expr)) + return error_mark_node; + + if ((invalid_conv_diag + = targetm.invalid_conversion (TREE_TYPE (expr), type))) + { + error (invalid_conv_diag); + return error_mark_node; + } + + if (type == TREE_TYPE (expr)) + return expr; + ret = targetm.convert_to_type (type, expr); + if (ret) + return ret; + + STRIP_TYPE_NOPS (e); + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)) + && (TREE_CODE (TREE_TYPE (expr)) != COMPLEX_TYPE + || TREE_CODE (e) == COMPLEX_EXPR)) + return fold_convert_loc (loc, type, expr); + if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) + return error_mark_node; + if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + + switch (code) + { + case VOID_TYPE: + return fold_convert_loc (loc, type, e); + + case INTEGER_TYPE: + case ENUMERAL_TYPE: + if (sanitize_flags_p (SANITIZE_FLOAT_CAST) + && current_function_decl != NULL_TREE + && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE + && COMPLETE_TYPE_P (type)) + { + expr = save_expr (expr); + expr = c_fully_fold (expr, init_const, NULL); + tree check = ubsan_instrument_float_cast (loc, type, expr); + expr = fold_build1 (FIX_TRUNC_EXPR, type, expr); + if (check == NULL_TREE) + return expr; + return fold_build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr); + } + ret = convert_to_integer (type, e); + goto maybe_fold; + + case BOOLEAN_TYPE: + return fold_convert_loc + (loc, type, c_objc_common_truthvalue_conversion (input_location, expr)); + + case POINTER_TYPE: + case REFERENCE_TYPE: + ret = convert_to_pointer (type, e); + goto maybe_fold; + + case REAL_TYPE: + ret = convert_to_real (type, e); + goto maybe_fold; + + case FIXED_POINT_TYPE: + ret = convert_to_fixed (type, e); + goto maybe_fold; + + case COMPLEX_TYPE: + ret = convert_to_complex (type, e); + goto maybe_fold; + + case VECTOR_TYPE: + if (gnu_vector_type_p (type) + || gnu_vector_type_p (TREE_TYPE (e)) + /* Allow conversions between compatible non-GNU vector types + when -flax-vector-conversions is passed. The whole purpose + of the option is to bend the normal type rules and accept + nonconforming code. */ + || (flag_lax_vector_conversions + && VECTOR_TYPE_P (TREE_TYPE (e)) + && vector_types_convertible_p (type, TREE_TYPE (e), false))) + { + ret = convert_to_vector (type, e); + goto maybe_fold; + } + break; + + case RECORD_TYPE: + case UNION_TYPE: + if (lang_hooks.types_compatible_p (type, TREE_TYPE (expr))) + return e; + break; + + default: + break; + + maybe_fold: + if (TREE_CODE (ret) != C_MAYBE_CONST_EXPR) + ret = init_const ? fold_init (ret) : fold (ret); + return ret; + } + + error ("conversion to non-scalar type requested"); + return error_mark_node; +} + +/* Create an expression whose value is that of EXPR, converted to type TYPE. + The TREE_TYPE of the value is always TYPE. This function implements all + reasonable conversions; callers should filter out those that are not + permitted by the language being compiled. */ + +tree +convert (tree type, tree expr) +{ + return c_convert (type, expr, false); +} + +/* Create an expression whose value is that of EXPR, converted to type TYPE, in + a static initializer. The TREE_TYPE of the value is always TYPE. This + function implements all reasonable conversions; callers should filter out + those that are not permitted by the language being compiled. */ + +tree +convert_init (tree type, tree expr) +{ + return c_convert (type, expr, true); +} diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c deleted file mode 100644 index 29a79eb..0000000 --- a/gcc/c/c-decl.c +++ /dev/null @@ -1,12469 +0,0 @@ -/* Process declarations and variables for C compiler. - Copyright (C) 1988-2022 Free Software Foundation, Inc. - -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 -. */ - -/* Process declarations and symbol lookup for C front end. - Also constructs types; the standard scalar types at initialization, - and structure, union, array and enum types when they are declared. */ - -/* ??? not all decl nodes are given the most useful possible - line numbers. For example, the CONST_DECLs for enum values. */ - -#include "config.h" -#define INCLUDE_STRING -#define INCLUDE_MEMORY -#include "system.h" -#include "coretypes.h" -#include "target.h" -#include "function.h" -#include "c-tree.h" -#include "timevar.h" -#include "stringpool.h" -#include "cgraph.h" -#include "intl.h" -#include "print-tree.h" -#include "stor-layout.h" -#include "varasm.h" -#include "attribs.h" -#include "toplev.h" -#include "debug.h" -#include "c-family/c-objc.h" -#include "c-family/c-pragma.h" -#include "c-family/c-ubsan.h" -#include "c-lang.h" -#include "langhooks.h" -#include "tree-iterator.h" -#include "dumpfile.h" -#include "plugin.h" -#include "c-family/c-ada-spec.h" -#include "builtins.h" -#include "spellcheck-tree.h" -#include "gcc-rich-location.h" -#include "asan.h" -#include "c-family/name-hint.h" -#include "c-family/known-headers.h" -#include "c-family/c-spellcheck.h" -#include "context.h" /* For 'g'. */ -#include "omp-general.h" -#include "omp-offload.h" /* For offload_vars. */ - -#include "tree-pretty-print.h" - -/* In grokdeclarator, distinguish syntactic contexts of declarators. */ -enum decl_context -{ NORMAL, /* Ordinary declaration */ - FUNCDEF, /* Function definition */ - PARM, /* Declaration of parm before function body */ - FIELD, /* Declaration inside struct or union */ - TYPENAME}; /* Typename (inside cast or sizeof) */ - -/* States indicating how grokdeclarator() should handle declspecs marked - with __attribute__((deprecated)) or __attribute__((unavailable)). - An object declared as __attribute__((unavailable)) should suppress - any reports of being declared with unavailable or deprecated items. - An object declared as __attribute__((deprecated)) should suppress - warnings of uses of other deprecated items. */ - -enum deprecated_states { - DEPRECATED_NORMAL, - DEPRECATED_SUPPRESS, - UNAVAILABLE_DEPRECATED_SUPPRESS -}; - - -/* Nonzero if we have seen an invalid cross reference - to a struct, union, or enum, but not yet printed the message. */ -tree pending_invalid_xref; - -/* File and line to appear in the eventual error message. */ -location_t pending_invalid_xref_location; - -/* The file and line that the prototype came from if this is an - old-style definition; used for diagnostics in - store_parm_decls_oldstyle. */ - -static location_t current_function_prototype_locus; - -/* Whether this prototype was built-in. */ - -static bool current_function_prototype_built_in; - -/* The argument type information of this prototype. */ - -static tree current_function_prototype_arg_types; - -/* The argument information structure for the function currently being - defined. */ - -static struct c_arg_info *current_function_arg_info; - -/* The obstack on which parser and related data structures, which are - not live beyond their top-level declaration or definition, are - allocated. */ -struct obstack parser_obstack; - -/* The current statement tree. */ - -static GTY(()) struct stmt_tree_s c_stmt_tree; - -/* Zero if we are not in an iteration or switch statement, otherwise - a bitmask. See bitmask definitions in c-tree.h. */ -unsigned char in_statement; - -/* A list of decls to be made automatically visible in each file scope. */ -static GTY(()) tree visible_builtins; - -/* Set to 0 at beginning of a function definition, set to 1 if - a return statement that specifies a return value is seen. */ - -int current_function_returns_value; - -/* Set to 0 at beginning of a function definition, set to 1 if - a return statement with no argument is seen. */ - -int current_function_returns_null; - -/* Set to 0 at beginning of a function definition, set to 1 if - a call to a noreturn function is seen. */ - -int current_function_returns_abnormally; - -/* Set to nonzero by `grokdeclarator' for a function - whose return type is defaulted, if warnings for this are desired. */ - -static int warn_about_return_type; - -/* Nonzero when the current toplevel function contains a declaration - of a nested function which is never defined. */ - -static bool undef_nested_function; - -/* If non-zero, implicit "omp declare target" attribute is added into the - attribute lists. */ -int current_omp_declare_target_attribute; - -/* Each c_binding structure describes one binding of an identifier to - a decl. All the decls in a scope - irrespective of namespace - are - chained together by the ->prev field, which (as the name implies) - runs in reverse order. All the decls in a given namespace bound to - a given identifier are chained by the ->shadowed field, which runs - from inner to outer scopes. - - The ->decl field usually points to a DECL node, but there are two - exceptions. In the namespace of type tags, the bound entity is a - RECORD_TYPE, UNION_TYPE, or ENUMERAL_TYPE node. If an undeclared - identifier is encountered, it is bound to error_mark_node to - suppress further errors about that identifier in the current - function. - - The ->u.type field stores the type of the declaration in this scope; - if NULL, the type is the type of the ->decl field. This is only of - relevance for objects with external or internal linkage which may - be redeclared in inner scopes, forming composite types that only - persist for the duration of those scopes. In the external scope, - this stores the composite of all the types declared for this - object, visible or not. The ->inner_comp field (used only at file - scope) stores whether an incomplete array type at file scope was - completed at an inner scope to an array size other than 1. - - The ->u.label field is used for labels. It points to a structure - which stores additional information used for warnings. - - The depth field is copied from the scope structure that holds this - decl. It is used to preserve the proper ordering of the ->shadowed - field (see bind()) and also for a handful of special-case checks. - Finally, the invisible bit is true for a decl which should be - ignored for purposes of normal name lookup, and the nested bit is - true for a decl that's been bound a second time in an inner scope; - in all such cases, the binding in the outer scope will have its - invisible bit true. */ - -struct GTY((chain_next ("%h.prev"))) c_binding { - union GTY(()) { /* first so GTY desc can use decl */ - tree GTY((tag ("0"))) type; /* the type in this scope */ - struct c_label_vars * GTY((tag ("1"))) label; /* for warnings */ - } GTY((desc ("TREE_CODE (%0.decl) == LABEL_DECL"))) u; - tree decl; /* the decl bound */ - tree id; /* the identifier it's bound to */ - struct c_binding *prev; /* the previous decl in this scope */ - struct c_binding *shadowed; /* the innermost decl shadowed by this one */ - unsigned int depth : 28; /* depth of this scope */ - BOOL_BITFIELD invisible : 1; /* normal lookup should ignore this binding */ - BOOL_BITFIELD nested : 1; /* do not set DECL_CONTEXT when popping */ - BOOL_BITFIELD inner_comp : 1; /* incomplete array completed in inner scope */ - BOOL_BITFIELD in_struct : 1; /* currently defined as struct field */ - location_t locus; /* location for nested bindings */ -}; -#define B_IN_SCOPE(b1, b2) ((b1)->depth == (b2)->depth) -#define B_IN_CURRENT_SCOPE(b) ((b)->depth == current_scope->depth) -#define B_IN_FILE_SCOPE(b) ((b)->depth == 1 /*file_scope->depth*/) -#define B_IN_EXTERNAL_SCOPE(b) ((b)->depth == 0 /*external_scope->depth*/) - -/* Each C symbol points to three linked lists of c_binding structures. - These describe the values of the identifier in the three different - namespaces defined by the language. */ - -struct GTY(()) lang_identifier { - struct c_common_identifier common_id; - struct c_binding *symbol_binding; /* vars, funcs, constants, typedefs */ - struct c_binding *tag_binding; /* struct/union/enum tags */ - struct c_binding *label_binding; /* labels */ -}; - -/* Validate c-lang.c's assumptions. */ -extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate -[(sizeof(struct lang_identifier) == C_SIZEOF_STRUCT_LANG_IDENTIFIER) ? 1 : -1]; - -/* The binding oracle; see c-tree.h. */ -void (*c_binding_oracle) (enum c_oracle_request, tree identifier); - -/* This flag is set on an identifier if we have previously asked the - binding oracle for this identifier's symbol binding. */ -#define I_SYMBOL_CHECKED(node) \ - (TREE_LANG_FLAG_4 (IDENTIFIER_NODE_CHECK (node))) - -static inline struct c_binding* * -i_symbol_binding (tree node) -{ - struct lang_identifier *lid - = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node); - - if (lid->symbol_binding == NULL - && c_binding_oracle != NULL - && !I_SYMBOL_CHECKED (node)) - { - /* Set the "checked" flag first, to avoid infinite recursion - when the binding oracle calls back into gcc. */ - I_SYMBOL_CHECKED (node) = 1; - c_binding_oracle (C_ORACLE_SYMBOL, node); - } - - return &lid->symbol_binding; -} - -#define I_SYMBOL_BINDING(node) (*i_symbol_binding (node)) - -#define I_SYMBOL_DECL(node) \ - (I_SYMBOL_BINDING(node) ? I_SYMBOL_BINDING(node)->decl : 0) - -/* This flag is set on an identifier if we have previously asked the - binding oracle for this identifier's tag binding. */ -#define I_TAG_CHECKED(node) \ - (TREE_LANG_FLAG_5 (IDENTIFIER_NODE_CHECK (node))) - -static inline struct c_binding ** -i_tag_binding (tree node) -{ - struct lang_identifier *lid - = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node); - - if (lid->tag_binding == NULL - && c_binding_oracle != NULL - && !I_TAG_CHECKED (node)) - { - /* Set the "checked" flag first, to avoid infinite recursion - when the binding oracle calls back into gcc. */ - I_TAG_CHECKED (node) = 1; - c_binding_oracle (C_ORACLE_TAG, node); - } - - return &lid->tag_binding; -} - -#define I_TAG_BINDING(node) (*i_tag_binding (node)) - -#define I_TAG_DECL(node) \ - (I_TAG_BINDING(node) ? I_TAG_BINDING(node)->decl : 0) - -/* This flag is set on an identifier if we have previously asked the - binding oracle for this identifier's label binding. */ -#define I_LABEL_CHECKED(node) \ - (TREE_LANG_FLAG_6 (IDENTIFIER_NODE_CHECK (node))) - -static inline struct c_binding ** -i_label_binding (tree node) -{ - struct lang_identifier *lid - = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node); - - if (lid->label_binding == NULL - && c_binding_oracle != NULL - && !I_LABEL_CHECKED (node)) - { - /* Set the "checked" flag first, to avoid infinite recursion - when the binding oracle calls back into gcc. */ - I_LABEL_CHECKED (node) = 1; - c_binding_oracle (C_ORACLE_LABEL, node); - } - - return &lid->label_binding; -} - -#define I_LABEL_BINDING(node) (*i_label_binding (node)) - -#define I_LABEL_DECL(node) \ - (I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0) - -/* The resulting tree type. */ - -union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), - chain_next ("(union lang_tree_node *) c_tree_chain_next (&%h.generic)"))) lang_tree_node - { - union tree_node GTY ((tag ("0"), - desc ("tree_node_structure (&%h)"))) - generic; - struct lang_identifier GTY ((tag ("1"))) identifier; -}; - -/* Track bindings and other things that matter for goto warnings. For - efficiency, we do not gather all the decls at the point of - definition. Instead, we point into the bindings structure. As - scopes are popped, we update these structures and gather the decls - that matter at that time. */ - -struct GTY(()) c_spot_bindings { - /* The currently open scope which holds bindings defined when the - label was defined or the goto statement was found. */ - struct c_scope *scope; - /* The bindings in the scope field which were defined at the point - of the label or goto. This lets us look at older or newer - bindings in the scope, as appropriate. */ - struct c_binding *bindings_in_scope; - /* The number of statement expressions that have started since this - label or goto statement was defined. This is zero if we are at - the same statement expression level. It is positive if we are in - a statement expression started since this spot. It is negative - if this spot was in a statement expression and we have left - it. */ - int stmt_exprs; - /* Whether we started in a statement expression but are no longer in - it. This is set to true if stmt_exprs ever goes negative. */ - bool left_stmt_expr; -}; - -/* This structure is used to keep track of bindings seen when a goto - statement is defined. This is only used if we see the goto - statement before we see the label. */ - -struct GTY(()) c_goto_bindings { - /* The location of the goto statement. */ - location_t loc; - /* The bindings of the goto statement. */ - struct c_spot_bindings goto_bindings; -}; - -typedef struct c_goto_bindings *c_goto_bindings_p; - -/* The additional information we keep track of for a label binding. - These fields are updated as scopes are popped. */ - -struct GTY(()) c_label_vars { - /* The shadowed c_label_vars, when one label shadows another (which - can only happen using a __label__ declaration). */ - struct c_label_vars *shadowed; - /* The bindings when the label was defined. */ - struct c_spot_bindings label_bindings; - /* A list of decls that we care about: decls about which we should - warn if a goto branches to this label from later in the function. - Decls are added to this list as scopes are popped. We only add - the decls that matter. */ - vec *decls_in_scope; - /* A list of goto statements to this label. This is only used for - goto statements seen before the label was defined, so that we can - issue appropriate warnings for them. */ - vec *gotos; -}; - -/* Each c_scope structure describes the complete contents of one - scope. Four scopes are distinguished specially: the innermost or - current scope, the innermost function scope, the file scope (always - the second to outermost) and the outermost or external scope. - - Most declarations are recorded in the current scope. - - All normal label declarations are recorded in the innermost - function scope, as are bindings of undeclared identifiers to - error_mark_node. (GCC permits nested functions as an extension, - hence the 'innermost' qualifier.) Explicitly declared labels - (using the __label__ extension) appear in the current scope. - - Being in the file scope (current_scope == file_scope) causes - special behavior in several places below. Also, under some - conditions the Objective-C front end records declarations in the - file scope even though that isn't the current scope. - - All declarations with external linkage are recorded in the external - scope, even if they aren't visible there; this models the fact that - such declarations are visible to the entire program, and (with a - bit of cleverness, see pushdecl) allows diagnosis of some violations - of C99 6.2.2p7 and 6.2.7p2: - - If, within the same translation unit, the same identifier appears - with both internal and external linkage, the behavior is - undefined. - - All declarations that refer to the same object or function shall - have compatible type; otherwise, the behavior is undefined. - - Initially only the built-in declarations, which describe compiler - intrinsic functions plus a subset of the standard library, are in - this scope. - - The order of the blocks list matters, and it is frequently appended - to. To avoid having to walk all the way to the end of the list on - each insertion, or reverse the list later, we maintain a pointer to - the last list entry. (FIXME: It should be feasible to use a reversed - list here.) - - The bindings list is strictly in reverse order of declarations; - pop_scope relies on this. */ - - -struct GTY((chain_next ("%h.outer"))) c_scope { - /* The scope containing this one. */ - struct c_scope *outer; - - /* The next outermost function scope. */ - struct c_scope *outer_function; - - /* All bindings in this scope. */ - struct c_binding *bindings; - - /* For each scope (except the global one), a chain of BLOCK nodes - for all the scopes that were entered and exited one level down. */ - tree blocks; - tree blocks_last; - - /* The depth of this scope. Used to keep the ->shadowed chain of - bindings sorted innermost to outermost. */ - unsigned int depth : 28; - - /* True if we are currently filling this scope with parameter - declarations. */ - BOOL_BITFIELD parm_flag : 1; - - /* True if we saw [*] in this scope. Used to give an error messages - if these appears in a function definition. */ - BOOL_BITFIELD had_vla_unspec : 1; - - /* True if we already complained about forward parameter decls - in this scope. This prevents double warnings on - foo (int a; int b; ...) */ - BOOL_BITFIELD warned_forward_parm_decls : 1; - - /* True if this is the outermost block scope of a function body. - This scope contains the parameters, the local variables declared - in the outermost block, and all the labels (except those in - nested functions, or declared at block scope with __label__). */ - BOOL_BITFIELD function_body : 1; - - /* True means make a BLOCK for this scope no matter what. */ - BOOL_BITFIELD keep : 1; - - /* True means that an unsuffixed float constant is _Decimal64. */ - BOOL_BITFIELD float_const_decimal64 : 1; - - /* True if this scope has any label bindings. This is used to speed - up searching for labels when popping scopes, particularly since - labels are normally only found at function scope. */ - BOOL_BITFIELD has_label_bindings : 1; - - /* True if we should issue a warning if a goto statement crosses any - of the bindings. We still need to check the list of bindings to - find the specific ones we need to warn about. This is true if - decl_jump_unsafe would return true for any of the bindings. This - is used to avoid looping over all the bindings unnecessarily. */ - BOOL_BITFIELD has_jump_unsafe_decl : 1; -}; - -/* The scope currently in effect. */ - -static GTY(()) struct c_scope *current_scope; - -/* The innermost function scope. Ordinary (not explicitly declared) - labels, bindings to error_mark_node, and the lazily-created - bindings of __func__ and its friends get this scope. */ - -static GTY(()) struct c_scope *current_function_scope; - -/* The C file scope. This is reset for each input translation unit. */ - -static GTY(()) struct c_scope *file_scope; - -/* The outermost scope. This is used for all declarations with - external linkage, and only these, hence the name. */ - -static GTY(()) struct c_scope *external_scope; - -/* A chain of c_scope structures awaiting reuse. */ - -static GTY((deletable)) struct c_scope *scope_freelist; - -/* A chain of c_binding structures awaiting reuse. */ - -static GTY((deletable)) struct c_binding *binding_freelist; - -/* Append VAR to LIST in scope SCOPE. */ -#define SCOPE_LIST_APPEND(scope, list, decl) do { \ - struct c_scope *s_ = (scope); \ - tree d_ = (decl); \ - if (s_->list##_last) \ - BLOCK_CHAIN (s_->list##_last) = d_; \ - else \ - s_->list = d_; \ - s_->list##_last = d_; \ -} while (0) - -/* Concatenate FROM in scope FSCOPE onto TO in scope TSCOPE. */ -#define SCOPE_LIST_CONCAT(tscope, to, fscope, from) do { \ - struct c_scope *t_ = (tscope); \ - struct c_scope *f_ = (fscope); \ - if (t_->to##_last) \ - BLOCK_CHAIN (t_->to##_last) = f_->from; \ - else \ - t_->to = f_->from; \ - t_->to##_last = f_->from##_last; \ -} while (0) - -/* A c_inline_static structure stores details of a static identifier - referenced in a definition of a function that may be an inline - definition if no subsequent declaration of that function uses - "extern" or does not use "inline". */ - -struct GTY((chain_next ("%h.next"))) c_inline_static { - /* The location for a diagnostic. */ - location_t location; - - /* The function that may be an inline definition. */ - tree function; - - /* The object or function referenced. */ - tree static_decl; - - /* What sort of reference this is. */ - enum c_inline_static_type type; - - /* The next such structure or NULL. */ - struct c_inline_static *next; -}; - -/* List of static identifiers used or referenced in functions that may - be inline definitions. */ -static GTY(()) struct c_inline_static *c_inline_statics; - -/* True means unconditionally make a BLOCK for the next scope pushed. */ - -static bool keep_next_level_flag; - -/* True means the next call to push_scope will be the outermost scope - of a function body, so do not push a new scope, merely cease - expecting parameter decls. */ - -static bool next_is_function_body; - -/* A vector of pointers to c_binding structures. */ - -typedef struct c_binding *c_binding_ptr; - -/* Information that we keep for a struct or union while it is being - parsed. */ - -class c_struct_parse_info -{ -public: - /* If warn_cxx_compat, a list of types defined within this - struct. */ - auto_vec struct_types; - /* If warn_cxx_compat, a list of field names which have bindings, - and which are defined in this struct, but which are not defined - in any enclosing struct. This is used to clear the in_struct - field of the c_bindings structure. */ - auto_vec fields; - /* If warn_cxx_compat, a list of typedef names used when defining - fields in this struct. */ - auto_vec typedefs_seen; -}; - -/* Information for the struct or union currently being parsed, or - NULL if not parsing a struct or union. */ -static class c_struct_parse_info *struct_parse_info; - -/* Forward declarations. */ -static tree lookup_name_in_scope (tree, struct c_scope *); -static tree c_make_fname_decl (location_t, tree, int); -static tree grokdeclarator (const struct c_declarator *, - struct c_declspecs *, - enum decl_context, bool, tree *, tree *, tree *, - bool *, enum deprecated_states); -static tree grokparms (struct c_arg_info *, bool); -static void layout_array_type (tree); -static void warn_defaults_to (location_t, int, const char *, ...) - ATTRIBUTE_GCC_DIAG(3,4); -static const char *header_for_builtin_fn (tree); - -/* T is a statement. Add it to the statement-tree. This is the - C/ObjC version--C++ has a slightly different version of this - function. */ - -tree -add_stmt (tree t) -{ - enum tree_code code = TREE_CODE (t); - - if (CAN_HAVE_LOCATION_P (t) && code != LABEL_EXPR) - { - if (!EXPR_HAS_LOCATION (t)) - SET_EXPR_LOCATION (t, input_location); - } - - if (code == LABEL_EXPR || code == CASE_LABEL_EXPR) - STATEMENT_LIST_HAS_LABEL (cur_stmt_list) = 1; - - /* Add T to the statement-tree. Non-side-effect statements need to be - recorded during statement expressions. */ - if (!building_stmt_list_p ()) - push_stmt_list (); - append_to_statement_list_force (t, &cur_stmt_list); - - return t; -} - -/* Build a pointer type using the default pointer mode. */ - -static tree -c_build_pointer_type (tree to_type) -{ - addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC - : TYPE_ADDR_SPACE (to_type); - machine_mode pointer_mode; - - if (as != ADDR_SPACE_GENERIC || c_default_pointer_mode == VOIDmode) - pointer_mode = targetm.addr_space.pointer_mode (as); - else - pointer_mode = c_default_pointer_mode; - return build_pointer_type_for_mode (to_type, pointer_mode, false); -} - - -/* Return true if we will want to say something if a goto statement - crosses DECL. */ - -static bool -decl_jump_unsafe (tree decl) -{ - if (error_operand_p (decl)) - return false; - - /* Don't warn for compound literals. If a goto statement crosses - their initialization, it should cross also all the places where - the complit is used or where the complit address might be saved - into some variable, so code after the label to which goto jumps - should not be able to refer to the compound literal. */ - if (VAR_P (decl) && C_DECL_COMPOUND_LITERAL_P (decl)) - return false; - - /* Always warn about crossing variably modified types. */ - if ((VAR_P (decl) || TREE_CODE (decl) == TYPE_DECL) - && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) - return true; - - /* Otherwise, only warn if -Wgoto-misses-init and this is an - initialized automatic decl. */ - if (warn_jump_misses_init - && VAR_P (decl) - && !TREE_STATIC (decl) - && DECL_INITIAL (decl) != NULL_TREE) - return true; - - return false; -} - - -void -c_print_identifier (FILE *file, tree node, int indent) -{ - void (*save) (enum c_oracle_request, tree identifier); - - /* Temporarily hide any binding oracle. Without this, calls to - debug_tree from the debugger will end up calling into the oracle, - making for a confusing debug session. As the oracle isn't needed - here for normal operation, it's simplest to suppress it. */ - save = c_binding_oracle; - c_binding_oracle = NULL; - - print_node (file, "symbol", I_SYMBOL_DECL (node), indent + 4); - print_node (file, "tag", I_TAG_DECL (node), indent + 4); - print_node (file, "label", I_LABEL_DECL (node), indent + 4); - if (C_IS_RESERVED_WORD (node) && C_RID_CODE (node) != RID_CXX_COMPAT_WARN) - { - tree rid = ridpointers[C_RID_CODE (node)]; - indent_to (file, indent + 4); - fprintf (file, "rid " HOST_PTR_PRINTF " \"%s\"", - (void *) rid, IDENTIFIER_POINTER (rid)); - } - - c_binding_oracle = save; -} - -/* Establish a binding between NAME, an IDENTIFIER_NODE, and DECL, - which may be any of several kinds of DECL or TYPE or error_mark_node, - in the scope SCOPE. */ -static void -bind (tree name, tree decl, struct c_scope *scope, bool invisible, - bool nested, location_t locus) -{ - struct c_binding *b, **here; - - if (binding_freelist) - { - b = binding_freelist; - binding_freelist = b->prev; - } - else - b = ggc_alloc (); - - b->shadowed = 0; - b->decl = decl; - b->id = name; - b->depth = scope->depth; - b->invisible = invisible; - b->nested = nested; - b->inner_comp = 0; - b->in_struct = 0; - b->locus = locus; - - b->u.type = NULL; - - b->prev = scope->bindings; - scope->bindings = b; - - if (decl_jump_unsafe (decl)) - scope->has_jump_unsafe_decl = 1; - - if (!name) - return; - - switch (TREE_CODE (decl)) - { - case LABEL_DECL: here = &I_LABEL_BINDING (name); break; - case ENUMERAL_TYPE: - case UNION_TYPE: - case RECORD_TYPE: here = &I_TAG_BINDING (name); break; - case VAR_DECL: - case FUNCTION_DECL: - case TYPE_DECL: - case CONST_DECL: - case PARM_DECL: - case ERROR_MARK: here = &I_SYMBOL_BINDING (name); break; - - default: - gcc_unreachable (); - } - - /* Locate the appropriate place in the chain of shadowed decls - to insert this binding. Normally, scope == current_scope and - this does nothing. */ - while (*here && (*here)->depth > scope->depth) - here = &(*here)->shadowed; - - b->shadowed = *here; - *here = b; -} - -/* Clear the binding structure B, stick it on the binding_freelist, - and return the former value of b->prev. This is used by pop_scope - and get_parm_info to iterate destructively over all the bindings - from a given scope. */ -static struct c_binding * -free_binding_and_advance (struct c_binding *b) -{ - struct c_binding *prev = b->prev; - - memset (b, 0, sizeof (struct c_binding)); - b->prev = binding_freelist; - binding_freelist = b; - - return prev; -} - -/* Bind a label. Like bind, but skip fields which aren't used for - labels, and add the LABEL_VARS value. */ -static void -bind_label (tree name, tree label, struct c_scope *scope, - struct c_label_vars *label_vars) -{ - struct c_binding *b; - - bind (name, label, scope, /*invisible=*/false, /*nested=*/false, - UNKNOWN_LOCATION); - - scope->has_label_bindings = true; - - b = scope->bindings; - gcc_assert (b->decl == label); - label_vars->shadowed = b->u.label; - b->u.label = label_vars; -} - -/* Hook called at end of compilation to assume 1 elt - for a file-scope tentative array defn that wasn't complete before. */ - -void -c_finish_incomplete_decl (tree decl) -{ - if (VAR_P (decl)) - { - tree type = TREE_TYPE (decl); - if (type != error_mark_node - && TREE_CODE (type) == ARRAY_TYPE - && !DECL_EXTERNAL (decl) - && TYPE_DOMAIN (type) == NULL_TREE) - { - warning_at (DECL_SOURCE_LOCATION (decl), - 0, "array %q+D assumed to have one element", decl); - - complete_array_type (&TREE_TYPE (decl), NULL_TREE, true); - - relayout_decl (decl); - } - } -} - -/* Record that inline function FUNC contains a reference (location - LOC) to static DECL (file-scope or function-local according to - TYPE). */ - -void -record_inline_static (location_t loc, tree func, tree decl, - enum c_inline_static_type type) -{ - c_inline_static *csi = ggc_alloc (); - csi->location = loc; - csi->function = func; - csi->static_decl = decl; - csi->type = type; - csi->next = c_inline_statics; - c_inline_statics = csi; -} - -/* Check for references to static declarations in inline functions at - the end of the translation unit and diagnose them if the functions - are still inline definitions. */ - -static void -check_inline_statics (void) -{ - struct c_inline_static *csi; - for (csi = c_inline_statics; csi; csi = csi->next) - { - if (DECL_EXTERNAL (csi->function)) - switch (csi->type) - { - case csi_internal: - pedwarn (csi->location, 0, - "%qD is static but used in inline function %qD " - "which is not static", csi->static_decl, csi->function); - break; - case csi_modifiable: - pedwarn (csi->location, 0, - "%q+D is static but declared in inline function %qD " - "which is not static", csi->static_decl, csi->function); - break; - default: - gcc_unreachable (); - } - } - c_inline_statics = NULL; -} - -/* Fill in a c_spot_bindings structure. If DEFINING is true, set it - for the current state, otherwise set it to uninitialized. */ - -static void -set_spot_bindings (struct c_spot_bindings *p, bool defining) -{ - if (defining) - { - p->scope = current_scope; - p->bindings_in_scope = current_scope->bindings; - } - else - { - p->scope = NULL; - p->bindings_in_scope = NULL; - } - p->stmt_exprs = 0; - p->left_stmt_expr = false; -} - -/* Update spot bindings P as we pop out of SCOPE. Return true if we - should push decls for a label. */ - -static bool -update_spot_bindings (struct c_scope *scope, struct c_spot_bindings *p) -{ - if (p->scope != scope) - { - /* This label or goto is defined in some other scope, or it is a - label which is not yet defined. There is nothing to - update. */ - return false; - } - - /* Adjust the spot bindings to refer to the bindings already defined - in the enclosing scope. */ - p->scope = scope->outer; - p->bindings_in_scope = p->scope->bindings; - - return true; -} - -/* The Objective-C front-end often needs to determine the current scope. */ - -void * -objc_get_current_scope (void) -{ - return current_scope; -} - -/* The following function is used only by Objective-C. It needs to live here - because it accesses the innards of c_scope. */ - -void -objc_mark_locals_volatile (void *enclosing_blk) -{ - struct c_scope *scope; - struct c_binding *b; - - for (scope = current_scope; - scope && scope != enclosing_blk; - scope = scope->outer) - { - for (b = scope->bindings; b; b = b->prev) - objc_volatilize_decl (b->decl); - - /* Do not climb up past the current function. */ - if (scope->function_body) - break; - } -} - -/* Return true if we are in the global binding level. */ - -bool -global_bindings_p (void) -{ - return current_scope == file_scope; -} - -/* Return true if we're declaring parameters in an old-style function - declaration. */ - -bool -old_style_parameter_scope (void) -{ - /* If processing parameters and there is no function statement list, we - * have an old-style function declaration. */ - return (current_scope->parm_flag && !DECL_SAVED_TREE (current_function_decl)); -} - -void -keep_next_level (void) -{ - keep_next_level_flag = true; -} - -/* Set the flag for the FLOAT_CONST_DECIMAL64 pragma being ON. */ - -void -set_float_const_decimal64 (void) -{ - current_scope->float_const_decimal64 = true; -} - -/* Clear the flag for the FLOAT_CONST_DECIMAL64 pragma. */ - -void -clear_float_const_decimal64 (void) -{ - current_scope->float_const_decimal64 = false; -} - -/* Return nonzero if an unsuffixed float constant is _Decimal64. */ - -bool -float_const_decimal64_p (void) -{ - return current_scope->float_const_decimal64; -} - -/* Identify this scope as currently being filled with parameters. */ - -void -declare_parm_level (void) -{ - current_scope->parm_flag = true; -} - -void -push_scope (void) -{ - if (next_is_function_body) - { - /* This is the transition from the parameters to the top level - of the function body. These are the same scope - (C99 6.2.1p4,6) so we do not push another scope structure. - next_is_function_body is set only by store_parm_decls, which - in turn is called when and only when we are about to - encounter the opening curly brace for the function body. - - The outermost block of a function always gets a BLOCK node, - because the debugging output routines expect that each - function has at least one BLOCK. */ - current_scope->parm_flag = false; - current_scope->function_body = true; - current_scope->keep = true; - current_scope->outer_function = current_function_scope; - current_function_scope = current_scope; - - keep_next_level_flag = false; - next_is_function_body = false; - - /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes. */ - if (current_scope->outer) - current_scope->float_const_decimal64 - = current_scope->outer->float_const_decimal64; - else - current_scope->float_const_decimal64 = false; - } - else - { - struct c_scope *scope; - if (scope_freelist) - { - scope = scope_freelist; - scope_freelist = scope->outer; - } - else - scope = ggc_cleared_alloc (); - - /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes. */ - if (current_scope) - scope->float_const_decimal64 = current_scope->float_const_decimal64; - else - scope->float_const_decimal64 = false; - - scope->keep = keep_next_level_flag; - scope->outer = current_scope; - scope->depth = current_scope ? (current_scope->depth + 1) : 0; - - /* Check for scope depth overflow. Unlikely (2^28 == 268,435,456) but - possible. */ - if (current_scope && scope->depth == 0) - { - scope->depth--; - sorry ("GCC supports only %u nested scopes", scope->depth); - } - - current_scope = scope; - keep_next_level_flag = false; - } -} - -/* This is called when we are leaving SCOPE. For each label defined - in SCOPE, add any appropriate decls to its decls_in_scope fields. - These are the decls whose initialization will be skipped by a goto - later in the function. */ - -static void -update_label_decls (struct c_scope *scope) -{ - struct c_scope *s; - - s = scope; - while (s != NULL) - { - if (s->has_label_bindings) - { - struct c_binding *b; - - for (b = s->bindings; b != NULL; b = b->prev) - { - struct c_label_vars *label_vars; - struct c_binding *b1; - bool hjud; - unsigned int ix; - struct c_goto_bindings *g; - - if (TREE_CODE (b->decl) != LABEL_DECL) - continue; - label_vars = b->u.label; - - b1 = label_vars->label_bindings.bindings_in_scope; - if (label_vars->label_bindings.scope == NULL) - hjud = false; - else - hjud = label_vars->label_bindings.scope->has_jump_unsafe_decl; - if (update_spot_bindings (scope, &label_vars->label_bindings)) - { - /* This label is defined in this scope. */ - if (hjud) - { - for (; b1 != NULL; b1 = b1->prev) - { - /* A goto from later in the function to this - label will never see the initialization - of B1, if any. Save it to issue a - warning if needed. */ - if (decl_jump_unsafe (b1->decl)) - vec_safe_push(label_vars->decls_in_scope, b1->decl); - } - } - } - - /* Update the bindings of any goto statements associated - with this label. */ - FOR_EACH_VEC_SAFE_ELT (label_vars->gotos, ix, g) - update_spot_bindings (scope, &g->goto_bindings); - } - } - - /* Don't search beyond the current function. */ - if (s == current_function_scope) - break; - - s = s->outer; - } -} - -/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT. */ - -static void -set_type_context (tree type, tree context) -{ - for (type = TYPE_MAIN_VARIANT (type); type; - type = TYPE_NEXT_VARIANT (type)) - TYPE_CONTEXT (type) = context; -} - -/* Exit a scope. Restore the state of the identifier-decl mappings - that were in effect when this scope was entered. Return a BLOCK - node containing all the DECLs in this scope that are of interest - to debug info generation. */ - -tree -pop_scope (void) -{ - struct c_scope *scope = current_scope; - tree block, context, p; - struct c_binding *b; - - bool functionbody = scope->function_body; - bool keep = functionbody || scope->keep || scope->bindings; - - update_label_decls (scope); - - /* If appropriate, create a BLOCK to record the decls for the life - of this function. */ - block = NULL_TREE; - if (keep) - { - block = make_node (BLOCK); - BLOCK_SUBBLOCKS (block) = scope->blocks; - TREE_USED (block) = 1; - - /* In each subblock, record that this is its superior. */ - for (p = scope->blocks; p; p = BLOCK_CHAIN (p)) - BLOCK_SUPERCONTEXT (p) = block; - - BLOCK_VARS (block) = NULL_TREE; - } - - /* The TYPE_CONTEXTs for all of the tagged types belonging to this - scope must be set so that they point to the appropriate - construct, i.e. either to the current FUNCTION_DECL node, or - else to the BLOCK node we just constructed. - - Note that for tagged types whose scope is just the formal - parameter list for some function type specification, we can't - properly set their TYPE_CONTEXTs here, because we don't have a - pointer to the appropriate FUNCTION_TYPE node readily available - to us. For those cases, the TYPE_CONTEXTs of the relevant tagged - type nodes get set in `grokdeclarator' as soon as we have created - the FUNCTION_TYPE node which will represent the "scope" for these - "parameter list local" tagged types. */ - if (scope->function_body) - context = current_function_decl; - else if (scope == file_scope) - { - tree file_decl - = build_translation_unit_decl (get_identifier (main_input_filename)); - context = file_decl; - debug_hooks->register_main_translation_unit (file_decl); - } - else - context = block; - - /* Clear all bindings in this scope. */ - for (b = scope->bindings; b; b = free_binding_and_advance (b)) - { - p = b->decl; - switch (TREE_CODE (p)) - { - case LABEL_DECL: - /* Warnings for unused labels, errors for undefined labels. */ - if (TREE_USED (p) && !DECL_INITIAL (p)) - { - error ("label %q+D used but not defined", p); - DECL_INITIAL (p) = error_mark_node; - } - else - warn_for_unused_label (p); - - /* Labels go in BLOCK_VARS. */ - DECL_CHAIN (p) = BLOCK_VARS (block); - BLOCK_VARS (block) = p; - gcc_assert (I_LABEL_BINDING (b->id) == b); - I_LABEL_BINDING (b->id) = b->shadowed; - - /* Also pop back to the shadowed label_vars. */ - release_tree_vector (b->u.label->decls_in_scope); - b->u.label = b->u.label->shadowed; - break; - - case ENUMERAL_TYPE: - case UNION_TYPE: - case RECORD_TYPE: - set_type_context (p, context); - - /* Types may not have tag-names, in which case the type - appears in the bindings list with b->id NULL. */ - if (b->id) - { - gcc_assert (I_TAG_BINDING (b->id) == b); - I_TAG_BINDING (b->id) = b->shadowed; - } - break; - - case FUNCTION_DECL: - /* Propagate TREE_ADDRESSABLE from nested functions to their - containing functions. */ - if (!TREE_ASM_WRITTEN (p) - && DECL_INITIAL (p) != NULL_TREE - && TREE_ADDRESSABLE (p) - && DECL_ABSTRACT_ORIGIN (p) != NULL_TREE - && DECL_ABSTRACT_ORIGIN (p) != p) - TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (p)) = 1; - if (!TREE_PUBLIC (p) - && !DECL_INITIAL (p) - && !b->nested - && scope != file_scope - && scope != external_scope) - { - error ("nested function %q+D declared but never defined", p); - undef_nested_function = true; - } - else if (DECL_DECLARED_INLINE_P (p) - && TREE_PUBLIC (p) - && !DECL_INITIAL (p)) - { - /* C99 6.7.4p6: "a function with external linkage... declared - with an inline function specifier ... shall also be defined - in the same translation unit." */ - if (!flag_gnu89_inline - && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (p)) - && scope == external_scope) - pedwarn (input_location, 0, - "inline function %q+D declared but never defined", p); - DECL_EXTERNAL (p) = 1; - } - - goto common_symbol; - - case VAR_DECL: - /* Warnings for unused variables. */ - if ((!TREE_USED (p) || !DECL_READ_P (p)) - && !warning_suppressed_p (p, OPT_Wunused_but_set_variable) - && !DECL_IN_SYSTEM_HEADER (p) - && DECL_NAME (p) - && !DECL_ARTIFICIAL (p) - && scope != file_scope - && scope != external_scope) - { - if (!TREE_USED (p)) - warning (OPT_Wunused_variable, "unused variable %q+D", p); - else if (DECL_CONTEXT (p) == current_function_decl) - warning_at (DECL_SOURCE_LOCATION (p), - OPT_Wunused_but_set_variable, - "variable %qD set but not used", p); - } - - if (b->inner_comp) - { - error ("type of array %q+D completed incompatibly with" - " implicit initialization", p); - } - - /* Fall through. */ - case TYPE_DECL: - case CONST_DECL: - common_symbol: - /* All of these go in BLOCK_VARS, but only if this is the - binding in the home scope. */ - if (!b->nested) - { - DECL_CHAIN (p) = BLOCK_VARS (block); - BLOCK_VARS (block) = p; - } - else if (VAR_OR_FUNCTION_DECL_P (p) && scope != file_scope) - { - /* For block local externs add a special - DECL_EXTERNAL decl for debug info generation. */ - tree extp = copy_node (p); - - DECL_EXTERNAL (extp) = 1; - TREE_STATIC (extp) = 0; - TREE_PUBLIC (extp) = 1; - DECL_INITIAL (extp) = NULL_TREE; - DECL_LANG_SPECIFIC (extp) = NULL; - DECL_CONTEXT (extp) = current_function_decl; - if (TREE_CODE (p) == FUNCTION_DECL) - { - DECL_RESULT (extp) = NULL_TREE; - DECL_SAVED_TREE (extp) = NULL_TREE; - DECL_STRUCT_FUNCTION (extp) = NULL; - } - if (b->locus != UNKNOWN_LOCATION) - DECL_SOURCE_LOCATION (extp) = b->locus; - DECL_CHAIN (extp) = BLOCK_VARS (block); - BLOCK_VARS (block) = extp; - } - /* If this is the file scope set DECL_CONTEXT of each decl to - the TRANSLATION_UNIT_DECL. This makes same_translation_unit_p - work. */ - if (scope == file_scope) - { - DECL_CONTEXT (p) = context; - if (TREE_CODE (p) == TYPE_DECL - && TREE_TYPE (p) != error_mark_node) - set_type_context (TREE_TYPE (p), context); - } - - gcc_fallthrough (); - /* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have - already been put there by store_parm_decls. Unused- - parameter warnings are handled by function.c. - error_mark_node obviously does not go in BLOCK_VARS and - does not get unused-variable warnings. */ - case PARM_DECL: - case ERROR_MARK: - /* It is possible for a decl not to have a name. We get - here with b->id NULL in this case. */ - if (b->id) - { - gcc_assert (I_SYMBOL_BINDING (b->id) == b); - I_SYMBOL_BINDING (b->id) = b->shadowed; - if (b->shadowed && b->shadowed->u.type) - TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type; - } - break; - - default: - gcc_unreachable (); - } - } - - - /* Dispose of the block that we just made inside some higher level. */ - if ((scope->function_body || scope == file_scope) && context) - { - DECL_INITIAL (context) = block; - BLOCK_SUPERCONTEXT (block) = context; - } - else if (scope->outer) - { - if (block) - SCOPE_LIST_APPEND (scope->outer, blocks, block); - /* If we did not make a block for the scope just exited, any - blocks made for inner scopes must be carried forward so they - will later become subblocks of something else. */ - else if (scope->blocks) - SCOPE_LIST_CONCAT (scope->outer, blocks, scope, blocks); - } - - /* Pop the current scope, and free the structure for reuse. */ - current_scope = scope->outer; - if (scope->function_body) - current_function_scope = scope->outer_function; - - memset (scope, 0, sizeof (struct c_scope)); - scope->outer = scope_freelist; - scope_freelist = scope; - - return block; -} - -void -push_file_scope (void) -{ - tree decl; - - if (file_scope) - return; - - push_scope (); - file_scope = current_scope; - - start_fname_decls (); - - for (decl = visible_builtins; decl; decl = DECL_CHAIN (decl)) - bind (DECL_NAME (decl), decl, file_scope, - /*invisible=*/false, /*nested=*/true, DECL_SOURCE_LOCATION (decl)); -} - -void -pop_file_scope (void) -{ - /* In case there were missing closebraces, get us back to the global - binding level. */ - while (current_scope != file_scope) - pop_scope (); - - /* __FUNCTION__ is defined at file scope (""). This - call may not be necessary as my tests indicate it - still works without it. */ - finish_fname_decls (); - - check_inline_statics (); - - /* This is the point to write out a PCH if we're doing that. - In that case we do not want to do anything else. */ - if (pch_file) - { - c_common_write_pch (); - /* Ensure even the callers don't try to finalize the CU. */ - flag_syntax_only = 1; - return; - } - - /* Pop off the file scope and close this translation unit. */ - pop_scope (); - file_scope = 0; - - maybe_apply_pending_pragma_weaks (); -} - -/* Adjust the bindings for the start of a statement expression. */ - -void -c_bindings_start_stmt_expr (struct c_spot_bindings* switch_bindings) -{ - struct c_scope *scope; - - for (scope = current_scope; scope != NULL; scope = scope->outer) - { - struct c_binding *b; - - if (!scope->has_label_bindings) - continue; - - for (b = scope->bindings; b != NULL; b = b->prev) - { - struct c_label_vars *label_vars; - unsigned int ix; - struct c_goto_bindings *g; - - if (TREE_CODE (b->decl) != LABEL_DECL) - continue; - label_vars = b->u.label; - ++label_vars->label_bindings.stmt_exprs; - FOR_EACH_VEC_SAFE_ELT (label_vars->gotos, ix, g) - ++g->goto_bindings.stmt_exprs; - } - } - - if (switch_bindings != NULL) - ++switch_bindings->stmt_exprs; -} - -/* Adjust the bindings for the end of a statement expression. */ - -void -c_bindings_end_stmt_expr (struct c_spot_bindings *switch_bindings) -{ - struct c_scope *scope; - - for (scope = current_scope; scope != NULL; scope = scope->outer) - { - struct c_binding *b; - - if (!scope->has_label_bindings) - continue; - - for (b = scope->bindings; b != NULL; b = b->prev) - { - struct c_label_vars *label_vars; - unsigned int ix; - struct c_goto_bindings *g; - - if (TREE_CODE (b->decl) != LABEL_DECL) - continue; - label_vars = b->u.label; - --label_vars->label_bindings.stmt_exprs; - if (label_vars->label_bindings.stmt_exprs < 0) - { - label_vars->label_bindings.left_stmt_expr = true; - label_vars->label_bindings.stmt_exprs = 0; - } - FOR_EACH_VEC_SAFE_ELT (label_vars->gotos, ix, g) - { - --g->goto_bindings.stmt_exprs; - if (g->goto_bindings.stmt_exprs < 0) - { - g->goto_bindings.left_stmt_expr = true; - g->goto_bindings.stmt_exprs = 0; - } - } - } - } - - if (switch_bindings != NULL) - { - --switch_bindings->stmt_exprs; - gcc_assert (switch_bindings->stmt_exprs >= 0); - } -} - -/* Push a definition or a declaration of struct, union or enum tag "name". - "type" should be the type node. - We assume that the tag "name" is not already defined, and has a location - of LOC. - - Note that the definition may really be just a forward reference. - In that case, the TYPE_SIZE will be zero. */ - -static void -pushtag (location_t loc, tree name, tree type) -{ - /* Record the identifier as the type's name if it has none. */ - if (name && !TYPE_NAME (type)) - TYPE_NAME (type) = name; - bind (name, type, current_scope, /*invisible=*/false, /*nested=*/false, loc); - - /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE will be the - tagged type we just added to the current scope. This fake - NULL-named TYPE_DECL node helps dwarfout.c to know when it needs - to output a representation of a tagged type, and it also gives - us a convenient place to record the "scope start" address for the - tagged type. */ - - TYPE_STUB_DECL (type) = pushdecl (build_decl (loc, - TYPE_DECL, NULL_TREE, type)); - - /* An approximation for now, so we can tell this is a function-scope tag. - This will be updated in pop_scope. */ - TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type)); - - if (warn_cxx_compat && name != NULL_TREE) - { - struct c_binding *b = I_SYMBOL_BINDING (name); - - if (b != NULL - && b->decl != NULL_TREE - && TREE_CODE (b->decl) == TYPE_DECL - && (B_IN_CURRENT_SCOPE (b) - || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) - && (TYPE_MAIN_VARIANT (TREE_TYPE (b->decl)) - != TYPE_MAIN_VARIANT (type))) - { - auto_diagnostic_group d; - if (warning_at (loc, OPT_Wc___compat, - ("using %qD as both a typedef and a tag is " - "invalid in C++"), b->decl) - && b->locus != UNKNOWN_LOCATION) - inform (b->locus, "originally defined here"); - } - } -} - -/* An exported interface to pushtag. This is used by the gdb plugin's - binding oracle to introduce a new tag binding. */ - -void -c_pushtag (location_t loc, tree name, tree type) -{ - pushtag (loc, name, type); -} - -/* An exported interface to bind a declaration. LOC is the location - to use. DECL is the declaration to bind. The decl's name is used - to determine how it is bound. If DECL is a VAR_DECL, then - IS_GLOBAL determines whether the decl is put into the global (file - and external) scope or the current function's scope; if DECL is not - a VAR_DECL then it is always put into the file scope. */ - -void -c_bind (location_t loc, tree decl, bool is_global) -{ - struct c_scope *scope; - bool nested = false; - - if (!VAR_P (decl) || current_function_scope == NULL) - { - /* Types and functions are always considered to be global. */ - scope = file_scope; - DECL_EXTERNAL (decl) = 1; - TREE_PUBLIC (decl) = 1; - } - else if (is_global) - { - /* Also bind it into the external scope. */ - bind (DECL_NAME (decl), decl, external_scope, true, false, loc); - nested = true; - scope = file_scope; - DECL_EXTERNAL (decl) = 1; - TREE_PUBLIC (decl) = 1; - } - else - { - DECL_CONTEXT (decl) = current_function_decl; - TREE_PUBLIC (decl) = 0; - scope = current_function_scope; - } - - bind (DECL_NAME (decl), decl, scope, false, nested, loc); -} - - -/* Stores the first FILE*, const struct tm* etc. argument type (whatever - it is) seen in a declaration of a file I/O etc. built-in, corresponding - to the builtin_structptr_types array. Subsequent declarations of such - built-ins are expected to refer to it rather than to fileptr_type_node, - etc. which is just void* (or to any other type). - Used only by match_builtin_function_types. */ - -static const unsigned builtin_structptr_type_count - = sizeof builtin_structptr_types / sizeof builtin_structptr_types[0]; - -static GTY(()) tree last_structptr_types[builtin_structptr_type_count]; - -/* Returns true if types T1 and T2 representing return types or types - of function arguments are close enough to be considered interchangeable - in redeclarations of built-in functions. */ - -static bool -types_close_enough_to_match (tree t1, tree t2) -{ - return (TYPE_MODE (t1) == TYPE_MODE (t2) - && POINTER_TYPE_P (t1) == POINTER_TYPE_P (t2) - && FUNCTION_POINTER_TYPE_P (t1) == FUNCTION_POINTER_TYPE_P (t2)); -} - -/* Subroutine of compare_decls. Allow harmless mismatches in return - and argument types provided that the type modes match. Set *STRICT - and *ARGNO to the expected argument type and number in case of - an argument type mismatch or null and zero otherwise. Return - a unified type given a suitable match, and 0 otherwise. */ - -static tree -match_builtin_function_types (tree newtype, tree oldtype, - tree *strict, unsigned *argno) -{ - *argno = 0; - *strict = NULL_TREE; - - /* Accept the return type of the new declaration if it has the same - mode and if they're both pointers or if neither is. */ - tree oldrettype = TREE_TYPE (oldtype); - tree newrettype = TREE_TYPE (newtype); - - if (!types_close_enough_to_match (oldrettype, newrettype)) - return NULL_TREE; - - /* Check that the return types are compatible but don't fail if they - are not (e.g., int vs long in ILP32) and just let the caller know. */ - if (!comptypes (TYPE_MAIN_VARIANT (oldrettype), - TYPE_MAIN_VARIANT (newrettype))) - *strict = oldrettype; - - tree oldargs = TYPE_ARG_TYPES (oldtype); - tree newargs = TYPE_ARG_TYPES (newtype); - tree tryargs = newargs; - - const unsigned nlst - = sizeof last_structptr_types / sizeof last_structptr_types[0]; - const unsigned nbst - = sizeof builtin_structptr_types / sizeof builtin_structptr_types[0]; - - gcc_checking_assert (nlst == nbst); - - for (unsigned i = 1; oldargs || newargs; ++i) - { - if (!oldargs - || !newargs - || !TREE_VALUE (oldargs) - || !TREE_VALUE (newargs)) - return NULL_TREE; - - tree oldtype = TYPE_MAIN_VARIANT (TREE_VALUE (oldargs)); - tree newtype = TREE_VALUE (newargs); - if (newtype == error_mark_node) - return NULL_TREE; - newtype = TYPE_MAIN_VARIANT (newtype); - - if (!types_close_enough_to_match (oldtype, newtype)) - return NULL_TREE; - - unsigned j = nbst; - if (POINTER_TYPE_P (oldtype)) - /* Iterate over well-known struct types like FILE (whose types - aren't known to us) and compare the pointer to each to - the pointer argument. */ - for (j = 0; j < nbst; ++j) - { - if (TREE_VALUE (oldargs) != builtin_structptr_types[j].node) - continue; - /* Store the first FILE* etc. argument type (whatever it is), and - expect any subsequent declarations of file I/O etc. built-ins - to refer to it rather than to fileptr_type_node etc. which is - just void* (or const void*). */ - if (last_structptr_types[j]) - { - if (!comptypes (last_structptr_types[j], newtype)) - { - *argno = i; - *strict = last_structptr_types[j]; - } - } - else - last_structptr_types[j] = newtype; - break; - } - - if (j == nbst && !comptypes (oldtype, newtype)) - { - if (POINTER_TYPE_P (oldtype)) - { - /* For incompatible pointers, only reject differences in - the unqualified variants of the referenced types but - consider differences in qualifiers as benign (report - those to caller via *STRICT below). */ - tree oldref = TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)); - tree newref = TYPE_MAIN_VARIANT (TREE_TYPE (newtype)); - if (!comptypes (oldref, newref)) - return NULL_TREE; - } - - if (!*strict) - { - *argno = i; - *strict = oldtype; - } - } - - oldargs = TREE_CHAIN (oldargs); - newargs = TREE_CHAIN (newargs); - } - - tree trytype = build_function_type (newrettype, tryargs); - - /* Allow declaration to change transaction_safe attribute. */ - tree oldattrs = TYPE_ATTRIBUTES (oldtype); - tree oldtsafe = lookup_attribute ("transaction_safe", oldattrs); - tree newattrs = TYPE_ATTRIBUTES (newtype); - tree newtsafe = lookup_attribute ("transaction_safe", newattrs); - if (oldtsafe && !newtsafe) - oldattrs = remove_attribute ("transaction_safe", oldattrs); - else if (newtsafe && !oldtsafe) - oldattrs = tree_cons (get_identifier ("transaction_safe"), - NULL_TREE, oldattrs); - - return build_type_attribute_variant (trytype, oldattrs); -} - -/* Subroutine of diagnose_mismatched_decls. Check for function type - mismatch involving an empty arglist vs a nonempty one and give clearer - diagnostics. */ -static void -diagnose_arglist_conflict (tree newdecl, tree olddecl, - tree newtype, tree oldtype) -{ - tree t; - - if (TREE_CODE (olddecl) != FUNCTION_DECL - || !comptypes (TREE_TYPE (oldtype), TREE_TYPE (newtype)) - || !((!prototype_p (oldtype) && DECL_INITIAL (olddecl) == NULL_TREE) - || (!prototype_p (newtype) && DECL_INITIAL (newdecl) == NULL_TREE))) - return; - - t = TYPE_ARG_TYPES (oldtype); - if (t == NULL_TREE) - t = TYPE_ARG_TYPES (newtype); - for (; t; t = TREE_CHAIN (t)) - { - tree type = TREE_VALUE (t); - - if (TREE_CHAIN (t) == NULL_TREE - && TYPE_MAIN_VARIANT (type) != void_type_node) - { - inform (input_location, "a parameter list with an ellipsis " - "cannot match an empty parameter name list declaration"); - break; - } - - if (c_type_promotes_to (type) != type) - { - inform (input_location, "an argument type that has a default " - "promotion cannot match an empty parameter name list " - "declaration"); - break; - } - } -} - -/* Another subroutine of diagnose_mismatched_decls. OLDDECL is an - old-style function definition, NEWDECL is a prototype declaration. - Diagnose inconsistencies in the argument list. Returns TRUE if - the prototype is compatible, FALSE if not. */ -static bool -validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype) -{ - tree newargs, oldargs; - int i; - -#define END_OF_ARGLIST(t) ((t) == void_type_node) - - oldargs = TYPE_ACTUAL_ARG_TYPES (oldtype); - newargs = TYPE_ARG_TYPES (newtype); - i = 1; - - for (;;) - { - tree oldargtype = TREE_VALUE (oldargs); - tree newargtype = TREE_VALUE (newargs); - - if (oldargtype == error_mark_node || newargtype == error_mark_node) - return false; - - oldargtype = (TYPE_ATOMIC (oldargtype) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (oldargtype), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (oldargtype)); - newargtype = (TYPE_ATOMIC (newargtype) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (newargtype), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (newargtype)); - - if (END_OF_ARGLIST (oldargtype) && END_OF_ARGLIST (newargtype)) - break; - - /* Reaching the end of just one list means the two decls don't - agree on the number of arguments. */ - if (END_OF_ARGLIST (oldargtype)) - { - error ("prototype for %q+D declares more arguments " - "than previous old-style definition", newdecl); - return false; - } - else if (END_OF_ARGLIST (newargtype)) - { - error ("prototype for %q+D declares fewer arguments " - "than previous old-style definition", newdecl); - return false; - } - - /* Type for passing arg must be consistent with that declared - for the arg. */ - else if (!comptypes (oldargtype, newargtype)) - { - error ("prototype for %q+D declares argument %d" - " with incompatible type", - newdecl, i); - return false; - } - - oldargs = TREE_CHAIN (oldargs); - newargs = TREE_CHAIN (newargs); - i++; - } - - /* If we get here, no errors were found, but do issue a warning - for this poor-style construct. */ - warning (0, "prototype for %q+D follows non-prototype definition", - newdecl); - return true; -#undef END_OF_ARGLIST -} - -/* Subroutine of diagnose_mismatched_decls. Report the location of DECL, - first in a pair of mismatched declarations, using the diagnostic - function DIAG. */ -static void -locate_old_decl (tree decl) -{ - if (TREE_CODE (decl) == FUNCTION_DECL - && fndecl_built_in_p (decl) - && !C_DECL_DECLARED_BUILTIN (decl)) - ; - else if (DECL_INITIAL (decl)) - inform (input_location, - "previous definition of %q+D with type %qT", - decl, TREE_TYPE (decl)); - else if (C_DECL_IMPLICIT (decl)) - inform (input_location, - "previous implicit declaration of %q+D with type %qT", - decl, TREE_TYPE (decl)); - else - inform (input_location, - "previous declaration of %q+D with type %qT", - decl, TREE_TYPE (decl)); -} - -/* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL. - Returns true if the caller should proceed to merge the two, false - if OLDDECL should simply be discarded. As a side effect, issues - all necessary diagnostics for invalid or poor-style combinations. - If it returns true, writes the types of NEWDECL and OLDDECL to - *NEWTYPEP and *OLDTYPEP - these may have been adjusted from - TREE_TYPE (NEWDECL, OLDDECL) respectively. */ - -static bool -diagnose_mismatched_decls (tree newdecl, tree olddecl, - tree *newtypep, tree *oldtypep) -{ - tree newtype, oldtype; - bool retval = true; - -#define DECL_EXTERN_INLINE(DECL) (DECL_DECLARED_INLINE_P (DECL) \ - && DECL_EXTERNAL (DECL)) - - /* If we have error_mark_node for either decl or type, just discard - the previous decl - we're in an error cascade already. */ - if (olddecl == error_mark_node || newdecl == error_mark_node) - return false; - *oldtypep = oldtype = TREE_TYPE (olddecl); - *newtypep = newtype = TREE_TYPE (newdecl); - if (oldtype == error_mark_node || newtype == error_mark_node) - return false; - - /* Two different categories of symbol altogether. This is an error - unless OLDDECL is a builtin. OLDDECL will be discarded in any case. */ - if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) - { - if (!(TREE_CODE (olddecl) == FUNCTION_DECL - && fndecl_built_in_p (olddecl) - && !C_DECL_DECLARED_BUILTIN (olddecl))) - { - auto_diagnostic_group d; - error ("%q+D redeclared as different kind of symbol", newdecl); - locate_old_decl (olddecl); - } - else if (TREE_PUBLIC (newdecl)) - warning (OPT_Wbuiltin_declaration_mismatch, - "built-in function %q+D declared as non-function", - newdecl); - else - warning (OPT_Wshadow, "declaration of %q+D shadows " - "a built-in function", newdecl); - return false; - } - - /* Enumerators have no linkage, so may only be declared once in a - given scope. */ - if (TREE_CODE (olddecl) == CONST_DECL) - { - auto_diagnostic_group d; - error ("redeclaration of enumerator %q+D", newdecl); - locate_old_decl (olddecl); - return false; - } - - bool pedwarned = false; - bool warned = false; - auto_diagnostic_group d; - - if (!comptypes (oldtype, newtype)) - { - if (TREE_CODE (olddecl) == FUNCTION_DECL - && fndecl_built_in_p (olddecl, BUILT_IN_NORMAL) - && !C_DECL_DECLARED_BUILTIN (olddecl)) - { - /* Accept "harmless" mismatches in function types such - as missing qualifiers or int vs long when they're the same - size. However, diagnose return and argument types that are - incompatible according to language rules. */ - tree mismatch_expect; - unsigned mismatch_argno; - - tree trytype = match_builtin_function_types (newtype, oldtype, - &mismatch_expect, - &mismatch_argno); - - if (trytype && comptypes (newtype, trytype)) - *oldtypep = oldtype = trytype; - else - { - /* If types don't match for a built-in, throw away the - built-in. No point in calling locate_old_decl here, it - won't print anything. */ - const char *header = header_for_builtin_fn (olddecl); - location_t loc = DECL_SOURCE_LOCATION (newdecl); - if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch, - "conflicting types for built-in function %q+D; " - "expected %qT", - newdecl, oldtype) - && header) - { - /* Suggest the right header to include as the preferred - solution rather than the spelling of the declaration. */ - rich_location richloc (line_table, loc); - maybe_add_include_fixit (&richloc, header, true); - inform (&richloc, - "%qD is declared in header %qs", olddecl, header); - } - return false; - } - - if (mismatch_expect && extra_warnings) - { - location_t newloc = DECL_SOURCE_LOCATION (newdecl); - bool warned = false; - if (mismatch_argno) - warned = warning_at (newloc, OPT_Wbuiltin_declaration_mismatch, - "mismatch in argument %u type of built-in " - "function %qD; expected %qT", - mismatch_argno, newdecl, mismatch_expect); - else - warned = warning_at (newloc, OPT_Wbuiltin_declaration_mismatch, - "mismatch in return type of built-in " - "function %qD; expected %qT", - newdecl, mismatch_expect); - const char *header = header_for_builtin_fn (olddecl); - if (warned && header) - { - rich_location richloc (line_table, newloc); - maybe_add_include_fixit (&richloc, header, true); - inform (&richloc, - "%qD is declared in header %qs", olddecl, header); - } - } - } - else if (TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_IS_UNDECLARED_BUILTIN (olddecl)) - { - /* A conflicting function declaration for a predeclared - function that isn't actually built in. Objective C uses - these. The new declaration silently overrides everything - but the volatility (i.e. noreturn) indication. See also - below. FIXME: Make Objective C use normal builtins. */ - TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); - return false; - } - /* Permit void foo (...) to match int foo (...) if the latter is - the definition and implicit int was used. See - c-torture/compile/920625-2.c. */ - else if (TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) - && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node - && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node - && C_FUNCTION_IMPLICIT_INT (newdecl) && !DECL_INITIAL (olddecl)) - { - pedwarned = pedwarn (input_location, 0, - "conflicting types for %q+D", newdecl); - /* Make sure we keep void as the return type. */ - TREE_TYPE (newdecl) = *newtypep = newtype = oldtype; - C_FUNCTION_IMPLICIT_INT (newdecl) = 0; - } - /* Permit void foo (...) to match an earlier call to foo (...) with - no declared type (thus, implicitly int). */ - else if (TREE_CODE (newdecl) == FUNCTION_DECL - && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == void_type_node - && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == integer_type_node - && C_DECL_IMPLICIT (olddecl) && !DECL_INITIAL (olddecl)) - { - pedwarned = pedwarn (input_location, 0, - "conflicting types for %q+D; have %qT", - newdecl, newtype); - /* Make sure we keep void as the return type. */ - TREE_TYPE (olddecl) = *oldtypep = oldtype = newtype; - } - else - { - int new_quals = TYPE_QUALS (newtype); - int old_quals = TYPE_QUALS (oldtype); - - if (new_quals != old_quals) - { - addr_space_t new_addr = DECODE_QUAL_ADDR_SPACE (new_quals); - addr_space_t old_addr = DECODE_QUAL_ADDR_SPACE (old_quals); - if (new_addr != old_addr) - { - if (ADDR_SPACE_GENERIC_P (new_addr)) - error ("conflicting named address spaces (generic vs %s) " - "for %q+D", - c_addr_space_name (old_addr), newdecl); - else if (ADDR_SPACE_GENERIC_P (old_addr)) - error ("conflicting named address spaces (%s vs generic) " - "for %q+D", - c_addr_space_name (new_addr), newdecl); - else - error ("conflicting named address spaces (%s vs %s) " - "for %q+D", - c_addr_space_name (new_addr), - c_addr_space_name (old_addr), - newdecl); - } - - if (CLEAR_QUAL_ADDR_SPACE (new_quals) - != CLEAR_QUAL_ADDR_SPACE (old_quals)) - error ("conflicting type qualifiers for %q+D", newdecl); - } - else - error ("conflicting types for %q+D; have %qT", newdecl, newtype); - diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype); - locate_old_decl (olddecl); - return false; - } - } - - /* Redeclaration of a type is a constraint violation (6.7.2.3p1), - but silently ignore the redeclaration if either is in a system - header. (Conflicting redeclarations were handled above.) This - is allowed for C11 if the types are the same, not just - compatible. */ - if (TREE_CODE (newdecl) == TYPE_DECL) - { - bool types_different = false; - int comptypes_result; - - comptypes_result - = comptypes_check_different_types (oldtype, newtype, &types_different); - - if (comptypes_result != 1 || types_different) - { - error ("redefinition of typedef %q+D with different type", newdecl); - locate_old_decl (olddecl); - return false; - } - - if (DECL_IN_SYSTEM_HEADER (newdecl) - || DECL_IN_SYSTEM_HEADER (olddecl) - || warning_suppressed_p (newdecl, OPT_Wpedantic) - || warning_suppressed_p (olddecl, OPT_Wpedantic)) - return true; /* Allow OLDDECL to continue in use. */ - - if (variably_modified_type_p (newtype, NULL)) - { - error ("redefinition of typedef %q+D with variably modified type", - newdecl); - locate_old_decl (olddecl); - } - else if (pedwarn_c99 (input_location, OPT_Wpedantic, - "redefinition of typedef %q+D", newdecl)) - locate_old_decl (olddecl); - - return true; - } - - /* Function declarations can either be 'static' or 'extern' (no - qualifier is equivalent to 'extern' - C99 6.2.2p5) and therefore - can never conflict with each other on account of linkage - (6.2.2p4). Multiple definitions are not allowed (6.9p3,5) but - gnu89 mode permits two definitions if one is 'extern inline' and - one is not. The non- extern-inline definition supersedes the - extern-inline definition. */ - - else if (TREE_CODE (newdecl) == FUNCTION_DECL) - { - /* If you declare a built-in function name as static, or - define the built-in with an old-style definition (so we - can't validate the argument list) the built-in definition is - overridden, but optionally warn this was a bad choice of name. */ - if (fndecl_built_in_p (olddecl) - && !C_DECL_DECLARED_BUILTIN (olddecl)) - { - if (!TREE_PUBLIC (newdecl) - || (DECL_INITIAL (newdecl) - && !prototype_p (TREE_TYPE (newdecl)))) - { - warning_at (DECL_SOURCE_LOCATION (newdecl), - OPT_Wshadow, "declaration of %qD shadows " - "a built-in function", newdecl); - /* Discard the old built-in function. */ - return false; - } - - if (!prototype_p (TREE_TYPE (newdecl))) - { - /* Set for built-ins that take no arguments. */ - bool func_void_args = false; - if (tree at = TYPE_ARG_TYPES (oldtype)) - func_void_args = VOID_TYPE_P (TREE_VALUE (at)); - - if (extra_warnings && !func_void_args) - warning_at (DECL_SOURCE_LOCATION (newdecl), - OPT_Wbuiltin_declaration_mismatch, - "declaration of built-in function %qD without " - "a prototype; expected %qT", - newdecl, TREE_TYPE (olddecl)); - } - } - - if (DECL_INITIAL (newdecl)) - { - if (DECL_INITIAL (olddecl)) - { - /* If both decls are in the same TU and the new declaration - isn't overriding an extern inline reject the new decl. - In c99, no overriding is allowed in the same translation - unit. */ - if ((!DECL_EXTERN_INLINE (olddecl) - || DECL_EXTERN_INLINE (newdecl) - || (!flag_gnu89_inline - && (!DECL_DECLARED_INLINE_P (olddecl) - || !lookup_attribute ("gnu_inline", - DECL_ATTRIBUTES (olddecl))) - && (!DECL_DECLARED_INLINE_P (newdecl) - || !lookup_attribute ("gnu_inline", - DECL_ATTRIBUTES (newdecl)))) - ) - && same_translation_unit_p (newdecl, olddecl)) - { - auto_diagnostic_group d; - error ("redefinition of %q+D", newdecl); - locate_old_decl (olddecl); - return false; - } - } - } - /* If we have a prototype after an old-style function definition, - the argument types must be checked specially. */ - else if (DECL_INITIAL (olddecl) - && !prototype_p (oldtype) && prototype_p (newtype) - && TYPE_ACTUAL_ARG_TYPES (oldtype)) - { - auto_diagnostic_group d; - if (!validate_proto_after_old_defn (newdecl, newtype, oldtype)) - { - locate_old_decl (olddecl); - return false; - } - } - /* A non-static declaration (even an "extern") followed by a - static declaration is undefined behavior per C99 6.2.2p3-5,7. - The same is true for a static forward declaration at block - scope followed by a non-static declaration/definition at file - scope. Static followed by non-static at the same scope is - not undefined behavior, and is the most convenient way to get - some effects (see e.g. what unwind-dw2-fde-glibc.c does to - the definition of _Unwind_Find_FDE in unwind-dw2-fde.c), but - we do diagnose it if -Wtraditional. */ - if (TREE_PUBLIC (olddecl) && !TREE_PUBLIC (newdecl)) - { - /* Two exceptions to the rule. If olddecl is an extern - inline, or a predeclared function that isn't actually - built in, newdecl silently overrides olddecl. The latter - occur only in Objective C; see also above. (FIXME: Make - Objective C use normal builtins.) */ - if (!DECL_IS_UNDECLARED_BUILTIN (olddecl) - && !DECL_EXTERN_INLINE (olddecl)) - { - auto_diagnostic_group d; - error ("static declaration of %q+D follows " - "non-static declaration", newdecl); - locate_old_decl (olddecl); - } - return false; - } - else if (TREE_PUBLIC (newdecl) && !TREE_PUBLIC (olddecl)) - { - if (DECL_CONTEXT (olddecl)) - { - auto_diagnostic_group d; - error ("non-static declaration of %q+D follows " - "static declaration", newdecl); - locate_old_decl (olddecl); - return false; - } - else if (warn_traditional) - { - warned |= warning (OPT_Wtraditional, - "non-static declaration of %q+D " - "follows static declaration", newdecl); - } - } - - /* Make sure gnu_inline attribute is either not present, or - present on all inline decls. */ - if (DECL_DECLARED_INLINE_P (olddecl) - && DECL_DECLARED_INLINE_P (newdecl)) - { - bool newa = lookup_attribute ("gnu_inline", - DECL_ATTRIBUTES (newdecl)) != NULL; - bool olda = lookup_attribute ("gnu_inline", - DECL_ATTRIBUTES (olddecl)) != NULL; - if (newa != olda) - { - auto_diagnostic_group d; - error_at (input_location, "% attribute present on %q+D", - newa ? newdecl : olddecl); - error_at (DECL_SOURCE_LOCATION (newa ? olddecl : newdecl), - "but not here"); - } - } - } - else if (VAR_P (newdecl)) - { - /* Only variables can be thread-local, and all declarations must - agree on this property. */ - if (C_DECL_THREADPRIVATE_P (olddecl) && !DECL_THREAD_LOCAL_P (newdecl)) - { - /* Nothing to check. Since OLDDECL is marked threadprivate - and NEWDECL does not have a thread-local attribute, we - will merge the threadprivate attribute into NEWDECL. */ - ; - } - else if (DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl)) - { - auto_diagnostic_group d; - if (DECL_THREAD_LOCAL_P (newdecl)) - error ("thread-local declaration of %q+D follows " - "non-thread-local declaration", newdecl); - else - error ("non-thread-local declaration of %q+D follows " - "thread-local declaration", newdecl); - - locate_old_decl (olddecl); - return false; - } - - /* Multiple initialized definitions are not allowed (6.9p3,5). */ - if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl)) - { - auto_diagnostic_group d; - error ("redefinition of %q+D", newdecl); - locate_old_decl (olddecl); - return false; - } - - /* Objects declared at file scope: if the first declaration had - external linkage (even if it was an external reference) the - second must have external linkage as well, or the behavior is - undefined. If the first declaration had internal linkage, then - the second must too, or else be an external reference (in which - case the composite declaration still has internal linkage). - As for function declarations, we warn about the static-then- - extern case only for -Wtraditional. See generally 6.2.2p3-5,7. */ - if (DECL_FILE_SCOPE_P (newdecl) - && TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl)) - { - if (DECL_EXTERNAL (newdecl)) - { - if (!DECL_FILE_SCOPE_P (olddecl)) - { - auto_diagnostic_group d; - error ("extern declaration of %q+D follows " - "declaration with no linkage", newdecl); - locate_old_decl (olddecl); - return false; - } - else if (warn_traditional) - { - warned |= warning (OPT_Wtraditional, - "non-static declaration of %q+D " - "follows static declaration", newdecl); - } - } - else - { - auto_diagnostic_group d; - if (TREE_PUBLIC (newdecl)) - error ("non-static declaration of %q+D follows " - "static declaration", newdecl); - else - error ("static declaration of %q+D follows " - "non-static declaration", newdecl); - - locate_old_decl (olddecl); - return false; - } - } - /* Two objects with the same name declared at the same block - scope must both be external references (6.7p3). */ - else if (!DECL_FILE_SCOPE_P (newdecl)) - { - if (DECL_EXTERNAL (newdecl)) - { - /* Extern with initializer at block scope, which will - already have received an error. */ - } - else if (DECL_EXTERNAL (olddecl)) - { - auto_diagnostic_group d; - error ("declaration of %q+D with no linkage follows " - "extern declaration", newdecl); - locate_old_decl (olddecl); - } - else - { - auto_diagnostic_group d; - error ("redeclaration of %q+D with no linkage", newdecl); - locate_old_decl (olddecl); - } - - return false; - } - - /* C++ does not permit a decl to appear multiple times at file - scope. */ - if (warn_cxx_compat - && DECL_FILE_SCOPE_P (newdecl) - && !DECL_EXTERNAL (newdecl) - && !DECL_EXTERNAL (olddecl)) - warned |= warning_at (DECL_SOURCE_LOCATION (newdecl), - OPT_Wc___compat, - ("duplicate declaration of %qD is " - "invalid in C++"), - newdecl); - } - - /* warnings */ - /* All decls must agree on a visibility. */ - if (CODE_CONTAINS_STRUCT (TREE_CODE (newdecl), TS_DECL_WITH_VIS) - && DECL_VISIBILITY_SPECIFIED (newdecl) && DECL_VISIBILITY_SPECIFIED (olddecl) - && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) - { - warned |= warning (0, "redeclaration of %q+D with different visibility " - "(old visibility preserved)", newdecl); - } - - if (TREE_CODE (newdecl) == FUNCTION_DECL) - warned |= diagnose_mismatched_attributes (olddecl, newdecl); - else /* PARM_DECL, VAR_DECL */ - { - /* Redeclaration of a parameter is a constraint violation (this is - not explicitly stated, but follows from C99 6.7p3 [no more than - one declaration of the same identifier with no linkage in the - same scope, except type tags] and 6.2.2p6 [parameters have no - linkage]). We must check for a forward parameter declaration, - indicated by TREE_ASM_WRITTEN on the old declaration - this is - an extension, the mandatory diagnostic for which is handled by - mark_forward_parm_decls. */ - - if (TREE_CODE (newdecl) == PARM_DECL - && (!TREE_ASM_WRITTEN (olddecl) || TREE_ASM_WRITTEN (newdecl))) - { - auto_diagnostic_group d; - error ("redefinition of parameter %q+D", newdecl); - locate_old_decl (olddecl); - return false; - } - } - - /* Optional warning for completely redundant decls. */ - if (!warned && !pedwarned - && warn_redundant_decls - /* Don't warn about a function declaration followed by a - definition. */ - && !(TREE_CODE (newdecl) == FUNCTION_DECL - && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl)) - /* Don't warn about redundant redeclarations of builtins. */ - && !(TREE_CODE (newdecl) == FUNCTION_DECL - && !fndecl_built_in_p (newdecl) - && fndecl_built_in_p (olddecl) - && !C_DECL_DECLARED_BUILTIN (olddecl)) - /* Don't warn about an extern followed by a definition. */ - && !(DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl)) - /* Don't warn about forward parameter decls. */ - && !(TREE_CODE (newdecl) == PARM_DECL - && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)) - /* Don't warn about a variable definition following a declaration. */ - && !(VAR_P (newdecl) - && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl))) - { - warned = warning (OPT_Wredundant_decls, "redundant redeclaration of %q+D", - newdecl); - } - - /* Report location of previous decl/defn. */ - if (warned || pedwarned) - locate_old_decl (olddecl); - -#undef DECL_EXTERN_INLINE - - return retval; -} - -/* Subroutine of duplicate_decls. NEWDECL has been found to be - consistent with OLDDECL, but carries new information. Merge the - new information into OLDDECL. This function issues no - diagnostics. */ - -static void -merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) -{ - bool new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL - && DECL_INITIAL (newdecl) != NULL_TREE); - bool new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL - && prototype_p (TREE_TYPE (newdecl))); - bool old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL - && prototype_p (TREE_TYPE (olddecl))); - - /* For real parm decl following a forward decl, rechain the old decl - in its new location and clear TREE_ASM_WRITTEN (it's not a - forward decl anymore). */ - if (TREE_CODE (newdecl) == PARM_DECL - && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)) - { - struct c_binding *b, **here; - - for (here = ¤t_scope->bindings; *here; here = &(*here)->prev) - if ((*here)->decl == olddecl) - goto found; - gcc_unreachable (); - - found: - b = *here; - *here = b->prev; - b->prev = current_scope->bindings; - current_scope->bindings = b; - - TREE_ASM_WRITTEN (olddecl) = 0; - } - - DECL_ATTRIBUTES (newdecl) - = targetm.merge_decl_attributes (olddecl, newdecl); - - /* For typedefs use the old type, as the new type's DECL_NAME points - at newdecl, which will be ggc_freed. */ - if (TREE_CODE (newdecl) == TYPE_DECL) - { - /* But NEWTYPE might have an attribute, honor that. */ - tree tem = newtype; - newtype = oldtype; - - if (TYPE_USER_ALIGN (tem)) - { - if (TYPE_ALIGN (tem) > TYPE_ALIGN (newtype)) - SET_TYPE_ALIGN (newtype, TYPE_ALIGN (tem)); - TYPE_USER_ALIGN (newtype) = true; - } - - /* And remove the new type from the variants list. */ - if (TYPE_NAME (TREE_TYPE (newdecl)) == newdecl) - { - tree remove = TREE_TYPE (newdecl); - if (TYPE_MAIN_VARIANT (remove) == remove) - { - gcc_assert (TYPE_NEXT_VARIANT (remove) == NULL_TREE); - /* If remove is the main variant, no need to remove that - from the list. One of the DECL_ORIGINAL_TYPE - variants, e.g. created for aligned attribute, might still - refer to the newdecl TYPE_DECL though, so remove that one - in that case. */ - if (DECL_ORIGINAL_TYPE (newdecl) - && DECL_ORIGINAL_TYPE (newdecl) != remove) - for (tree t = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (newdecl)); - t; t = TYPE_MAIN_VARIANT (t)) - if (TYPE_NAME (TYPE_NEXT_VARIANT (t)) == newdecl) - { - TYPE_NEXT_VARIANT (t) - = TYPE_NEXT_VARIANT (TYPE_NEXT_VARIANT (t)); - break; - } - } - else - for (tree t = TYPE_MAIN_VARIANT (remove); ; - t = TYPE_NEXT_VARIANT (t)) - if (TYPE_NEXT_VARIANT (t) == remove) - { - TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (remove); - break; - } - } - } - - /* Merge the data types specified in the two decls. */ - TREE_TYPE (newdecl) - = TREE_TYPE (olddecl) - = composite_type (newtype, oldtype); - - /* Lay the type out, unless already done. */ - if (!comptypes (oldtype, TREE_TYPE (newdecl))) - { - if (TREE_TYPE (newdecl) != error_mark_node) - layout_type (TREE_TYPE (newdecl)); - if (TREE_CODE (newdecl) != FUNCTION_DECL - && TREE_CODE (newdecl) != TYPE_DECL - && TREE_CODE (newdecl) != CONST_DECL) - layout_decl (newdecl, 0); - } - else - { - /* Since the type is OLDDECL's, make OLDDECL's size go with. */ - DECL_SIZE (newdecl) = DECL_SIZE (olddecl); - DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl); - SET_DECL_MODE (newdecl, DECL_MODE (olddecl)); - if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) - { - SET_DECL_ALIGN (newdecl, DECL_ALIGN (olddecl)); - DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl); - } - else if (DECL_ALIGN (olddecl) == DECL_ALIGN (newdecl) - && DECL_USER_ALIGN (olddecl) != DECL_USER_ALIGN (newdecl)) - DECL_USER_ALIGN (newdecl) = 1; - if (DECL_WARN_IF_NOT_ALIGN (olddecl) - > DECL_WARN_IF_NOT_ALIGN (newdecl)) - SET_DECL_WARN_IF_NOT_ALIGN (newdecl, - DECL_WARN_IF_NOT_ALIGN (olddecl)); - } - - /* Keep the old rtl since we can safely use it. */ - if (HAS_RTL_P (olddecl)) - COPY_DECL_RTL (olddecl, newdecl); - - /* Merge the type qualifiers. */ - if (TREE_READONLY (newdecl)) - TREE_READONLY (olddecl) = 1; - - if (TREE_THIS_VOLATILE (newdecl)) - TREE_THIS_VOLATILE (olddecl) = 1; - - /* Merge deprecatedness. */ - if (TREE_DEPRECATED (newdecl)) - TREE_DEPRECATED (olddecl) = 1; - - /* Merge unavailability. */ - if (TREE_UNAVAILABLE (newdecl)) - TREE_UNAVAILABLE (olddecl) = 1; - - /* If a decl is in a system header and the other isn't, keep the one on the - system header. Otherwise, keep source location of definition rather than - declaration and of prototype rather than non-prototype unless that - prototype is built-in. */ - if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS) - && DECL_IN_SYSTEM_HEADER (olddecl) - && !DECL_IN_SYSTEM_HEADER (newdecl) ) - DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); - else if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS) - && DECL_IN_SYSTEM_HEADER (newdecl) - && !DECL_IN_SYSTEM_HEADER (olddecl)) - DECL_SOURCE_LOCATION (olddecl) = DECL_SOURCE_LOCATION (newdecl); - else if ((DECL_INITIAL (newdecl) == NULL_TREE - && DECL_INITIAL (olddecl) != NULL_TREE) - || (old_is_prototype && !new_is_prototype - && !C_DECL_BUILTIN_PROTOTYPE (olddecl))) - DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); - - /* Merge the initialization information. */ - if (DECL_INITIAL (newdecl) == NULL_TREE) - DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); - - /* Merge the threadprivate attribute. */ - if (VAR_P (olddecl) && C_DECL_THREADPRIVATE_P (olddecl)) - C_DECL_THREADPRIVATE_P (newdecl) = 1; - - if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS)) - { - /* Copy the assembler name. - Currently, it can only be defined in the prototype. */ - COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); - - /* Use visibility of whichever declaration had it specified */ - if (DECL_VISIBILITY_SPECIFIED (olddecl)) - { - DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); - DECL_VISIBILITY_SPECIFIED (newdecl) = 1; - } - - if (TREE_CODE (newdecl) == FUNCTION_DECL) - { - DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); - DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); - DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl); - DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) - |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); - TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); - DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl); - if (DECL_IS_OPERATOR_NEW_P (olddecl)) - DECL_SET_IS_OPERATOR_NEW (newdecl, true); - if (DECL_IS_OPERATOR_DELETE_P (olddecl)) - DECL_SET_IS_OPERATOR_DELETE (newdecl, true); - TREE_READONLY (newdecl) |= TREE_READONLY (olddecl); - DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl); - DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl); - } - - /* Merge the storage class information. */ - merge_weak (newdecl, olddecl); - - /* For functions, static overrides non-static. */ - if (TREE_CODE (newdecl) == FUNCTION_DECL) - { - TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl); - /* This is since we don't automatically - copy the attributes of NEWDECL into OLDDECL. */ - TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); - /* If this clears `static', clear it in the identifier too. */ - if (!TREE_PUBLIC (olddecl)) - TREE_PUBLIC (DECL_NAME (olddecl)) = 0; - } - } - - /* In c99, 'extern' declaration before (or after) 'inline' means this - function is not DECL_EXTERNAL, unless 'gnu_inline' attribute - is present. */ - if (TREE_CODE (newdecl) == FUNCTION_DECL - && !flag_gnu89_inline - && (DECL_DECLARED_INLINE_P (newdecl) - || DECL_DECLARED_INLINE_P (olddecl)) - && (!DECL_DECLARED_INLINE_P (newdecl) - || !DECL_DECLARED_INLINE_P (olddecl) - || !DECL_EXTERNAL (olddecl)) - && DECL_EXTERNAL (newdecl) - && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (newdecl)) - && !current_function_decl) - DECL_EXTERNAL (newdecl) = 0; - - /* An inline definition following a static declaration is not - DECL_EXTERNAL. */ - if (new_is_definition - && (DECL_DECLARED_INLINE_P (newdecl) - || DECL_DECLARED_INLINE_P (olddecl)) - && !TREE_PUBLIC (olddecl)) - DECL_EXTERNAL (newdecl) = 0; - - if (DECL_EXTERNAL (newdecl)) - { - TREE_STATIC (newdecl) = TREE_STATIC (olddecl); - DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl); - - /* An extern decl does not override previous storage class. */ - TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); - if (!DECL_EXTERNAL (newdecl)) - { - DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl); - DECL_COMMON (newdecl) = DECL_COMMON (olddecl); - } - } - else - { - TREE_STATIC (olddecl) = TREE_STATIC (newdecl); - TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); - } - - if (TREE_CODE (newdecl) == FUNCTION_DECL) - { - /* If we're redefining a function previously defined as extern - inline, make sure we emit debug info for the inline before we - throw it away, in case it was inlined into a function that - hasn't been written out yet. */ - if (new_is_definition && DECL_INITIAL (olddecl)) - /* The new defn must not be inline. */ - DECL_UNINLINABLE (newdecl) = 1; - else - { - /* If either decl says `inline', this fn is inline, unless - its definition was passed already. */ - if (DECL_DECLARED_INLINE_P (newdecl) - || DECL_DECLARED_INLINE_P (olddecl)) - DECL_DECLARED_INLINE_P (newdecl) = 1; - - DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl) - = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)); - - DECL_DISREGARD_INLINE_LIMITS (newdecl) - = DECL_DISREGARD_INLINE_LIMITS (olddecl) - = (DECL_DISREGARD_INLINE_LIMITS (newdecl) - || DECL_DISREGARD_INLINE_LIMITS (olddecl)); - } - - if (fndecl_built_in_p (olddecl)) - { - /* If redeclaring a builtin function, it stays built in. - But it gets tagged as having been declared. */ - copy_decl_built_in_function (newdecl, olddecl); - C_DECL_DECLARED_BUILTIN (newdecl) = 1; - if (new_is_prototype) - { - C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0; - if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL) - { - enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl); - switch (fncode) - { - /* If a compatible prototype of these builtin functions - is seen, assume the runtime implements it with the - expected semantics. */ - case BUILT_IN_STPCPY: - if (builtin_decl_explicit_p (fncode)) - set_builtin_decl_implicit_p (fncode, true); - break; - default: - if (builtin_decl_explicit_p (fncode)) - set_builtin_decl_declared_p (fncode, true); - break; - } - - copy_attributes_to_builtin (newdecl); - } - } - else - C_DECL_BUILTIN_PROTOTYPE (newdecl) - = C_DECL_BUILTIN_PROTOTYPE (olddecl); - } - - /* Preserve function specific target and optimization options */ - if (DECL_FUNCTION_SPECIFIC_TARGET (olddecl) - && !DECL_FUNCTION_SPECIFIC_TARGET (newdecl)) - DECL_FUNCTION_SPECIFIC_TARGET (newdecl) - = DECL_FUNCTION_SPECIFIC_TARGET (olddecl); - - if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl) - && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl)) - DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl) - = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl); - - /* Also preserve various other info from the definition. */ - if (!new_is_definition) - { - tree t; - DECL_RESULT (newdecl) = DECL_RESULT (olddecl); - DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); - DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl); - DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl); - DECL_ARGUMENTS (newdecl) = copy_list (DECL_ARGUMENTS (olddecl)); - for (t = DECL_ARGUMENTS (newdecl); t ; t = DECL_CHAIN (t)) - DECL_CONTEXT (t) = newdecl; - - /* See if we've got a function to instantiate from. */ - if (DECL_SAVED_TREE (olddecl)) - DECL_ABSTRACT_ORIGIN (newdecl) - = DECL_ABSTRACT_ORIGIN (olddecl); - } - } - - /* Merge the USED information. */ - if (TREE_USED (olddecl)) - TREE_USED (newdecl) = 1; - else if (TREE_USED (newdecl)) - TREE_USED (olddecl) = 1; - if (VAR_P (olddecl) || TREE_CODE (olddecl) == PARM_DECL) - DECL_READ_P (newdecl) |= DECL_READ_P (olddecl); - if (DECL_PRESERVE_P (olddecl)) - DECL_PRESERVE_P (newdecl) = 1; - else if (DECL_PRESERVE_P (newdecl)) - DECL_PRESERVE_P (olddecl) = 1; - - /* Merge DECL_COMMON */ - if (VAR_P (olddecl) && VAR_P (newdecl) - && !lookup_attribute ("common", DECL_ATTRIBUTES (newdecl)) - && !lookup_attribute ("nocommon", DECL_ATTRIBUTES (newdecl))) - DECL_COMMON (newdecl) = DECL_COMMON (newdecl) && DECL_COMMON (olddecl); - - /* Copy most of the decl-specific fields of NEWDECL into OLDDECL. - But preserve OLDDECL's DECL_UID, DECL_CONTEXT and - DECL_ARGUMENTS (if appropriate). */ - { - unsigned olddecl_uid = DECL_UID (olddecl); - tree olddecl_context = DECL_CONTEXT (olddecl); - tree olddecl_arguments = NULL; - if (TREE_CODE (olddecl) == FUNCTION_DECL) - olddecl_arguments = DECL_ARGUMENTS (olddecl); - - memcpy ((char *) olddecl + sizeof (struct tree_common), - (char *) newdecl + sizeof (struct tree_common), - sizeof (struct tree_decl_common) - sizeof (struct tree_common)); - DECL_USER_ALIGN (olddecl) = DECL_USER_ALIGN (newdecl); - switch (TREE_CODE (olddecl)) - { - case FUNCTION_DECL: - case VAR_DECL: - { - struct symtab_node *snode = olddecl->decl_with_vis.symtab_node; - - memcpy ((char *) olddecl + sizeof (struct tree_decl_common), - (char *) newdecl + sizeof (struct tree_decl_common), - tree_code_size (TREE_CODE (olddecl)) - sizeof (struct tree_decl_common)); - olddecl->decl_with_vis.symtab_node = snode; - - if ((DECL_EXTERNAL (olddecl) - || TREE_PUBLIC (olddecl) - || TREE_STATIC (olddecl)) - && DECL_SECTION_NAME (newdecl) != NULL) - set_decl_section_name (olddecl, newdecl); - - /* This isn't quite correct for something like - int __thread x attribute ((tls_model ("local-exec"))); - extern int __thread x; - as we'll lose the "local-exec" model. */ - if (VAR_P (olddecl) && DECL_THREAD_LOCAL_P (newdecl)) - set_decl_tls_model (olddecl, DECL_TLS_MODEL (newdecl)); - break; - } - - case FIELD_DECL: - case PARM_DECL: - case LABEL_DECL: - case RESULT_DECL: - case CONST_DECL: - case TYPE_DECL: - memcpy ((char *) olddecl + sizeof (struct tree_decl_common), - (char *) newdecl + sizeof (struct tree_decl_common), - tree_code_size (TREE_CODE (olddecl)) - sizeof (struct tree_decl_common)); - break; - - default: - - memcpy ((char *) olddecl + sizeof (struct tree_decl_common), - (char *) newdecl + sizeof (struct tree_decl_common), - sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common)); - } - DECL_UID (olddecl) = olddecl_uid; - DECL_CONTEXT (olddecl) = olddecl_context; - if (TREE_CODE (olddecl) == FUNCTION_DECL) - DECL_ARGUMENTS (olddecl) = olddecl_arguments; - } - - /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl - so that encode_section_info has a chance to look at the new decl - flags and attributes. */ - if (DECL_RTL_SET_P (olddecl) - && (TREE_CODE (olddecl) == FUNCTION_DECL - || (VAR_P (olddecl) && TREE_STATIC (olddecl)))) - make_decl_rtl (olddecl); -} - -/* Handle when a new declaration NEWDECL has the same name as an old - one OLDDECL in the same binding contour. Prints an error message - if appropriate. - - If safely possible, alter OLDDECL to look like NEWDECL, and return - true. Otherwise, return false. */ - -static bool -duplicate_decls (tree newdecl, tree olddecl) -{ - tree newtype = NULL, oldtype = NULL; - - if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype)) - { - /* Avoid `unused variable' and other warnings for OLDDECL. */ - suppress_warning (olddecl, OPT_Wunused); - /* If the types are completely different, poison them both with - error_mark_node. */ - if (TREE_CODE (TREE_TYPE (newdecl)) != TREE_CODE (TREE_TYPE (olddecl)) - && olddecl != error_mark_node - && seen_error ()) - { - if (TREE_CODE (olddecl) != FUNCTION_DECL) - TREE_TYPE (olddecl) = error_mark_node; - if (TREE_CODE (newdecl) != FUNCTION_DECL) - TREE_TYPE (newdecl) = error_mark_node; - } - return false; - } - - merge_decls (newdecl, olddecl, newtype, oldtype); - - /* The NEWDECL will no longer be needed. - - Before releasing the node, be sure to remove function from symbol - table that might have been inserted there to record comdat group. - Be sure to however do not free DECL_STRUCT_FUNCTION because this - structure is shared in between NEWDECL and OLDECL. */ - if (TREE_CODE (newdecl) == FUNCTION_DECL) - DECL_STRUCT_FUNCTION (newdecl) = NULL; - if (VAR_OR_FUNCTION_DECL_P (newdecl)) - { - struct symtab_node *snode = symtab_node::get (newdecl); - if (snode) - snode->remove (); - } - ggc_free (newdecl); - return true; -} - - -/* Check whether decl-node NEW_DECL shadows an existing declaration. */ -static void -warn_if_shadowing (tree new_decl) -{ - struct c_binding *b; - - /* Shadow warnings wanted? */ - if (!(warn_shadow - || warn_shadow_local - || warn_shadow_compatible_local) - /* No shadow warnings for internally generated vars. */ - || DECL_IS_UNDECLARED_BUILTIN (new_decl)) - return; - - /* Is anything being shadowed? Invisible decls do not count. */ - for (b = I_SYMBOL_BINDING (DECL_NAME (new_decl)); b; b = b->shadowed) - if (b->decl && b->decl != new_decl && !b->invisible - && (b->decl == error_mark_node - || diagnostic_report_warnings_p (global_dc, - DECL_SOURCE_LOCATION (b->decl)))) - { - tree old_decl = b->decl; - - if (old_decl == error_mark_node) - { - warning (OPT_Wshadow, "declaration of %q+D shadows previous " - "non-variable", new_decl); - break; - } - - bool warned = false; - auto_diagnostic_group d; - if (TREE_CODE (old_decl) == PARM_DECL) - { - enum opt_code warning_code; - - /* If '-Wshadow=compatible-local' is specified without other - -Wshadow= flags, we will warn only when the types of the - shadowing variable (i.e. new_decl) and the shadowed variable - (old_decl) are compatible. */ - if (warn_shadow) - warning_code = OPT_Wshadow; - else if (comptypes (TREE_TYPE (old_decl), TREE_TYPE (new_decl))) - warning_code = OPT_Wshadow_compatible_local; - else - warning_code = OPT_Wshadow_local; - warned = warning_at (DECL_SOURCE_LOCATION (new_decl), warning_code, - "declaration of %qD shadows a parameter", - new_decl); - } - else if (DECL_FILE_SCOPE_P (old_decl)) - { - /* Do not warn if a variable shadows a function, unless - the variable is a function or a pointer-to-function. */ - if (TREE_CODE (old_decl) == FUNCTION_DECL - && TREE_CODE (new_decl) != FUNCTION_DECL - && !FUNCTION_POINTER_TYPE_P (TREE_TYPE (new_decl))) - continue; - - warned = warning_at (DECL_SOURCE_LOCATION (new_decl), OPT_Wshadow, - "declaration of %qD shadows a global " - "declaration", - new_decl); - } - else if (TREE_CODE (old_decl) == FUNCTION_DECL - && fndecl_built_in_p (old_decl)) - { - warning (OPT_Wshadow, "declaration of %q+D shadows " - "a built-in function", new_decl); - break; - } - else - { - enum opt_code warning_code; - - /* If '-Wshadow=compatible-local' is specified without other - -Wshadow= flags, we will warn only when the types of the - shadowing variable (i.e. new_decl) and the shadowed variable - (old_decl) are compatible. */ - if (warn_shadow) - warning_code = OPT_Wshadow; - else if (comptypes (TREE_TYPE (old_decl), TREE_TYPE (new_decl))) - warning_code = OPT_Wshadow_compatible_local; - else - warning_code = OPT_Wshadow_local; - warned = warning_at (DECL_SOURCE_LOCATION (new_decl), warning_code, - "declaration of %qD shadows a previous local", - new_decl); - } - - if (warned) - inform (DECL_SOURCE_LOCATION (old_decl), - "shadowed declaration is here"); - - break; - } -} - -/* Record a decl-node X as belonging to the current lexical scope. - Check for errors (such as an incompatible declaration for the same - name already seen in the same scope). - - Returns either X or an old decl for the same name. - If an old decl is returned, it may have been smashed - to agree with what X says. */ - -tree -pushdecl (tree x) -{ - tree name = DECL_NAME (x); - struct c_scope *scope = current_scope; - struct c_binding *b; - bool nested = false; - location_t locus = DECL_SOURCE_LOCATION (x); - - /* Must set DECL_CONTEXT for everything not at file scope or - DECL_FILE_SCOPE_P won't work. Local externs don't count - unless they have initializers (which generate code). */ - if (current_function_decl - && (!VAR_OR_FUNCTION_DECL_P (x) - || DECL_INITIAL (x) || !TREE_PUBLIC (x))) - DECL_CONTEXT (x) = current_function_decl; - - /* Anonymous decls are just inserted in the scope. */ - if (!name) - { - bind (name, x, scope, /*invisible=*/false, /*nested=*/false, - locus); - return x; - } - - /* First, see if there is another declaration with the same name in - the current scope. If there is, duplicate_decls may do all the - work for us. If duplicate_decls returns false, that indicates - two incompatible decls in the same scope; we are to silently - replace the old one (duplicate_decls has issued all appropriate - diagnostics). In particular, we should not consider possible - duplicates in the external scope, or shadowing. */ - b = I_SYMBOL_BINDING (name); - if (b && B_IN_SCOPE (b, scope)) - { - struct c_binding *b_ext, *b_use; - tree type = TREE_TYPE (x); - tree visdecl = b->decl; - tree vistype = TREE_TYPE (visdecl); - if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE - && COMPLETE_TYPE_P (TREE_TYPE (x))) - b->inner_comp = false; - b_use = b; - b_ext = b; - /* If this is an external linkage declaration, we should check - for compatibility with the type in the external scope before - setting the type at this scope based on the visible - information only. */ - if (TREE_PUBLIC (x) && TREE_PUBLIC (visdecl)) - { - while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext)) - b_ext = b_ext->shadowed; - if (b_ext) - { - b_use = b_ext; - if (b_use->u.type) - TREE_TYPE (b_use->decl) = b_use->u.type; - } - } - if (duplicate_decls (x, b_use->decl)) - { - if (b_use != b) - { - /* Save the updated type in the external scope and - restore the proper type for this scope. */ - tree thistype; - if (comptypes (vistype, type)) - thistype = composite_type (vistype, type); - else - thistype = TREE_TYPE (b_use->decl); - b_use->u.type = TREE_TYPE (b_use->decl); - if (TREE_CODE (b_use->decl) == FUNCTION_DECL - && fndecl_built_in_p (b_use->decl)) - thistype - = build_type_attribute_variant (thistype, - TYPE_ATTRIBUTES - (b_use->u.type)); - TREE_TYPE (b_use->decl) = thistype; - } - return b_use->decl; - } - else - goto skip_external_and_shadow_checks; - } - - /* All declarations with external linkage, and all external - references, go in the external scope, no matter what scope is - current. However, the binding in that scope is ignored for - purposes of normal name lookup. A separate binding structure is - created in the requested scope; this governs the normal - visibility of the symbol. - - The binding in the externals scope is used exclusively for - detecting duplicate declarations of the same object, no matter - what scope they are in; this is what we do here. (C99 6.2.7p2: - All declarations that refer to the same object or function shall - have compatible type; otherwise, the behavior is undefined.) - However, in Objective-C, we also want to detect declarations - conflicting with those of the basic types. */ - if ((DECL_EXTERNAL (x) || scope == file_scope) - && (VAR_OR_FUNCTION_DECL_P (x) || c_dialect_objc ())) - { - tree type = TREE_TYPE (x); - tree vistype = NULL_TREE; - tree visdecl = NULL_TREE; - bool type_saved = false; - if (b && !B_IN_EXTERNAL_SCOPE (b) - && VAR_OR_FUNCTION_DECL_P (b->decl) - && DECL_FILE_SCOPE_P (b->decl)) - { - visdecl = b->decl; - vistype = TREE_TYPE (visdecl); - } - if (scope != file_scope - && !DECL_IN_SYSTEM_HEADER (x)) - warning_at (locus, OPT_Wnested_externs, - "nested extern declaration of %qD", x); - - while (b && !B_IN_EXTERNAL_SCOPE (b)) - { - /* If this decl might be modified, save its type. This is - done here rather than when the decl is first bound - because the type may change after first binding, through - being completed or through attributes being added. If we - encounter multiple such decls, only the first should have - its type saved; the others will already have had their - proper types saved and the types will not have changed as - their scopes will not have been re-entered. */ - if (DECL_P (b->decl) && DECL_FILE_SCOPE_P (b->decl) && !type_saved) - { - b->u.type = TREE_TYPE (b->decl); - type_saved = true; - } - if (B_IN_FILE_SCOPE (b) - && VAR_P (b->decl) - && TREE_STATIC (b->decl) - && TREE_CODE (TREE_TYPE (b->decl)) == ARRAY_TYPE - && !TYPE_DOMAIN (TREE_TYPE (b->decl)) - && TREE_CODE (type) == ARRAY_TYPE - && TYPE_DOMAIN (type) - && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) - && !integer_zerop (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))) - { - /* Array type completed in inner scope, which should be - diagnosed if the completion does not have size 1 and - it does not get completed in the file scope. */ - b->inner_comp = true; - } - b = b->shadowed; - } - - /* If a matching external declaration has been found, set its - type to the composite of all the types of that declaration. - After the consistency checks, it will be reset to the - composite of the visible types only. */ - if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl)) - && b->u.type) - TREE_TYPE (b->decl) = b->u.type; - - /* The point of the same_translation_unit_p check here is, - we want to detect a duplicate decl for a construct like - foo() { extern bar(); } ... static bar(); but not if - they are in different translation units. In any case, - the static does not go in the externals scope. */ - if (b - && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl)) - && duplicate_decls (x, b->decl)) - { - tree thistype; - if (vistype) - { - if (comptypes (vistype, type)) - thistype = composite_type (vistype, type); - else - thistype = TREE_TYPE (b->decl); - } - else - thistype = type; - b->u.type = TREE_TYPE (b->decl); - /* Propagate the type attributes to the decl. */ - thistype - = build_type_attribute_variant (thistype, - TYPE_ATTRIBUTES (b->u.type)); - TREE_TYPE (b->decl) = thistype; - bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true, - locus); - return b->decl; - } - else if (TREE_PUBLIC (x)) - { - if (visdecl && !b && duplicate_decls (x, visdecl)) - { - /* An external declaration at block scope referring to a - visible entity with internal linkage. The composite - type will already be correct for this scope, so we - just need to fall through to make the declaration in - this scope. */ - nested = true; - x = visdecl; - } - else - { - bind (name, x, external_scope, /*invisible=*/true, - /*nested=*/false, locus); - nested = true; - } - } - } - - if (TREE_CODE (x) != PARM_DECL) - warn_if_shadowing (x); - - skip_external_and_shadow_checks: - if (TREE_CODE (x) == TYPE_DECL) - { - /* So this is a typedef, set its underlying type. */ - set_underlying_type (x); - - /* If X is a typedef defined in the current function, record it - for the purpose of implementing the -Wunused-local-typedefs - warning. */ - record_locally_defined_typedef (x); - } - - bind (name, x, scope, /*invisible=*/false, nested, locus); - - /* If x's type is incomplete because it's based on a - structure or union which has not yet been fully declared, - attach it to that structure or union type, so we can go - back and complete the variable declaration later, if the - structure or union gets fully declared. - - If the input is erroneous, we can have error_mark in the type - slot (e.g. "f(void a, ...)") - that doesn't count as an - incomplete type. */ - if (TREE_TYPE (x) != error_mark_node - && !COMPLETE_TYPE_P (TREE_TYPE (x))) - { - tree element = TREE_TYPE (x); - - while (TREE_CODE (element) == ARRAY_TYPE) - element = TREE_TYPE (element); - element = TYPE_MAIN_VARIANT (element); - - if ((RECORD_OR_UNION_TYPE_P (element) - || TREE_CODE (element) == ENUMERAL_TYPE) - && (TREE_CODE (x) != TYPE_DECL - || TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE) - && !COMPLETE_TYPE_P (element)) - C_TYPE_INCOMPLETE_VARS (element) - = tree_cons (NULL_TREE, x, C_TYPE_INCOMPLETE_VARS (element)); - } - return x; -} - - -/* Issue a warning about implicit function declaration. ID is the function - identifier, OLDDECL is a declaration of the function in a different scope, - or NULL_TREE. */ - -static void -implicit_decl_warning (location_t loc, tree id, tree olddecl) -{ - if (!warn_implicit_function_declaration) - return; - - bool warned; - auto_diagnostic_group d; - name_hint hint; - if (!olddecl) - hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_FUNCTION_NAME, loc); - - if (flag_isoc99) - { - if (const char *suggestion = hint.suggestion ()) - { - gcc_rich_location richloc (loc); - richloc.add_fixit_replace (suggestion); - warned = pedwarn (&richloc, OPT_Wimplicit_function_declaration, - "implicit declaration of function %qE;" - " did you mean %qs?", - id, suggestion); - } - else - warned = pedwarn (loc, OPT_Wimplicit_function_declaration, - "implicit declaration of function %qE", id); - } - else if (const char *suggestion = hint.suggestion ()) - { - gcc_rich_location richloc (loc); - richloc.add_fixit_replace (suggestion); - warned = warning_at - (&richloc, OPT_Wimplicit_function_declaration, - G_("implicit declaration of function %qE; did you mean %qs?"), - id, suggestion); - } - else - warned = warning_at (loc, OPT_Wimplicit_function_declaration, - G_("implicit declaration of function %qE"), id); - - if (warned) - { - /* Whether the olddecl is an undeclared builtin function. - locate_old_decl will not generate a diagnostic for those, - so in that case we want to look elsewhere. */ - bool undeclared_builtin = (olddecl - && TREE_CODE (olddecl) == FUNCTION_DECL - && fndecl_built_in_p (olddecl) - && !C_DECL_DECLARED_BUILTIN (olddecl)); - if (undeclared_builtin) - { - const char *header = header_for_builtin_fn (olddecl); - if (header) - { - rich_location richloc (line_table, loc); - maybe_add_include_fixit (&richloc, header, true); - inform (&richloc, - "include %qs or provide a declaration of %qE", - header, id); - } - } - else if (olddecl) - locate_old_decl (olddecl); - } - - if (!warned) - hint.suppress (); -} - -/* Return the name of the header file that declares built-in function - FNDECL, or null if either we don't know or don't expect to see an - explicit declaration. */ - -static const char * -header_for_builtin_fn (tree fndecl) -{ - if (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL) - return NULL; - - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_ACOS): - CASE_FLT_FN (BUILT_IN_ACOSH): - CASE_FLT_FN (BUILT_IN_ASIN): - CASE_FLT_FN (BUILT_IN_ASINH): - CASE_FLT_FN (BUILT_IN_ATAN): - CASE_FLT_FN (BUILT_IN_ATANH): - CASE_FLT_FN (BUILT_IN_ATAN2): - CASE_FLT_FN (BUILT_IN_CBRT): - CASE_FLT_FN (BUILT_IN_CEIL): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_CEIL): - CASE_FLT_FN (BUILT_IN_COPYSIGN): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_COPYSIGN): - CASE_FLT_FN (BUILT_IN_COS): - CASE_FLT_FN (BUILT_IN_COSH): - CASE_FLT_FN (BUILT_IN_ERF): - CASE_FLT_FN (BUILT_IN_ERFC): - CASE_FLT_FN (BUILT_IN_EXP): - CASE_FLT_FN (BUILT_IN_EXP2): - CASE_FLT_FN (BUILT_IN_EXPM1): - CASE_FLT_FN (BUILT_IN_FABS): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS): - CASE_FLT_FN (BUILT_IN_FDIM): - CASE_FLT_FN (BUILT_IN_FLOOR): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_FLOOR): - CASE_FLT_FN (BUILT_IN_FMA): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMA): - CASE_FLT_FN (BUILT_IN_FMAX): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMAX): - CASE_FLT_FN (BUILT_IN_FMIN): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMIN): - CASE_FLT_FN (BUILT_IN_FMOD): - CASE_FLT_FN (BUILT_IN_FREXP): - CASE_FLT_FN (BUILT_IN_HYPOT): - CASE_FLT_FN (BUILT_IN_ILOGB): - CASE_FLT_FN (BUILT_IN_LDEXP): - CASE_FLT_FN (BUILT_IN_LGAMMA): - CASE_FLT_FN (BUILT_IN_LLRINT): - CASE_FLT_FN (BUILT_IN_LLROUND): - CASE_FLT_FN (BUILT_IN_LOG): - CASE_FLT_FN (BUILT_IN_LOG10): - CASE_FLT_FN (BUILT_IN_LOG1P): - CASE_FLT_FN (BUILT_IN_LOG2): - CASE_FLT_FN (BUILT_IN_LOGB): - CASE_FLT_FN (BUILT_IN_LRINT): - CASE_FLT_FN (BUILT_IN_LROUND): - CASE_FLT_FN (BUILT_IN_MODF): - CASE_FLT_FN (BUILT_IN_NAN): - CASE_FLT_FN (BUILT_IN_NEARBYINT): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_NEARBYINT): - CASE_FLT_FN (BUILT_IN_NEXTAFTER): - CASE_FLT_FN (BUILT_IN_NEXTTOWARD): - CASE_FLT_FN (BUILT_IN_POW): - CASE_FLT_FN (BUILT_IN_REMAINDER): - CASE_FLT_FN (BUILT_IN_REMQUO): - CASE_FLT_FN (BUILT_IN_RINT): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_RINT): - CASE_FLT_FN (BUILT_IN_ROUND): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_ROUND): - CASE_FLT_FN (BUILT_IN_SCALBLN): - CASE_FLT_FN (BUILT_IN_SCALBN): - CASE_FLT_FN (BUILT_IN_SIN): - CASE_FLT_FN (BUILT_IN_SINH): - CASE_FLT_FN (BUILT_IN_SINCOS): - CASE_FLT_FN (BUILT_IN_SQRT): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_SQRT): - CASE_FLT_FN (BUILT_IN_TAN): - CASE_FLT_FN (BUILT_IN_TANH): - CASE_FLT_FN (BUILT_IN_TGAMMA): - CASE_FLT_FN (BUILT_IN_TRUNC): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_TRUNC): - case BUILT_IN_ISINF: - case BUILT_IN_ISNAN: - return ""; - CASE_FLT_FN (BUILT_IN_CABS): - CASE_FLT_FN (BUILT_IN_CACOS): - CASE_FLT_FN (BUILT_IN_CACOSH): - CASE_FLT_FN (BUILT_IN_CARG): - CASE_FLT_FN (BUILT_IN_CASIN): - CASE_FLT_FN (BUILT_IN_CASINH): - CASE_FLT_FN (BUILT_IN_CATAN): - CASE_FLT_FN (BUILT_IN_CATANH): - CASE_FLT_FN (BUILT_IN_CCOS): - CASE_FLT_FN (BUILT_IN_CCOSH): - CASE_FLT_FN (BUILT_IN_CEXP): - CASE_FLT_FN (BUILT_IN_CIMAG): - CASE_FLT_FN (BUILT_IN_CLOG): - CASE_FLT_FN (BUILT_IN_CONJ): - CASE_FLT_FN (BUILT_IN_CPOW): - CASE_FLT_FN (BUILT_IN_CPROJ): - CASE_FLT_FN (BUILT_IN_CREAL): - CASE_FLT_FN (BUILT_IN_CSIN): - CASE_FLT_FN (BUILT_IN_CSINH): - CASE_FLT_FN (BUILT_IN_CSQRT): - CASE_FLT_FN (BUILT_IN_CTAN): - CASE_FLT_FN (BUILT_IN_CTANH): - return ""; - case BUILT_IN_MEMCHR: - case BUILT_IN_MEMCMP: - case BUILT_IN_MEMCPY: - case BUILT_IN_MEMMOVE: - case BUILT_IN_MEMSET: - case BUILT_IN_STRCAT: - case BUILT_IN_STRCHR: - case BUILT_IN_STRCMP: - case BUILT_IN_STRCPY: - case BUILT_IN_STRCSPN: - case BUILT_IN_STRLEN: - case BUILT_IN_STRNCAT: - case BUILT_IN_STRNCMP: - case BUILT_IN_STRNCPY: - case BUILT_IN_STRPBRK: - case BUILT_IN_STRRCHR: - case BUILT_IN_STRSPN: - case BUILT_IN_STRSTR: - return ""; - case BUILT_IN_FPRINTF: - case BUILT_IN_PUTC: - case BUILT_IN_FPUTC: - case BUILT_IN_FPUTS: - case BUILT_IN_FSCANF: - case BUILT_IN_FWRITE: - case BUILT_IN_PRINTF: - case BUILT_IN_PUTCHAR: - case BUILT_IN_PUTS: - case BUILT_IN_SCANF: - case BUILT_IN_SNPRINTF: - case BUILT_IN_SPRINTF: - case BUILT_IN_SSCANF: - case BUILT_IN_VFPRINTF: - case BUILT_IN_VFSCANF: - case BUILT_IN_VPRINTF: - case BUILT_IN_VSCANF: - case BUILT_IN_VSNPRINTF: - case BUILT_IN_VSPRINTF: - case BUILT_IN_VSSCANF: - return ""; - case BUILT_IN_ISALNUM: - case BUILT_IN_ISALPHA: - case BUILT_IN_ISBLANK: - case BUILT_IN_ISCNTRL: - case BUILT_IN_ISDIGIT: - case BUILT_IN_ISGRAPH: - case BUILT_IN_ISLOWER: - case BUILT_IN_ISPRINT: - case BUILT_IN_ISPUNCT: - case BUILT_IN_ISSPACE: - case BUILT_IN_ISUPPER: - case BUILT_IN_ISXDIGIT: - case BUILT_IN_TOLOWER: - case BUILT_IN_TOUPPER: - return ""; - case BUILT_IN_ISWALNUM: - case BUILT_IN_ISWALPHA: - case BUILT_IN_ISWBLANK: - case BUILT_IN_ISWCNTRL: - case BUILT_IN_ISWDIGIT: - case BUILT_IN_ISWGRAPH: - case BUILT_IN_ISWLOWER: - case BUILT_IN_ISWPRINT: - case BUILT_IN_ISWPUNCT: - case BUILT_IN_ISWSPACE: - case BUILT_IN_ISWUPPER: - case BUILT_IN_ISWXDIGIT: - case BUILT_IN_TOWLOWER: - case BUILT_IN_TOWUPPER: - return ""; - case BUILT_IN_ABORT: - case BUILT_IN_ABS: - case BUILT_IN_CALLOC: - case BUILT_IN_EXIT: - case BUILT_IN_FREE: - case BUILT_IN_LABS: - case BUILT_IN_LLABS: - case BUILT_IN_MALLOC: - case BUILT_IN_REALLOC: - case BUILT_IN__EXIT2: - case BUILT_IN_ALIGNED_ALLOC: - return ""; - case BUILT_IN_IMAXABS: - return ""; - case BUILT_IN_STRFTIME: - return ""; - default: - return NULL; - } -} - -/* Generate an implicit declaration for identifier FUNCTIONID at LOC as a - function of type int (). */ - -tree -implicitly_declare (location_t loc, tree functionid) -{ - struct c_binding *b; - tree decl = NULL_TREE; - tree asmspec_tree; - - for (b = I_SYMBOL_BINDING (functionid); b; b = b->shadowed) - { - if (B_IN_SCOPE (b, external_scope)) - { - decl = b->decl; - break; - } - } - - if (decl) - { - if (TREE_CODE (decl) != FUNCTION_DECL) - return decl; - - /* FIXME: Objective-C has weird not-really-builtin functions - which are supposed to be visible automatically. They wind up - in the external scope because they're pushed before the file - scope gets created. Catch this here and rebind them into the - file scope. */ - if (!fndecl_built_in_p (decl) && DECL_IS_UNDECLARED_BUILTIN (decl)) - { - bind (functionid, decl, file_scope, - /*invisible=*/false, /*nested=*/true, - DECL_SOURCE_LOCATION (decl)); - return decl; - } - else - { - tree newtype = default_function_type; - if (b->u.type) - TREE_TYPE (decl) = b->u.type; - /* Implicit declaration of a function already declared - (somehow) in a different scope, or as a built-in. - If this is the first time this has happened, warn; - then recycle the old declaration but with the new type. */ - if (!C_DECL_IMPLICIT (decl)) - { - implicit_decl_warning (loc, functionid, decl); - C_DECL_IMPLICIT (decl) = 1; - } - if (fndecl_built_in_p (decl)) - { - newtype = build_type_attribute_variant (newtype, - TYPE_ATTRIBUTES - (TREE_TYPE (decl))); - if (!comptypes (newtype, TREE_TYPE (decl))) - { - bool warned = warning_at (loc, - OPT_Wbuiltin_declaration_mismatch, - "incompatible implicit " - "declaration of built-in " - "function %qD", decl); - /* See if we can hint which header to include. */ - const char *header = header_for_builtin_fn (decl); - if (header != NULL && warned) - { - rich_location richloc (line_table, loc); - maybe_add_include_fixit (&richloc, header, true); - inform (&richloc, - "include %qs or provide a declaration of %qD", - header, decl); - } - newtype = TREE_TYPE (decl); - } - } - else - { - if (!comptypes (newtype, TREE_TYPE (decl))) - { - auto_diagnostic_group d; - error_at (loc, "incompatible implicit declaration of " - "function %qD", decl); - locate_old_decl (decl); - } - } - b->u.type = TREE_TYPE (decl); - TREE_TYPE (decl) = newtype; - bind (functionid, decl, current_scope, - /*invisible=*/false, /*nested=*/true, - DECL_SOURCE_LOCATION (decl)); - return decl; - } - } - - /* Not seen before. */ - decl = build_decl (loc, FUNCTION_DECL, functionid, default_function_type); - DECL_EXTERNAL (decl) = 1; - TREE_PUBLIC (decl) = 1; - C_DECL_IMPLICIT (decl) = 1; - implicit_decl_warning (loc, functionid, 0); - asmspec_tree = maybe_apply_renaming_pragma (decl, /*asmname=*/NULL); - if (asmspec_tree) - set_user_assembler_name (decl, TREE_STRING_POINTER (asmspec_tree)); - - /* C89 says implicit declarations are in the innermost block. - So we record the decl in the standard fashion. */ - decl = pushdecl (decl); - - /* No need to call objc_check_decl here - it's a function type. */ - rest_of_decl_compilation (decl, 0, 0); - - /* Write a record describing this implicit function declaration - to the prototypes file (if requested). */ - gen_aux_info_record (decl, 0, 1, 0); - - /* Possibly apply some default attributes to this implicit declaration. */ - decl_attributes (&decl, NULL_TREE, 0); - - return decl; -} - -/* Issue an error message for a reference to an undeclared variable - ID, including a reference to a builtin outside of function-call - context. Establish a binding of the identifier to error_mark_node - in an appropriate scope, which will suppress further errors for the - same identifier. The error message should be given location LOC. */ -void -undeclared_variable (location_t loc, tree id) -{ - static bool already = false; - struct c_scope *scope; - - auto_diagnostic_group d; - if (current_function_decl == NULL_TREE) - { - name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc); - if (const char *suggestion = guessed_id.suggestion ()) - { - gcc_rich_location richloc (loc); - richloc.add_fixit_replace (suggestion); - error_at (&richloc, - "%qE undeclared here (not in a function);" - " did you mean %qs?", - id, suggestion); - } - else - error_at (loc, "%qE undeclared here (not in a function)", id); - scope = current_scope; - } - else - { - if (!objc_diagnose_private_ivar (id)) - { - name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc); - if (const char *suggestion = guessed_id.suggestion ()) - { - gcc_rich_location richloc (loc); - richloc.add_fixit_replace (suggestion); - error_at (&richloc, - "%qE undeclared (first use in this function);" - " did you mean %qs?", - id, suggestion); - } - else - error_at (loc, "%qE undeclared (first use in this function)", id); - } - if (!already) - { - inform (loc, "each undeclared identifier is reported only" - " once for each function it appears in"); - already = true; - } - - /* If we are parsing old-style parameter decls, current_function_decl - will be nonnull but current_function_scope will be null. */ - scope = current_function_scope ? current_function_scope : current_scope; - } - bind (id, error_mark_node, scope, /*invisible=*/false, /*nested=*/false, - UNKNOWN_LOCATION); -} - -/* Subroutine of lookup_label, declare_label, define_label: construct a - LABEL_DECL with all the proper frills. Also create a struct - c_label_vars initialized for the current scope. */ - -static tree -make_label (location_t location, tree name, bool defining, - struct c_label_vars **p_label_vars) -{ - tree label = build_decl (location, LABEL_DECL, name, void_type_node); - DECL_CONTEXT (label) = current_function_decl; - SET_DECL_MODE (label, VOIDmode); - - c_label_vars *label_vars = ggc_alloc (); - label_vars->shadowed = NULL; - set_spot_bindings (&label_vars->label_bindings, defining); - label_vars->decls_in_scope = make_tree_vector (); - label_vars->gotos = NULL; - *p_label_vars = label_vars; - - return label; -} - -/* Get the LABEL_DECL corresponding to identifier NAME as a label. - Create one if none exists so far for the current function. - This is called when a label is used in a goto expression or - has its address taken. */ - -tree -lookup_label (tree name) -{ - tree label; - struct c_label_vars *label_vars; - - if (current_function_scope == 0) - { - error ("label %qE referenced outside of any function", name); - return NULL_TREE; - } - - /* Use a label already defined or ref'd with this name, but not if - it is inherited from a containing function and wasn't declared - using __label__. */ - label = I_LABEL_DECL (name); - if (label && (DECL_CONTEXT (label) == current_function_decl - || C_DECLARED_LABEL_FLAG (label))) - { - /* If the label has only been declared, update its apparent - location to point here, for better diagnostics if it - turns out not to have been defined. */ - if (DECL_INITIAL (label) == NULL_TREE) - DECL_SOURCE_LOCATION (label) = input_location; - return label; - } - - /* No label binding for that identifier; make one. */ - label = make_label (input_location, name, false, &label_vars); - - /* Ordinary labels go in the current function scope. */ - bind_label (name, label, current_function_scope, label_vars); - - return label; -} - -/* Issue a warning about DECL for a goto statement at GOTO_LOC going - to LABEL. */ - -static void -warn_about_goto (location_t goto_loc, tree label, tree decl) -{ - if (variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) - error_at (goto_loc, - "jump into scope of identifier with variably modified type"); - else - warning_at (goto_loc, OPT_Wjump_misses_init, - "jump skips variable initialization"); - inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label); - inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl); -} - -/* Look up a label because of a goto statement. This is like - lookup_label, but also issues any appropriate warnings. */ - -tree -lookup_label_for_goto (location_t loc, tree name) -{ - tree label; - struct c_label_vars *label_vars; - unsigned int ix; - tree decl; - - label = lookup_label (name); - if (label == NULL_TREE) - return NULL_TREE; - - /* If we are jumping to a different function, we can't issue any - useful warnings. */ - if (DECL_CONTEXT (label) != current_function_decl) - { - gcc_assert (C_DECLARED_LABEL_FLAG (label)); - return label; - } - - label_vars = I_LABEL_BINDING (name)->u.label; - - /* If the label has not yet been defined, then push this goto on a - list for possible later warnings. */ - if (label_vars->label_bindings.scope == NULL) - { - c_goto_bindings *g = ggc_alloc (); - - g->loc = loc; - set_spot_bindings (&g->goto_bindings, true); - vec_safe_push (label_vars->gotos, g); - return label; - } - - /* If there are any decls in label_vars->decls_in_scope, then this - goto has missed the declaration of the decl. This happens for a - case like - int i = 1; - lab: - ... - goto lab; - Issue a warning or error. */ - FOR_EACH_VEC_SAFE_ELT (label_vars->decls_in_scope, ix, decl) - warn_about_goto (loc, label, decl); - - if (label_vars->label_bindings.left_stmt_expr) - { - error_at (loc, "jump into statement expression"); - inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label); - } - - return label; -} - -/* Make a label named NAME in the current function, shadowing silently - any that may be inherited from containing functions or containing - scopes. This is called for __label__ declarations. */ - -tree -declare_label (tree name) -{ - struct c_binding *b = I_LABEL_BINDING (name); - tree label; - struct c_label_vars *label_vars; - - /* Check to make sure that the label hasn't already been declared - at this scope */ - if (b && B_IN_CURRENT_SCOPE (b)) - { - auto_diagnostic_group d; - error ("duplicate label declaration %qE", name); - locate_old_decl (b->decl); - - /* Just use the previous declaration. */ - return b->decl; - } - - label = make_label (input_location, name, false, &label_vars); - C_DECLARED_LABEL_FLAG (label) = 1; - - /* Declared labels go in the current scope. */ - bind_label (name, label, current_scope, label_vars); - - return label; -} - -/* When we define a label, issue any appropriate warnings if there are - any gotos earlier in the function which jump to this label. */ - -static void -check_earlier_gotos (tree label, struct c_label_vars* label_vars) -{ - unsigned int ix; - struct c_goto_bindings *g; - - FOR_EACH_VEC_SAFE_ELT (label_vars->gotos, ix, g) - { - struct c_binding *b; - struct c_scope *scope; - - /* We have a goto to this label. The goto is going forward. In - g->scope, the goto is going to skip any binding which was - defined after g->bindings_in_scope. */ - if (g->goto_bindings.scope->has_jump_unsafe_decl) - { - for (b = g->goto_bindings.scope->bindings; - b != g->goto_bindings.bindings_in_scope; - b = b->prev) - { - if (decl_jump_unsafe (b->decl)) - warn_about_goto (g->loc, label, b->decl); - } - } - - /* We also need to warn about decls defined in any scopes - between the scope of the label and the scope of the goto. */ - for (scope = label_vars->label_bindings.scope; - scope != g->goto_bindings.scope; - scope = scope->outer) - { - gcc_assert (scope != NULL); - if (scope->has_jump_unsafe_decl) - { - if (scope == label_vars->label_bindings.scope) - b = label_vars->label_bindings.bindings_in_scope; - else - b = scope->bindings; - for (; b != NULL; b = b->prev) - { - if (decl_jump_unsafe (b->decl)) - warn_about_goto (g->loc, label, b->decl); - } - } - } - - if (g->goto_bindings.stmt_exprs > 0) - { - error_at (g->loc, "jump into statement expression"); - inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", - label); - } - } - - /* Now that the label is defined, we will issue warnings about - subsequent gotos to this label when we see them. */ - vec_safe_truncate (label_vars->gotos, 0); - label_vars->gotos = NULL; -} - -/* Define a label, specifying the location in the source file. - Return the LABEL_DECL node for the label, if the definition is valid. - Otherwise return NULL_TREE. */ - -tree -define_label (location_t location, tree name) -{ - /* Find any preexisting label with this name. It is an error - if that label has already been defined in this function, or - if there is a containing function with a declared label with - the same name. */ - tree label = I_LABEL_DECL (name); - - if (label - && ((DECL_CONTEXT (label) == current_function_decl - && DECL_INITIAL (label) != NULL_TREE) - || (DECL_CONTEXT (label) != current_function_decl - && C_DECLARED_LABEL_FLAG (label)))) - { - auto_diagnostic_group d; - error_at (location, "duplicate label %qD", label); - locate_old_decl (label); - return NULL_TREE; - } - else if (label && DECL_CONTEXT (label) == current_function_decl) - { - struct c_label_vars *label_vars = I_LABEL_BINDING (name)->u.label; - - /* The label has been used or declared already in this function, - but not defined. Update its location to point to this - definition. */ - DECL_SOURCE_LOCATION (label) = location; - set_spot_bindings (&label_vars->label_bindings, true); - - /* Issue warnings as required about any goto statements from - earlier in the function. */ - check_earlier_gotos (label, label_vars); - } - else - { - struct c_label_vars *label_vars; - - /* No label binding for that identifier; make one. */ - label = make_label (location, name, true, &label_vars); - - /* Ordinary labels go in the current function scope. */ - bind_label (name, label, current_function_scope, label_vars); - } - - if (!in_system_header_at (input_location) && lookup_name (name)) - warning_at (location, OPT_Wtraditional, - "traditional C lacks a separate namespace " - "for labels, identifier %qE conflicts", name); - - /* Mark label as having been defined. */ - DECL_INITIAL (label) = error_mark_node; - return label; -} - -/* Get the bindings for a new switch statement. This is used to issue - warnings as appropriate for jumps from the switch to case or - default labels. */ - -struct c_spot_bindings * -c_get_switch_bindings (void) -{ - struct c_spot_bindings *switch_bindings; - - switch_bindings = XNEW (struct c_spot_bindings); - set_spot_bindings (switch_bindings, true); - return switch_bindings; -} - -void -c_release_switch_bindings (struct c_spot_bindings *bindings) -{ - gcc_assert (bindings->stmt_exprs == 0 && !bindings->left_stmt_expr); - XDELETE (bindings); -} - -/* This is called at the point of a case or default label to issue - warnings about decls as needed. It returns true if it found an - error, not just a warning. */ - -bool -c_check_switch_jump_warnings (struct c_spot_bindings *switch_bindings, - location_t switch_loc, location_t case_loc) -{ - bool saw_error; - struct c_scope *scope; - - saw_error = false; - for (scope = current_scope; - scope != switch_bindings->scope; - scope = scope->outer) - { - struct c_binding *b; - - gcc_assert (scope != NULL); - - if (!scope->has_jump_unsafe_decl) - continue; - - for (b = scope->bindings; b != NULL; b = b->prev) - { - if (decl_jump_unsafe (b->decl)) - { - if (variably_modified_type_p (TREE_TYPE (b->decl), NULL_TREE)) - { - saw_error = true; - error_at (case_loc, - ("switch jumps into scope of identifier with " - "variably modified type")); - } - else - warning_at (case_loc, OPT_Wjump_misses_init, - "switch jumps over variable initialization"); - inform (switch_loc, "switch starts here"); - inform (DECL_SOURCE_LOCATION (b->decl), "%qD declared here", - b->decl); - } - } - } - - if (switch_bindings->stmt_exprs > 0) - { - saw_error = true; - error_at (case_loc, "switch jumps into statement expression"); - inform (switch_loc, "switch starts here"); - } - - return saw_error; -} - -/* Given NAME, an IDENTIFIER_NODE, - return the structure (or union or enum) definition for that name. - If THISLEVEL_ONLY is nonzero, searches only the current_scope. - CODE says which kind of type the caller wants; - it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE. - If PLOC is not NULL and this returns non-null, it sets *PLOC to the - location where the tag was defined. - If the wrong kind of type is found, an error is reported. */ - -static tree -lookup_tag (enum tree_code code, tree name, bool thislevel_only, - location_t *ploc) -{ - struct c_binding *b = I_TAG_BINDING (name); - bool thislevel = false; - - if (!b || !b->decl) - return NULL_TREE; - - /* We only care about whether it's in this level if - thislevel_only was set or it might be a type clash. */ - if (thislevel_only || TREE_CODE (b->decl) != code) - { - /* For our purposes, a tag in the external scope is the same as - a tag in the file scope. (Primarily relevant to Objective-C - and its builtin structure tags, which get pushed before the - file scope is created.) */ - if (B_IN_CURRENT_SCOPE (b) - || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) - thislevel = true; - } - - if (thislevel_only && !thislevel) - return NULL_TREE; - - if (TREE_CODE (b->decl) != code) - { - /* Definition isn't the kind we were looking for. */ - pending_invalid_xref = name; - pending_invalid_xref_location = input_location; - - /* If in the same binding level as a declaration as a tag - of a different type, this must not be allowed to - shadow that tag, so give the error immediately. - (For example, "struct foo; union foo;" is invalid.) */ - if (thislevel) - pending_xref_error (); - } - - if (ploc != NULL) - *ploc = b->locus; - - return b->decl; -} - -/* Return true if a definition exists for NAME with code CODE. */ - -bool -tag_exists_p (enum tree_code code, tree name) -{ - struct c_binding *b = I_TAG_BINDING (name); - - if (b == NULL || b->decl == NULL_TREE) - return false; - return TREE_CODE (b->decl) == code; -} - -/* Print an error message now - for a recent invalid struct, union or enum cross reference. - We don't print them immediately because they are not invalid - when used in the `struct foo;' construct for shadowing. */ - -void -pending_xref_error (void) -{ - if (pending_invalid_xref != NULL_TREE) - error_at (pending_invalid_xref_location, "%qE defined as wrong kind of tag", - pending_invalid_xref); - pending_invalid_xref = NULL_TREE; -} - - -/* Look up NAME in the current scope and its superiors - in the namespace of variables, functions and typedefs. - Return a ..._DECL node of some kind representing its definition, - or return NULL_TREE if it is undefined. */ - -tree -lookup_name (tree name) -{ - struct c_binding *b = I_SYMBOL_BINDING (name); - if (b && !b->invisible) - { - maybe_record_typedef_use (b->decl); - return b->decl; - } - return NULL_TREE; -} - -/* Similar to `lookup_name' but look only at the indicated scope. */ - -static tree -lookup_name_in_scope (tree name, struct c_scope *scope) -{ - struct c_binding *b; - - for (b = I_SYMBOL_BINDING (name); b; b = b->shadowed) - if (B_IN_SCOPE (b, scope)) - return b->decl; - return NULL_TREE; -} - -/* Look for the closest match for NAME within the currently valid - scopes. - - This finds the identifier with the lowest Levenshtein distance to - NAME. If there are multiple candidates with equal minimal distance, - the first one found is returned. Scopes are searched from innermost - outwards, and within a scope in reverse order of declaration, thus - benefiting candidates "near" to the current scope. - - The function also looks for similar macro names to NAME, since a - misspelled macro name will not be expanded, and hence looks like an - identifier to the C frontend. - - It also looks for start_typename keywords, to detect "singed" vs "signed" - typos. - - Use LOC for any deferred diagnostics. */ - -name_hint -lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) -{ - gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); - - /* First, try some well-known names in the C standard library, in case - the user forgot a #include. */ - const char *header_hint - = get_c_stdlib_header_for_name (IDENTIFIER_POINTER (name)); - - if (header_hint) - return name_hint (NULL, - new suggest_missing_header (loc, - IDENTIFIER_POINTER (name), - header_hint)); - - /* Only suggest names reserved for the implementation if NAME begins - with an underscore. */ - bool consider_implementation_names = (IDENTIFIER_POINTER (name)[0] == '_'); - - best_match bm (name); - - /* Look within currently valid scopes. */ - for (c_scope *scope = current_scope; scope; scope = scope->outer) - for (c_binding *binding = scope->bindings; binding; binding = binding->prev) - { - if (!binding->id || binding->invisible) - continue; - if (binding->decl == error_mark_node) - continue; - /* Don't use bindings from implicitly declared functions, - as they were likely misspellings themselves. */ - if (TREE_CODE (binding->decl) == FUNCTION_DECL) - if (C_DECL_IMPLICIT (binding->decl)) - continue; - /* Don't suggest names that are reserved for use by the - implementation, unless NAME began with an underscore. */ - if (!consider_implementation_names) - { - const char *suggestion_str = IDENTIFIER_POINTER (binding->id); - if (name_reserved_for_implementation_p (suggestion_str)) - continue; - } - switch (kind) - { - case FUZZY_LOOKUP_TYPENAME: - if (TREE_CODE (binding->decl) != TYPE_DECL) - continue; - break; - - case FUZZY_LOOKUP_FUNCTION_NAME: - if (TREE_CODE (binding->decl) != FUNCTION_DECL) - { - /* Allow function pointers. */ - if ((VAR_P (binding->decl) - || TREE_CODE (binding->decl) == PARM_DECL) - && TREE_CODE (TREE_TYPE (binding->decl)) == POINTER_TYPE - && (TREE_CODE (TREE_TYPE (TREE_TYPE (binding->decl))) - == FUNCTION_TYPE)) - break; - continue; - } - break; - - default: - break; - } - bm.consider (binding->id); - } - - /* Consider macros: if the user misspelled a macro name e.g. "SOME_MACRO" - as: - x = SOME_OTHER_MACRO (y); - then "SOME_OTHER_MACRO" will survive to the frontend and show up - as a misspelled identifier. - - Use the best distance so far so that a candidate is only set if - a macro is better than anything so far. This allows early rejection - (without calculating the edit distance) of macro names that must have - distance >= bm.get_best_distance (), and means that we only get a - non-NULL result for best_macro_match if it's better than any of - the identifiers already checked, which avoids needless creation - of identifiers for macro hashnodes. */ - best_macro_match bmm (name, bm.get_best_distance (), parse_in); - cpp_hashnode *best_macro = bmm.get_best_meaningful_candidate (); - /* If a macro is the closest so far to NAME, use it, creating an - identifier tree node for it. */ - if (best_macro) - { - const char *id = (const char *)best_macro->ident.str; - tree macro_as_identifier - = get_identifier_with_length (id, best_macro->ident.len); - bm.set_best_so_far (macro_as_identifier, - bmm.get_best_distance (), - bmm.get_best_candidate_length ()); - } - - /* Try the "start_typename" keywords to detect - "singed" vs "signed" typos. */ - if (kind == FUZZY_LOOKUP_TYPENAME) - { - for (unsigned i = 0; i < num_c_common_reswords; i++) - { - const c_common_resword *resword = &c_common_reswords[i]; - if (!c_keyword_starts_typename (resword->rid)) - continue; - tree resword_identifier = ridpointers [resword->rid]; - if (!resword_identifier) - continue; - gcc_assert (TREE_CODE (resword_identifier) == IDENTIFIER_NODE); - bm.consider (resword_identifier); - } - } - - tree best = bm.get_best_meaningful_candidate (); - if (best) - return name_hint (IDENTIFIER_POINTER (best), NULL); - else - return name_hint (NULL, NULL); -} - - -/* Handle the standard [[nodiscard]] attribute. */ - -static tree -handle_nodiscard_attribute (tree *node, tree name, tree /*args*/, - int /*flags*/, bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - { - if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))) - warning_at (DECL_SOURCE_LOCATION (*node), - OPT_Wattributes, "%qE attribute applied to %qD with void " - "return type", name, *node); - } - else if (RECORD_OR_UNION_TYPE_P (*node) - || TREE_CODE (*node) == ENUMERAL_TYPE) - /* OK */; - else - { - pedwarn (input_location, - OPT_Wattributes, "%qE attribute can only be applied to " - "functions or to structure, union or enumeration types", name); - *no_add_attrs = true; - } - return NULL_TREE; -} -/* Table of supported standard (C2x) attributes. */ -const struct attribute_spec std_attribute_table[] = -{ - /* { name, min_len, max_len, decl_req, type_req, fn_type_req, - affects_type_identity, handler, exclude } */ - { "deprecated", 0, 1, false, false, false, false, - handle_deprecated_attribute, NULL }, - { "fallthrough", 0, 0, false, false, false, false, - handle_fallthrough_attribute, NULL }, - { "maybe_unused", 0, 0, false, false, false, false, - handle_unused_attribute, NULL }, - { "nodiscard", 0, 1, false, false, false, false, - handle_nodiscard_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; - -/* Create the predefined scalar types of C, - and some nodes representing standard constants (0, 1, (void *) 0). - Initialize the global scope. - Make definitions for built-in primitive functions. */ - -void -c_init_decl_processing (void) -{ - location_t save_loc = input_location; - - /* Initialize reserved words for parser. */ - c_parse_init (); - - register_scoped_attributes (std_attribute_table, NULL); - - current_function_decl = NULL_TREE; - - gcc_obstack_init (&parser_obstack); - - /* Make the externals scope. */ - push_scope (); - external_scope = current_scope; - - /* Declarations from c_common_nodes_and_builtins must not be associated - with this input file, lest we get differences between using and not - using preprocessed headers. */ - input_location = BUILTINS_LOCATION; - - c_common_nodes_and_builtins (); - - /* In C, comparisons and TRUTH_* expressions have type int. */ - truthvalue_type_node = integer_type_node; - truthvalue_true_node = integer_one_node; - truthvalue_false_node = integer_zero_node; - - /* Even in C99, which has a real boolean type. */ - pushdecl (build_decl (UNKNOWN_LOCATION, TYPE_DECL, get_identifier ("_Bool"), - boolean_type_node)); - - input_location = save_loc; - - make_fname_decl = c_make_fname_decl; - start_fname_decls (); -} - -/* Create the VAR_DECL at LOC for __FUNCTION__ etc. ID is the name to - give the decl, NAME is the initialization string and TYPE_DEP - indicates whether NAME depended on the type of the function. As we - don't yet implement delayed emission of static data, we mark the - decl as emitted so it is not placed in the output. Anything using - it must therefore pull out the STRING_CST initializer directly. - FIXME. */ - -static tree -c_make_fname_decl (location_t loc, tree id, int type_dep) -{ - const char *name = fname_as_string (type_dep); - tree decl, type, init; - size_t length = strlen (name); - - type = build_array_type (char_type_node, - build_index_type (size_int (length))); - type = c_build_qualified_type (type, TYPE_QUAL_CONST); - - decl = build_decl (loc, VAR_DECL, id, type); - - TREE_STATIC (decl) = 1; - TREE_READONLY (decl) = 1; - DECL_ARTIFICIAL (decl) = 1; - - init = build_string (length + 1, name); - free (CONST_CAST (char *, name)); - TREE_TYPE (init) = type; - DECL_INITIAL (decl) = init; - - TREE_USED (decl) = 1; - - if (current_function_decl - /* For invalid programs like this: - - void foo() - const char* p = __FUNCTION__; - - the __FUNCTION__ is believed to appear in K&R style function - parameter declarator. In that case we still don't have - function_scope. */ - && current_function_scope) - { - DECL_CONTEXT (decl) = current_function_decl; - bind (id, decl, current_function_scope, - /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION); - } - - finish_decl (decl, loc, init, NULL_TREE, NULL_TREE); - - return decl; -} - -tree -c_builtin_function (tree decl) -{ - tree type = TREE_TYPE (decl); - tree id = DECL_NAME (decl); - - const char *name = IDENTIFIER_POINTER (id); - C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type); - - /* Should never be called on a symbol with a preexisting meaning. */ - gcc_assert (!I_SYMBOL_BINDING (id)); - - bind (id, decl, external_scope, /*invisible=*/true, /*nested=*/false, - UNKNOWN_LOCATION); - - /* Builtins in the implementation namespace are made visible without - needing to be explicitly declared. See push_file_scope. */ - if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1]))) - { - DECL_CHAIN (decl) = visible_builtins; - visible_builtins = decl; - } - - return decl; -} - -tree -c_builtin_function_ext_scope (tree decl) -{ - tree type = TREE_TYPE (decl); - tree id = DECL_NAME (decl); - - const char *name = IDENTIFIER_POINTER (id); - C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type); - - if (external_scope) - bind (id, decl, external_scope, /*invisible=*/false, /*nested=*/false, - UNKNOWN_LOCATION); - - /* Builtins in the implementation namespace are made visible without - needing to be explicitly declared. See push_file_scope. */ - if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1]))) - { - DECL_CHAIN (decl) = visible_builtins; - visible_builtins = decl; - } - - return decl; -} - -/* Implement LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL. */ - -tree -c_simulate_builtin_function_decl (tree decl) -{ - tree type = TREE_TYPE (decl); - C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type); - return pushdecl (decl); -} - -/* Warn about attributes in a context where they are unused - (attribute-declarations, except for the "fallthrough" case, and - attributes on statements). */ - -void -c_warn_unused_attributes (tree attrs) -{ - for (tree t = attrs; t != NULL_TREE; t = TREE_CHAIN (t)) - if (get_attribute_namespace (t) == NULL_TREE) - /* The specifications of standard attributes mean this is a - constraint violation. */ - pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", - get_attribute_name (t)); - else if (!attribute_ignored_p (t)) - warning (OPT_Wattributes, "%qE attribute ignored", - get_attribute_name (t)); -} - -/* Warn for standard attributes being applied to a type that is not - being defined, where that is a constraint violation, and return a - list of attributes with them removed. */ - -tree -c_warn_type_attributes (tree attrs) -{ - tree *attr_ptr = &attrs; - while (*attr_ptr) - if (get_attribute_namespace (*attr_ptr) == NULL_TREE) - { - pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", - get_attribute_name (*attr_ptr)); - *attr_ptr = TREE_CHAIN (*attr_ptr); - } - else - attr_ptr = &TREE_CHAIN (*attr_ptr); - return attrs; -} - -/* Called when a declaration is seen that contains no names to declare. - If its type is a reference to a structure, union or enum inherited - from a containing scope, shadow that tag name for the current scope - with a forward reference. - If its type defines a new named structure or union - or defines an enum, it is valid but we need not do anything here. - Otherwise, it is an error. */ - -void -shadow_tag (const struct c_declspecs *declspecs) -{ - shadow_tag_warned (declspecs, 0); -} - -/* WARNED is 1 if we have done a pedwarn, 2 if we have done a warning, - but no pedwarn. */ -void -shadow_tag_warned (const struct c_declspecs *declspecs, int warned) -{ - bool found_tag = false; - - if (declspecs->type && !declspecs->default_int_p && !declspecs->typedef_p) - { - tree value = declspecs->type; - enum tree_code code = TREE_CODE (value); - - if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) - /* Used to test also that TYPE_SIZE (value) != 0. - That caused warning for `struct foo;' at top level in the file. */ - { - tree name = TYPE_NAME (value); - tree t; - - found_tag = true; - - if (declspecs->restrict_p) - { - error ("invalid use of %"); - warned = 1; - } - - if (name == NULL_TREE) - { - if (warned != 1 && code != ENUMERAL_TYPE) - /* Empty unnamed enum OK */ - { - pedwarn (input_location, 0, - "unnamed struct/union that defines no instances"); - warned = 1; - } - } - else if (declspecs->typespec_kind != ctsk_tagdef - && declspecs->typespec_kind != ctsk_tagfirstref - && declspecs->typespec_kind != ctsk_tagfirstref_attrs - && declspecs->storage_class != csc_none) - { - if (warned != 1) - pedwarn (input_location, 0, - "empty declaration with storage class specifier " - "does not redeclare tag"); - warned = 1; - pending_xref_error (); - } - else if (declspecs->typespec_kind != ctsk_tagdef - && declspecs->typespec_kind != ctsk_tagfirstref - && declspecs->typespec_kind != ctsk_tagfirstref_attrs - && (declspecs->const_p - || declspecs->volatile_p - || declspecs->atomic_p - || declspecs->restrict_p - || declspecs->address_space)) - { - if (warned != 1) - pedwarn (input_location, 0, - "empty declaration with type qualifier " - "does not redeclare tag"); - warned = 1; - pending_xref_error (); - } - else if (declspecs->typespec_kind != ctsk_tagdef - && declspecs->typespec_kind != ctsk_tagfirstref - && declspecs->typespec_kind != ctsk_tagfirstref_attrs - && declspecs->alignas_p) - { - if (warned != 1) - pedwarn (input_location, 0, - "empty declaration with %<_Alignas%> " - "does not redeclare tag"); - warned = 1; - pending_xref_error (); - } - else - { - pending_invalid_xref = NULL_TREE; - t = lookup_tag (code, name, true, NULL); - - if (t == NULL_TREE) - { - t = make_node (code); - pushtag (input_location, name, t); - } - } - } - else - { - if (warned != 1 && !in_system_header_at (input_location)) - { - pedwarn (input_location, 0, - "useless type name in empty declaration"); - warned = 1; - } - } - } - else if (warned != 1 && !in_system_header_at (input_location) - && declspecs->typedef_p) - { - pedwarn (input_location, 0, "useless type name in empty declaration"); - warned = 1; - } - - pending_invalid_xref = NULL_TREE; - - if (declspecs->inline_p) - { - error ("% in empty declaration"); - warned = 1; - } - - if (declspecs->noreturn_p) - { - error ("%<_Noreturn%> in empty declaration"); - warned = 1; - } - - if (current_scope == file_scope && declspecs->storage_class == csc_auto) - { - error ("% in file-scope empty declaration"); - warned = 1; - } - - if (current_scope == file_scope && declspecs->storage_class == csc_register) - { - error ("% in file-scope empty declaration"); - warned = 1; - } - - if (!warned && !in_system_header_at (input_location) - && declspecs->storage_class != csc_none) - { - warning (0, "useless storage class specifier in empty declaration"); - warned = 2; - } - - if (!warned && !in_system_header_at (input_location) && declspecs->thread_p) - { - warning (0, "useless %qs in empty declaration", - declspecs->thread_gnu_p ? "__thread" : "_Thread_local"); - warned = 2; - } - - if (!warned - && !in_system_header_at (input_location) - && (declspecs->const_p - || declspecs->volatile_p - || declspecs->atomic_p - || declspecs->restrict_p - || declspecs->address_space)) - { - warning (0, "useless type qualifier in empty declaration"); - warned = 2; - } - - if (!warned && !in_system_header_at (input_location) - && declspecs->alignas_p) - { - warning (0, "useless %<_Alignas%> in empty declaration"); - warned = 2; - } - - if (found_tag - && warned == 2 - && (declspecs->typespec_kind == ctsk_tagref_attrs - || declspecs->typespec_kind == ctsk_tagfirstref_attrs)) - { - /* Standard attributes after the "struct" or "union" keyword are - only permitted when the contents of the type are defined, or - in the form "struct-or-union attribute-specifier-sequence - identifier;". If the ';' was not present, attributes were - diagnosed in the parser. Here, ensure that any other useless - elements of the declaration result in a pedwarn, not just a - warning. Forward declarations of enum types are not part of - standard C, but handle them the same. */ - pedwarn (input_location, 0, - "invalid use of attributes in empty declaration"); - warned = 1; - } - - if (warned != 1) - { - if (declspecs->declspecs_seen_p - && !declspecs->non_std_attrs_seen_p) - /* An attribute declaration (but not a fallthrough attribute - declaration, which was handled separately); warn if there - are any attributes being ignored (but not if the attributes - were empty). */ - c_warn_unused_attributes (declspecs->attrs); - else if (!found_tag) - pedwarn (input_location, 0, "empty declaration"); - } -} - - -/* Return the qualifiers from SPECS as a bitwise OR of TYPE_QUAL_* - bits. SPECS represents declaration specifiers that the grammar - only permits to contain type qualifiers and attributes. */ - -int -quals_from_declspecs (const struct c_declspecs *specs) -{ - int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0) - | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0) - | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0) - | (specs->atomic_p ? TYPE_QUAL_ATOMIC : 0) - | (ENCODE_QUAL_ADDR_SPACE (specs->address_space))); - gcc_assert (!specs->type - && !specs->decl_attr - && specs->typespec_word == cts_none - && specs->storage_class == csc_none - && !specs->typedef_p - && !specs->explicit_signed_p - && !specs->deprecated_p - && !specs->unavailable_p - && !specs->long_p - && !specs->long_long_p - && !specs->short_p - && !specs->signed_p - && !specs->unsigned_p - && !specs->complex_p - && !specs->inline_p - && !specs->noreturn_p - && !specs->thread_p); - return quals; -} - -/* Construct an array declarator. LOC is the location of the - beginning of the array (usually the opening brace). EXPR is the - expression inside [], or NULL_TREE. QUALS are the type qualifiers - inside the [] (to be applied to the pointer to which a parameter - array is converted). STATIC_P is true if "static" is inside the - [], false otherwise. VLA_UNSPEC_P is true if the array is [*], a - VLA of unspecified length which is nevertheless a complete type, - false otherwise. The field for the contained declarator is left to - be filled in by set_array_declarator_inner. */ - -struct c_declarator * -build_array_declarator (location_t loc, - tree expr, struct c_declspecs *quals, bool static_p, - bool vla_unspec_p) -{ - struct c_declarator *declarator = XOBNEW (&parser_obstack, - struct c_declarator); - declarator->id_loc = loc; - declarator->kind = cdk_array; - declarator->declarator = 0; - declarator->u.array.dimen = expr; - if (quals) - { - declarator->u.array.attrs = quals->attrs; - declarator->u.array.quals = quals_from_declspecs (quals); - } - else - { - declarator->u.array.attrs = NULL_TREE; - declarator->u.array.quals = 0; - } - declarator->u.array.static_p = static_p; - declarator->u.array.vla_unspec_p = vla_unspec_p; - if (static_p || quals != NULL) - pedwarn_c90 (loc, OPT_Wpedantic, - "ISO C90 does not support % or type " - "qualifiers in parameter array declarators"); - if (vla_unspec_p) - pedwarn_c90 (loc, OPT_Wpedantic, - "ISO C90 does not support %<[*]%> array declarators"); - if (vla_unspec_p) - { - if (!current_scope->parm_flag) - { - /* C99 6.7.5.2p4 */ - error_at (loc, "%<[*]%> not allowed in other than " - "function prototype scope"); - declarator->u.array.vla_unspec_p = false; - return NULL; - } - current_scope->had_vla_unspec = true; - } - return declarator; -} - -/* Set the contained declarator of an array declarator. DECL is the - declarator, as constructed by build_array_declarator; INNER is what - appears on the left of the []. */ - -struct c_declarator * -set_array_declarator_inner (struct c_declarator *decl, - struct c_declarator *inner) -{ - decl->declarator = inner; - return decl; -} - -/* INIT is a constructor that forms DECL's initializer. If the final - element initializes a flexible array field, add the size of that - initializer to DECL's size. */ - -static void -add_flexible_array_elts_to_size (tree decl, tree init) -{ - tree elt, type; - - if (vec_safe_is_empty (CONSTRUCTOR_ELTS (init))) - return; - - elt = CONSTRUCTOR_ELTS (init)->last ().value; - type = TREE_TYPE (elt); - if (TREE_CODE (type) == ARRAY_TYPE - && TYPE_SIZE (type) == NULL_TREE - && TYPE_DOMAIN (type) != NULL_TREE - && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE) - { - complete_array_type (&type, elt, false); - DECL_SIZE (decl) - = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type)); - DECL_SIZE_UNIT (decl) - = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type)); - } -} - -/* Decode a "typename", such as "int **", returning a ..._TYPE node. - Set *EXPR, if EXPR not NULL, to any expression to be evaluated - before the type name, and set *EXPR_CONST_OPERANDS, if - EXPR_CONST_OPERANDS not NULL, to indicate whether the type name may - appear in a constant expression. */ - -tree -groktypename (struct c_type_name *type_name, tree *expr, - bool *expr_const_operands) -{ - tree type; - tree attrs = type_name->specs->attrs; - - type_name->specs->attrs = NULL_TREE; - - type = grokdeclarator (type_name->declarator, type_name->specs, TYPENAME, - false, NULL, &attrs, expr, expr_const_operands, - DEPRECATED_NORMAL); - - /* Apply attributes. */ - attrs = c_warn_type_attributes (attrs); - decl_attributes (&type, attrs, 0); - - return type; -} - -/* Looks up the most recent pushed declaration corresponding to DECL. */ - -static tree -lookup_last_decl (tree decl) -{ - tree last_decl = lookup_name (DECL_NAME (decl)); - if (!last_decl) - last_decl = lookup_name_in_scope (DECL_NAME (decl), external_scope); - return last_decl; -} - -/* Wrapper for decl_attributes that adds some implicit attributes - to VAR_DECLs or FUNCTION_DECLs. */ - -static tree -c_decl_attributes (tree *node, tree attributes, int flags) -{ - /* Add implicit "omp declare target" attribute if requested. */ - if (current_omp_declare_target_attribute - && ((VAR_P (*node) && is_global_var (*node)) - || TREE_CODE (*node) == FUNCTION_DECL)) - { - if (VAR_P (*node) - && !lang_hooks.types.omp_mappable_type (TREE_TYPE (*node))) - attributes = tree_cons (get_identifier ("omp declare target implicit"), - NULL_TREE, attributes); - else - { - attributes = tree_cons (get_identifier ("omp declare target"), - NULL_TREE, attributes); - attributes = tree_cons (get_identifier ("omp declare target block"), - NULL_TREE, attributes); - } - } - - /* Look up the current declaration with all the attributes merged - so far so that attributes on the current declaration that's - about to be pushed that conflict with the former can be detected, - diagnosed, and rejected as appropriate. */ - tree last_decl = lookup_last_decl (*node); - return decl_attributes (node, attributes, flags, last_decl); -} - - -/* Decode a declarator in an ordinary declaration or data definition. - This is called as soon as the type information and variable name - have been parsed, before parsing the initializer if any. - Here we create the ..._DECL node, fill in its type, - and put it on the list of decls for the current context. - When nonnull, set *LASTLOC to the location of the prior declaration - of the same entity if one exists. - The ..._DECL node is returned as the value. - - Exception: for arrays where the length is not specified, - the type is left null, to be filled in by `finish_decl'. - - Function definitions do not come here; they go to start_function - instead. However, external and forward declarations of functions - do go through here. Structure field declarations are done by - grokfield and not through here. */ - -tree -start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, - bool initialized, tree attributes, location_t *lastloc /* = NULL */) -{ - tree decl; - tree tem; - tree expr = NULL_TREE; - enum deprecated_states deprecated_state = DEPRECATED_NORMAL; - - /* An object declared as __attribute__((unavailable)) suppresses - warnings and errors from __attribute__((deprecated/unavailable)) - components. - An object declared as __attribute__((deprecated)) suppresses - warnings of uses of other deprecated items. */ - if (lookup_attribute ("unavailable", attributes)) - deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS; - else if (lookup_attribute ("deprecated", attributes)) - deprecated_state = DEPRECATED_SUPPRESS; - - decl = grokdeclarator (declarator, declspecs, - NORMAL, initialized, NULL, &attributes, &expr, NULL, - deprecated_state); - if (!decl || decl == error_mark_node) - return NULL_TREE; - - if (tree lastdecl = lastloc ? lookup_last_decl (decl) : NULL_TREE) - if (lastdecl != error_mark_node) - *lastloc = DECL_SOURCE_LOCATION (lastdecl); - - if (expr) - add_stmt (fold_convert (void_type_node, expr)); - - if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl)) - && TREE_PUBLIC (decl)) - warning (OPT_Wmain, "%q+D is usually a function", decl); - - if (initialized) - /* Is it valid for this decl to have an initializer at all? - If not, set INITIALIZED to zero, which will indirectly - tell 'finish_decl' to ignore the initializer once it is parsed. */ - switch (TREE_CODE (decl)) - { - case TYPE_DECL: - error ("typedef %qD is initialized (use %<__typeof__%> instead)", decl); - initialized = false; - break; - - case FUNCTION_DECL: - error ("function %qD is initialized like a variable", decl); - initialized = false; - break; - - case PARM_DECL: - /* DECL_INITIAL in a PARM_DECL is really DECL_ARG_TYPE. */ - error ("parameter %qD is initialized", decl); - initialized = false; - break; - - default: - /* Don't allow initializations for incomplete types except for - arrays which might be completed by the initialization. */ - - /* This can happen if the array size is an undefined macro. - We already gave a warning, so we don't need another one. */ - if (TREE_TYPE (decl) == error_mark_node) - initialized = false; - else if (COMPLETE_TYPE_P (TREE_TYPE (decl))) - { - /* A complete type is ok if size is fixed. */ - - if (!poly_int_tree_p (TYPE_SIZE (TREE_TYPE (decl))) - || C_DECL_VARIABLE_SIZE (decl)) - { - error ("variable-sized object may not be initialized"); - initialized = false; - } - } - else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) - { - error ("variable %qD has initializer but incomplete type", decl); - initialized = false; - } - else if (C_DECL_VARIABLE_SIZE (decl)) - { - /* Although C99 is unclear about whether incomplete arrays - of VLAs themselves count as VLAs, it does not make - sense to permit them to be initialized given that - ordinary VLAs may not be initialized. */ - error ("variable-sized object may not be initialized"); - initialized = false; - } - } - - if (initialized) - { - if (current_scope == file_scope) - TREE_STATIC (decl) = 1; - - /* Tell 'pushdecl' this is an initialized decl - even though we don't yet have the initializer expression. - Also tell 'finish_decl' it may store the real initializer. */ - DECL_INITIAL (decl) = error_mark_node; - } - - /* If this is a function declaration, write a record describing it to the - prototypes file (if requested). */ - - if (TREE_CODE (decl) == FUNCTION_DECL) - gen_aux_info_record (decl, 0, 0, prototype_p (TREE_TYPE (decl))); - - /* ANSI specifies that a tentative definition which is not merged with - a non-tentative definition behaves exactly like a definition with an - initializer equal to zero. (Section 3.7.2) - - -fno-common gives strict ANSI behavior, though this tends to break - a large body of code that grew up without this rule. - - Thread-local variables are never common, since there's no entrenched - body of code to break, and it allows more efficient variable references - in the presence of dynamic linking. */ - - if (VAR_P (decl) - && !initialized - && TREE_PUBLIC (decl) - && !DECL_THREAD_LOCAL_P (decl) - && !flag_no_common) - DECL_COMMON (decl) = 1; - - /* Set attributes here so if duplicate decl, will have proper attributes. */ - c_decl_attributes (&decl, attributes, 0); - - /* Handle gnu_inline attribute. */ - if (declspecs->inline_p - && !flag_gnu89_inline - && TREE_CODE (decl) == FUNCTION_DECL - && (lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl)) - || current_function_decl)) - { - if (declspecs->storage_class == csc_auto && current_scope != file_scope) - ; - else if (declspecs->storage_class != csc_static) - DECL_EXTERNAL (decl) = !DECL_EXTERNAL (decl); - } - - if (TREE_CODE (decl) == FUNCTION_DECL - && targetm.calls.promote_prototypes (TREE_TYPE (decl))) - { - struct c_declarator *ce = declarator; - - if (ce->kind == cdk_pointer) - ce = declarator->declarator; - if (ce->kind == cdk_function) - { - tree args = ce->u.arg_info->parms; - for (; args; args = DECL_CHAIN (args)) - { - tree type = TREE_TYPE (args); - if (type && INTEGRAL_TYPE_P (type) - && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) - DECL_ARG_TYPE (args) = c_type_promotes_to (type); - } - } - } - - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_DECLARED_INLINE_P (decl) - && DECL_UNINLINABLE (decl) - && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl))) - warning (OPT_Wattributes, "inline function %q+D given attribute %qs", - decl, "noinline"); - - /* C99 6.7.4p3: An inline definition of a function with external - linkage shall not contain a definition of a modifiable object - with static storage duration... */ - if (VAR_P (decl) - && current_scope != file_scope - && TREE_STATIC (decl) - && !TREE_READONLY (decl) - && DECL_DECLARED_INLINE_P (current_function_decl) - && DECL_EXTERNAL (current_function_decl)) - record_inline_static (input_location, current_function_decl, - decl, csi_modifiable); - - if (c_dialect_objc () - && VAR_OR_FUNCTION_DECL_P (decl)) - objc_check_global_decl (decl); - - /* Add this decl to the current scope. - TEM may equal DECL or it may be a previous decl of the same name. */ - tem = pushdecl (decl); - - if (initialized && DECL_EXTERNAL (tem)) - { - DECL_EXTERNAL (tem) = 0; - TREE_STATIC (tem) = 1; - } - - return tem; -} - -/* Subroutine of finish_decl. TYPE is the type of an uninitialized object - DECL or the non-array element type if DECL is an uninitialized array. - If that type has a const member, diagnose this. */ - -static void -diagnose_uninitialized_cst_member (tree decl, tree type) -{ - tree field; - for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) - { - tree field_type; - if (TREE_CODE (field) != FIELD_DECL) - continue; - field_type = strip_array_types (TREE_TYPE (field)); - - if (TYPE_QUALS (field_type) & TYPE_QUAL_CONST) - { - warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, - "uninitialized const member in %qT is invalid in C++", - strip_array_types (TREE_TYPE (decl))); - inform (DECL_SOURCE_LOCATION (field), "%qD should be initialized", field); - } - - if (RECORD_OR_UNION_TYPE_P (field_type)) - diagnose_uninitialized_cst_member (decl, field_type); - } -} - -/* Finish processing of a declaration; - install its initial value. - If ORIGTYPE is not NULL_TREE, it is the original type of INIT. - If the length of an array type is not known before, - it must be determined now, from the initial value, or it is an error. - - INIT_LOC is the location of the initial value. */ - -void -finish_decl (tree decl, location_t init_loc, tree init, - tree origtype, tree asmspec_tree) -{ - tree type; - bool was_incomplete = (DECL_SIZE (decl) == NULL_TREE); - const char *asmspec = 0; - - /* If a name was specified, get the string. */ - if (VAR_OR_FUNCTION_DECL_P (decl) - && DECL_FILE_SCOPE_P (decl)) - asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree); - if (asmspec_tree) - asmspec = TREE_STRING_POINTER (asmspec_tree); - - if (VAR_P (decl) - && TREE_STATIC (decl) - && global_bindings_p ()) - /* So decl is a global variable. Record the types it uses - so that we can decide later to emit debug info for them. */ - record_types_used_by_current_var_decl (decl); - - /* If `start_decl' didn't like having an initialization, ignore it now. */ - if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE) - init = NULL_TREE; - - /* Don't crash if parm is initialized. */ - if (TREE_CODE (decl) == PARM_DECL) - init = NULL_TREE; - - if (init) - store_init_value (init_loc, decl, init, origtype); - - if (c_dialect_objc () && (VAR_OR_FUNCTION_DECL_P (decl) - || TREE_CODE (decl) == FIELD_DECL)) - objc_check_decl (decl); - - type = TREE_TYPE (decl); - - /* Deduce size of array from initialization, if not already known. - This is only needed for an initialization in the current scope; - it must not be done for a file-scope initialization of a - declaration with external linkage, redeclared in an inner scope - with the outer declaration shadowed in an intermediate scope. */ - if (TREE_CODE (type) == ARRAY_TYPE - && TYPE_DOMAIN (type) == NULL_TREE - && TREE_CODE (decl) != TYPE_DECL - && !(TREE_PUBLIC (decl) && current_scope != file_scope)) - { - bool do_default - = (TREE_STATIC (decl) - /* Even if pedantic, an external linkage array - may have incomplete type at first. */ - ? pedantic && !TREE_PUBLIC (decl) - : !DECL_EXTERNAL (decl)); - int failure - = complete_array_type (&TREE_TYPE (decl), DECL_INITIAL (decl), - do_default); - - /* Get the completed type made by complete_array_type. */ - type = TREE_TYPE (decl); - - switch (failure) - { - case 1: - error ("initializer fails to determine size of %q+D", decl); - break; - - case 2: - if (do_default) - error ("array size missing in %q+D", decl); - break; - - case 3: - error ("zero or negative size array %q+D", decl); - break; - - case 0: - /* For global variables, update the copy of the type that - exists in the binding. */ - if (TREE_PUBLIC (decl)) - { - struct c_binding *b_ext = I_SYMBOL_BINDING (DECL_NAME (decl)); - while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext)) - b_ext = b_ext->shadowed; - if (b_ext && TREE_CODE (decl) == TREE_CODE (b_ext->decl)) - { - if (b_ext->u.type && comptypes (b_ext->u.type, type)) - b_ext->u.type = composite_type (b_ext->u.type, type); - else - b_ext->u.type = type; - } - } - break; - - default: - gcc_unreachable (); - } - - if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node) - TREE_TYPE (DECL_INITIAL (decl)) = type; - - relayout_decl (decl); - } - - /* Look for braced array initializers for character arrays and - recursively convert them into STRING_CSTs. */ - if (tree init = DECL_INITIAL (decl)) - DECL_INITIAL (decl) = braced_lists_to_strings (type, init); - - if (VAR_P (decl)) - { - if (init && TREE_CODE (init) == CONSTRUCTOR) - add_flexible_array_elts_to_size (decl, init); - - complete_flexible_array_elts (DECL_INITIAL (decl)); - - if (is_global_var (decl)) - { - type_context_kind context = (DECL_THREAD_LOCAL_P (decl) - ? TCTX_THREAD_STORAGE - : TCTX_STATIC_STORAGE); - if (!verify_type_context (input_location, context, TREE_TYPE (decl))) - TREE_TYPE (decl) = error_mark_node; - } - - if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node - && COMPLETE_TYPE_P (TREE_TYPE (decl))) - layout_decl (decl, 0); - - if (DECL_SIZE (decl) == NULL_TREE - /* Don't give an error if we already gave one earlier. */ - && TREE_TYPE (decl) != error_mark_node - && (TREE_STATIC (decl) - /* A static variable with an incomplete type - is an error if it is initialized. - Also if it is not file scope. - Otherwise, let it through, but if it is not `extern' - then it may cause an error message later. */ - ? (DECL_INITIAL (decl) != NULL_TREE - || !DECL_FILE_SCOPE_P (decl)) - /* An automatic variable with an incomplete type - is an error. */ - : !DECL_EXTERNAL (decl))) - { - error ("storage size of %q+D isn%'t known", decl); - TREE_TYPE (decl) = error_mark_node; - } - - if ((RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)) - || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) - && DECL_SIZE (decl) == NULL_TREE - && TREE_STATIC (decl)) - incomplete_record_decls.safe_push (decl); - - if (is_global_var (decl) - && DECL_SIZE (decl) != NULL_TREE - && TREE_TYPE (decl) != error_mark_node) - { - if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) - constant_expression_warning (DECL_SIZE (decl)); - else - { - error ("storage size of %q+D isn%'t constant", decl); - TREE_TYPE (decl) = error_mark_node; - } - } - - if (TREE_USED (type)) - { - TREE_USED (decl) = 1; - DECL_READ_P (decl) = 1; - } - } - - /* If this is a function and an assembler name is specified, reset DECL_RTL - so we can give it its new name. Also, update builtin_decl if it - was a normal built-in. */ - if (TREE_CODE (decl) == FUNCTION_DECL && asmspec) - { - if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL) - set_builtin_user_assembler_name (decl, asmspec); - set_user_assembler_name (decl, asmspec); - } - - /* If #pragma weak was used, mark the decl weak now. */ - maybe_apply_pragma_weak (decl); - - /* Output the assembler code and/or RTL code for variables and functions, - unless the type is an undefined structure or union. - If not, it will get done when the type is completed. */ - - if (VAR_OR_FUNCTION_DECL_P (decl)) - { - /* Determine the ELF visibility. */ - if (TREE_PUBLIC (decl)) - c_determine_visibility (decl); - - /* This is a no-op in c-lang.c or something real in objc-act.c. */ - if (c_dialect_objc ()) - objc_check_decl (decl); - - if (asmspec) - { - /* If this is not a static variable, issue a warning. - It doesn't make any sense to give an ASMSPEC for an - ordinary, non-register local variable. Historically, - GCC has accepted -- but ignored -- the ASMSPEC in - this case. */ - if (!DECL_FILE_SCOPE_P (decl) - && VAR_P (decl) - && !C_DECL_REGISTER (decl) - && !TREE_STATIC (decl)) - warning (0, "ignoring % specifier for non-static local " - "variable %q+D", decl); - else - set_user_assembler_name (decl, asmspec); - } - - if (DECL_FILE_SCOPE_P (decl)) - { - if (DECL_INITIAL (decl) == NULL_TREE - || DECL_INITIAL (decl) == error_mark_node) - /* Don't output anything - when a tentative file-scope definition is seen. - But at end of compilation, do output code for them. */ - DECL_DEFER_OUTPUT (decl) = 1; - if (asmspec && VAR_P (decl) && C_DECL_REGISTER (decl)) - DECL_HARD_REGISTER (decl) = 1; - rest_of_decl_compilation (decl, true, 0); - - if (TREE_CODE (decl) == FUNCTION_DECL) - { - tree parms = DECL_ARGUMENTS (decl); - const bool builtin = fndecl_built_in_p (decl); - if (tree access = build_attr_access_from_parms (parms, !builtin)) - decl_attributes (&decl, access, 0); - } - } - else - { - /* In conjunction with an ASMSPEC, the `register' - keyword indicates that we should place the variable - in a particular register. */ - if (asmspec && C_DECL_REGISTER (decl)) - { - DECL_HARD_REGISTER (decl) = 1; - /* This cannot be done for a structure with volatile - fields, on which DECL_REGISTER will have been - reset. */ - if (!DECL_REGISTER (decl)) - error ("cannot put object with volatile field into register"); - } - - if (TREE_CODE (decl) != FUNCTION_DECL) - { - /* If we're building a variable sized type, and we might be - reachable other than via the top of the current binding - level, then create a new BIND_EXPR so that we deallocate - the object at the right time. */ - /* Note that DECL_SIZE can be null due to errors. */ - if (DECL_SIZE (decl) - && !TREE_CONSTANT (DECL_SIZE (decl)) - && STATEMENT_LIST_HAS_LABEL (cur_stmt_list)) - { - tree bind; - bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); - TREE_SIDE_EFFECTS (bind) = 1; - add_stmt (bind); - BIND_EXPR_BODY (bind) = push_stmt_list (); - } - add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), - DECL_EXPR, decl)); - } - } - - - if (!DECL_FILE_SCOPE_P (decl)) - { - /* Recompute the RTL of a local array now - if it used to be an incomplete type. */ - if (was_incomplete && !is_global_var (decl)) - { - /* If we used it already as memory, it must stay in memory. */ - TREE_ADDRESSABLE (decl) = TREE_USED (decl); - /* If it's still incomplete now, no init will save it. */ - if (DECL_SIZE (decl) == NULL_TREE) - DECL_INITIAL (decl) = NULL_TREE; - } - } - } - - if (TREE_CODE (decl) == TYPE_DECL) - { - if (!DECL_FILE_SCOPE_P (decl) - && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) - add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); - - rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0); - } - - /* Install a cleanup (aka destructor) if one was given. */ - if (VAR_P (decl) && !TREE_STATIC (decl)) - { - tree attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl)); - if (attr) - { - tree cleanup_id = TREE_VALUE (TREE_VALUE (attr)); - tree cleanup_decl = lookup_name (cleanup_id); - tree cleanup; - vec *v; - - /* Build "cleanup(&decl)" for the destructor. */ - cleanup = build_unary_op (input_location, ADDR_EXPR, decl, false); - vec_alloc (v, 1); - v->quick_push (cleanup); - cleanup = c_build_function_call_vec (DECL_SOURCE_LOCATION (decl), - vNULL, cleanup_decl, v, NULL); - vec_free (v); - - /* Don't warn about decl unused; the cleanup uses it. */ - TREE_USED (decl) = 1; - TREE_USED (cleanup_decl) = 1; - DECL_READ_P (decl) = 1; - - push_cleanup (decl, cleanup, false); - } - } - - if (warn_cxx_compat - && VAR_P (decl) - && !DECL_EXTERNAL (decl) - && DECL_INITIAL (decl) == NULL_TREE) - { - type = strip_array_types (type); - if (TREE_READONLY (decl)) - warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, - "uninitialized % is invalid in C++", decl); - else if (RECORD_OR_UNION_TYPE_P (type) - && C_TYPE_FIELDS_READONLY (type)) - diagnose_uninitialized_cst_member (decl, type); - } - - if (flag_openmp - && VAR_P (decl) - && lookup_attribute ("omp declare target implicit", - DECL_ATTRIBUTES (decl))) - { - DECL_ATTRIBUTES (decl) - = remove_attribute ("omp declare target implicit", - DECL_ATTRIBUTES (decl)); - if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (decl))) - error ("%q+D in declare target directive does not have mappable type", - decl); - else if (!lookup_attribute ("omp declare target", - DECL_ATTRIBUTES (decl)) - && !lookup_attribute ("omp declare target link", - DECL_ATTRIBUTES (decl))) - { - DECL_ATTRIBUTES (decl) - = tree_cons (get_identifier ("omp declare target"), - NULL_TREE, DECL_ATTRIBUTES (decl)); - symtab_node *node = symtab_node::get (decl); - if (node != NULL) - { - node->offloadable = 1; - if (ENABLE_OFFLOADING) - { - g->have_offload = true; - if (is_a (node)) - vec_safe_push (offload_vars, decl); - } - } - } - } - - /* This is the last point we can lower alignment so give the target the - chance to do so. */ - if (VAR_P (decl) - && !is_global_var (decl) - && !DECL_HARD_REGISTER (decl)) - targetm.lower_local_decl_alignment (decl); - - invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); -} - -/* Given a parsed parameter declaration, decode it into a PARM_DECL. - EXPR is NULL or a pointer to an expression that needs to be - evaluated for the side effects of array size expressions in the - parameters. */ - -tree -grokparm (const struct c_parm *parm, tree *expr) -{ - tree attrs = parm->attrs; - tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, - NULL, &attrs, expr, NULL, DEPRECATED_NORMAL); - - decl_attributes (&decl, attrs, 0); - - return decl; -} - -/* Return attribute "arg spec" corresponding to an array/VLA parameter - described by PARM, concatenated onto attributes ATTRS. - The spec consists of one dollar symbol for each specified variable - bound, one asterisk for each unspecified variable bound, followed - by at most one specification of the most significant bound of - an ordinary array parameter. For ordinary arrays the specification - is either the constant bound itself, or the space character for - an array with an unspecified bound (the [] form). Finally, a chain - of specified variable bounds is appended to the spec, starting with - the most significant bound. For example, the PARM T a[2][m][3][n] - will produce __attribute__((arg spec ("[$$2]", m, n)). - For T a typedef for an array with variable bounds, the bounds are - included in the specification in the expected order. - No "arg spec" is created for parameters of pointer types, making - a distinction between T(*)[N] (or, equivalently, T[][N]) and - the T[M][N] form, all of which have the same type and are represented - the same, but only the last of which gets an "arg spec" describing - the most significant bound M. */ - -static tree -get_parm_array_spec (const struct c_parm *parm, tree attrs) -{ - /* The attribute specification string, minor bound first. */ - std::string spec; - - /* A list of VLA variable bounds, major first, or null if unspecified - or not a VLA. */ - tree vbchain = NULL_TREE; - /* True for a pointer parameter. */ - bool pointer = false; - /* True for an ordinary array with an unpecified bound. */ - bool nobound = false; - - /* Create a string representation for the bounds of the array/VLA. */ - for (c_declarator *pd = parm->declarator, *next; pd; pd = next) - { - next = pd->declarator; - while (next && next->kind == cdk_attrs) - next = next->declarator; - - /* Remember if a pointer has been seen to avoid storing the constant - bound. */ - if (pd->kind == cdk_pointer) - pointer = true; - - if ((pd->kind == cdk_pointer || pd->kind == cdk_function) - && (!next || next->kind == cdk_id)) - { - /* Do nothing for the common case of a pointer. The fact that - the parameter is one can be deduced from the absence of - an arg spec for it. */ - return attrs; - } - - if (pd->kind == cdk_id) - { - if (pointer - || !parm->specs->type - || TREE_CODE (parm->specs->type) != ARRAY_TYPE - || !TYPE_DOMAIN (parm->specs->type) - || !TYPE_MAX_VALUE (TYPE_DOMAIN (parm->specs->type))) - continue; - - tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (parm->specs->type)); - if (!vbchain - && TREE_CODE (max) == INTEGER_CST) - { - /* Extract the upper bound from a parameter of an array type - unless the parameter is an ordinary array of unspecified - bound in which case a next iteration of the loop will - exit. */ - if (spec.empty () || spec.end ()[-1] != ' ') - { - if (!tree_fits_shwi_p (max)) - continue; - - /* The upper bound is the value of the largest valid - index. */ - HOST_WIDE_INT n = tree_to_shwi (max) + 1; - char buf[40]; - sprintf (buf, "%lu", (unsigned long)n); - spec += buf; - } - continue; - } - - /* For a VLA typedef, create a list of its variable bounds and - append it in the expected order to VBCHAIN. */ - tree tpbnds = NULL_TREE; - for (tree type = parm->specs->type; TREE_CODE (type) == ARRAY_TYPE; - type = TREE_TYPE (type)) - { - tree nelts = array_type_nelts (type); - if (error_operand_p (nelts)) - return attrs; - if (TREE_CODE (nelts) != INTEGER_CST) - { - /* Each variable VLA bound is represented by the dollar - sign. */ - spec += "$"; - tpbnds = tree_cons (NULL_TREE, nelts, tpbnds); - } - } - tpbnds = nreverse (tpbnds); - vbchain = chainon (vbchain, tpbnds); - continue; - } - - if (pd->kind != cdk_array) - continue; - - if (pd->u.array.vla_unspec_p) - { - /* Each unspecified bound is represented by a star. There - can be any number of these in a declaration (but none in - a definition). */ - spec += '*'; - continue; - } - - tree nelts = pd->u.array.dimen; - if (!nelts) - { - /* Ordinary array of unspecified size. There can be at most - one for the most significant bound. Exit on the next - iteration which determines whether or not PARM is declared - as a pointer or an array. */ - nobound = true; - continue; - } - - if (pd->u.array.static_p) - spec += 's'; - - if (!INTEGRAL_TYPE_P (TREE_TYPE (nelts))) - /* Avoid invalid NELTS. */ - return attrs; - - STRIP_NOPS (nelts); - nelts = c_fully_fold (nelts, false, nullptr); - if (TREE_CODE (nelts) == INTEGER_CST) - { - /* Skip all constant bounds except the most significant one. - The interior ones are included in the array type. */ - if (next && (next->kind == cdk_array || next->kind == cdk_pointer)) - continue; - - if (!tree_fits_uhwi_p (nelts)) - /* Bail completely on invalid bounds. */ - return attrs; - - char buf[40]; - unsigned HOST_WIDE_INT n = tree_to_uhwi (nelts); - sprintf (buf, "%llu", (unsigned long long)n); - spec += buf; - break; - } - - /* Each variable VLA bound is represented by a dollar sign. */ - spec += "$"; - vbchain = tree_cons (NULL_TREE, nelts, vbchain); - } - - if (spec.empty () && !nobound) - return attrs; - - spec.insert (0, "["); - if (nobound) - /* Ordinary array of unspecified bound is represented by a space. - It must be last in the spec. */ - spec += ' '; - spec += ']'; - - tree acsstr = build_string (spec.length () + 1, spec.c_str ()); - tree args = tree_cons (NULL_TREE, acsstr, vbchain); - tree name = get_identifier ("arg spec"); - return tree_cons (name, args, attrs); -} - -/* Given a parsed parameter declaration, decode it into a PARM_DECL - and push that on the current scope. EXPR is a pointer to an - expression that needs to be evaluated for the side effects of array - size expressions in the parameters. */ - -void -push_parm_decl (const struct c_parm *parm, tree *expr) -{ - tree attrs = parm->attrs; - tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL, - &attrs, expr, NULL, DEPRECATED_NORMAL); - if (decl && DECL_P (decl)) - DECL_SOURCE_LOCATION (decl) = parm->loc; - - attrs = get_parm_array_spec (parm, attrs); - decl_attributes (&decl, attrs, 0); - - decl = pushdecl (decl); - - finish_decl (decl, input_location, NULL_TREE, NULL_TREE, NULL_TREE); -} - -/* Mark all the parameter declarations to date as forward decls. - Also diagnose use of this extension. */ - -void -mark_forward_parm_decls (void) -{ - struct c_binding *b; - - if (pedantic && !current_scope->warned_forward_parm_decls) - { - pedwarn (input_location, OPT_Wpedantic, - "ISO C forbids forward parameter declarations"); - current_scope->warned_forward_parm_decls = true; - } - - for (b = current_scope->bindings; b; b = b->prev) - if (TREE_CODE (b->decl) == PARM_DECL) - TREE_ASM_WRITTEN (b->decl) = 1; -} - -/* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound - literal, which may be an incomplete array type completed by the - initializer; INIT is a CONSTRUCTOR at LOC that initializes the compound - literal. NON_CONST is true if the initializers contain something - that cannot occur in a constant expression. If ALIGNAS_ALIGN is nonzero, - it is the (valid) alignment for this compound literal, as specified - with _Alignas. */ - -tree -build_compound_literal (location_t loc, tree type, tree init, bool non_const, - unsigned int alignas_align) -{ - /* We do not use start_decl here because we have a type, not a declarator; - and do not use finish_decl because the decl should be stored inside - the COMPOUND_LITERAL_EXPR rather than added elsewhere as a DECL_EXPR. */ - tree decl; - tree complit; - tree stmt; - - if (type == error_mark_node - || init == error_mark_node) - return error_mark_node; - - decl = build_decl (loc, VAR_DECL, NULL_TREE, type); - DECL_EXTERNAL (decl) = 0; - TREE_PUBLIC (decl) = 0; - TREE_STATIC (decl) = (current_scope == file_scope); - DECL_CONTEXT (decl) = current_function_decl; - TREE_USED (decl) = 1; - DECL_READ_P (decl) = 1; - DECL_ARTIFICIAL (decl) = 1; - DECL_IGNORED_P (decl) = 1; - C_DECL_COMPOUND_LITERAL_P (decl) = 1; - TREE_TYPE (decl) = type; - c_apply_type_quals_to_decl (TYPE_QUALS (strip_array_types (type)), decl); - if (alignas_align) - { - SET_DECL_ALIGN (decl, alignas_align * BITS_PER_UNIT); - DECL_USER_ALIGN (decl) = 1; - } - store_init_value (loc, decl, init, NULL_TREE); - - if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type)) - { - int failure = complete_array_type (&TREE_TYPE (decl), - DECL_INITIAL (decl), true); - /* If complete_array_type returns 3, it means that the - initial value of the compound literal is empty. Allow it. */ - gcc_assert (failure == 0 || failure == 3); - - type = TREE_TYPE (decl); - TREE_TYPE (DECL_INITIAL (decl)) = type; - } - - if (type == error_mark_node || !COMPLETE_TYPE_P (type)) - { - c_incomplete_type_error (loc, NULL_TREE, type); - return error_mark_node; - } - - if (TREE_STATIC (decl) - && !verify_type_context (loc, TCTX_STATIC_STORAGE, type)) - return error_mark_node; - - stmt = build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl); - complit = build1 (COMPOUND_LITERAL_EXPR, type, stmt); - TREE_SIDE_EFFECTS (complit) = 1; - - layout_decl (decl, 0); - - if (TREE_STATIC (decl)) - { - /* This decl needs a name for the assembler output. */ - set_compound_literal_name (decl); - DECL_DEFER_OUTPUT (decl) = 1; - DECL_COMDAT (decl) = 1; - pushdecl (decl); - rest_of_decl_compilation (decl, 1, 0); - } - else if (current_function_decl && !current_scope->parm_flag) - pushdecl (decl); - - if (non_const) - { - complit = build2 (C_MAYBE_CONST_EXPR, type, NULL, complit); - C_MAYBE_CONST_EXPR_NON_CONST (complit) = 1; - } - - return complit; -} - -/* Check the type of a compound literal. Here we just check that it - is valid for C++. */ - -void -check_compound_literal_type (location_t loc, struct c_type_name *type_name) -{ - if (warn_cxx_compat - && (type_name->specs->typespec_kind == ctsk_tagdef - || type_name->specs->typespec_kind == ctsk_tagfirstref - || type_name->specs->typespec_kind == ctsk_tagfirstref_attrs)) - warning_at (loc, OPT_Wc___compat, - "defining a type in a compound literal is invalid in C++"); -} - -/* Performs sanity checks on the TYPE and WIDTH of the bit-field NAME, - replacing with appropriate values if they are invalid. */ - -static void -check_bitfield_type_and_width (location_t loc, tree *type, tree *width, - tree orig_name) -{ - tree type_mv; - unsigned int max_width; - unsigned HOST_WIDE_INT w; - const char *name = (orig_name - ? identifier_to_locale (IDENTIFIER_POINTER (orig_name)) - : _("")); - - /* Detect and ignore out of range field width and process valid - field widths. */ - if (!INTEGRAL_TYPE_P (TREE_TYPE (*width))) - { - error_at (loc, "bit-field %qs width not an integer constant", name); - *width = integer_one_node; - } - else - { - if (TREE_CODE (*width) != INTEGER_CST) - { - *width = c_fully_fold (*width, false, NULL); - if (TREE_CODE (*width) == INTEGER_CST) - pedwarn (loc, OPT_Wpedantic, - "bit-field %qs width not an integer constant expression", - name); - } - if (TREE_CODE (*width) != INTEGER_CST) - { - error_at (loc, "bit-field %qs width not an integer constant", name); - *width = integer_one_node; - } - constant_expression_warning (*width); - if (tree_int_cst_sgn (*width) < 0) - { - error_at (loc, "negative width in bit-field %qs", name); - *width = integer_one_node; - } - else if (integer_zerop (*width) && orig_name) - { - error_at (loc, "zero width for bit-field %qs", name); - *width = integer_one_node; - } - } - - /* Detect invalid bit-field type. */ - if (TREE_CODE (*type) != INTEGER_TYPE - && TREE_CODE (*type) != BOOLEAN_TYPE - && TREE_CODE (*type) != ENUMERAL_TYPE) - { - error_at (loc, "bit-field %qs has invalid type", name); - *type = unsigned_type_node; - } - - if (TYPE_WARN_IF_NOT_ALIGN (*type)) - { - error_at (loc, "cannot declare bit-field %qs with % type", - name); - *type = unsigned_type_node; - } - - type_mv = TYPE_MAIN_VARIANT (*type); - if (!in_system_header_at (input_location) - && type_mv != integer_type_node - && type_mv != unsigned_type_node - && type_mv != boolean_type_node) - pedwarn_c90 (loc, OPT_Wpedantic, - "type of bit-field %qs is a GCC extension", name); - - max_width = TYPE_PRECISION (*type); - - if (compare_tree_int (*width, max_width) > 0) - { - error_at (loc, "width of %qs exceeds its type", name); - w = max_width; - *width = build_int_cst (integer_type_node, w); - } - else - w = tree_to_uhwi (*width); - - if (TREE_CODE (*type) == ENUMERAL_TYPE) - { - struct lang_type *lt = TYPE_LANG_SPECIFIC (*type); - if (!lt - || w < tree_int_cst_min_precision (lt->enum_min, TYPE_SIGN (*type)) - || w < tree_int_cst_min_precision (lt->enum_max, TYPE_SIGN (*type))) - warning_at (loc, 0, "%qs is narrower than values of its type", name); - } -} - - - -/* Print warning about variable length array if necessary. */ - -static void -warn_variable_length_array (tree name, tree size) -{ - if (TREE_CONSTANT (size)) - { - if (name) - pedwarn_c90 (input_location, OPT_Wvla, - "ISO C90 forbids array %qE whose size " - "cannot be evaluated", name); - else - pedwarn_c90 (input_location, OPT_Wvla, "ISO C90 forbids array " - "whose size cannot be evaluated"); - } - else - { - if (name) - pedwarn_c90 (input_location, OPT_Wvla, - "ISO C90 forbids variable length array %qE", name); - else - pedwarn_c90 (input_location, OPT_Wvla, "ISO C90 forbids variable " - "length array"); - } -} - -/* Print warning about defaulting to int if necessary. */ - -static void -warn_defaults_to (location_t location, int opt, const char *gmsgid, ...) -{ - diagnostic_info diagnostic; - va_list ap; - rich_location richloc (line_table, location); - - va_start (ap, gmsgid); - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, - flag_isoc99 ? DK_PEDWARN : DK_WARNING); - diagnostic.option_index = opt; - diagnostic_report_diagnostic (global_dc, &diagnostic); - va_end (ap); -} - -/* Returns the smallest location != UNKNOWN_LOCATION in LOCATIONS, - considering only those c_declspec_words found in LIST, which - must be terminated by cdw_number_of_elements. */ - -static location_t -smallest_type_quals_location (const location_t *locations, - const c_declspec_word *list) -{ - location_t loc = UNKNOWN_LOCATION; - while (*list != cdw_number_of_elements) - { - location_t newloc = locations[*list]; - if (loc == UNKNOWN_LOCATION - || (newloc != UNKNOWN_LOCATION && newloc < loc)) - loc = newloc; - list++; - } - - return loc; -} - -/* Given declspecs and a declarator, - determine the name and type of the object declared - and construct a ..._DECL node for it. - (In one case we can return a ..._TYPE node instead. - For invalid input we sometimes return NULL_TREE.) - - DECLSPECS is a c_declspecs structure for the declaration specifiers. - - DECL_CONTEXT says which syntactic context this declaration is in: - NORMAL for most contexts. Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL. - FUNCDEF for a function definition. Like NORMAL but a few different - error messages in each case. Return value may be zero meaning - this definition is too screwy to try to parse. - PARM for a parameter declaration (either within a function prototype - or before a function body). Make a PARM_DECL, or return void_type_node. - TYPENAME if for a typename (in a cast or sizeof). - Don't make a DECL node; just return the ..._TYPE node. - FIELD for a struct or union field; make a FIELD_DECL. - INITIALIZED is true if the decl has an initializer. - WIDTH is non-NULL for bit-fields, and is a pointer to an INTEGER_CST node - representing the width of the bit-field. - DECL_ATTRS points to the list of attributes that should be added to this - decl. Any nested attributes that belong on the decl itself will be - added to this list. - If EXPR is not NULL, any expressions that need to be evaluated as - part of evaluating variably modified types will be stored in *EXPR. - If EXPR_CONST_OPERANDS is not NULL, *EXPR_CONST_OPERANDS will be - set to indicate whether operands in *EXPR can be used in constant - expressions. - DEPRECATED_STATE is a deprecated_states value indicating whether - deprecation/unavailability warnings should be suppressed. - - In the TYPENAME case, DECLARATOR is really an absolute declarator. - It may also be so in the PARM case, for a prototype where the - argument type is specified but not the name. - - This function is where the complicated C meanings of `static' - and `extern' are interpreted. */ - -static tree -grokdeclarator (const struct c_declarator *declarator, - struct c_declspecs *declspecs, - enum decl_context decl_context, bool initialized, tree *width, - tree *decl_attrs, tree *expr, bool *expr_const_operands, - enum deprecated_states deprecated_state) -{ - tree type = declspecs->type; - bool threadp = declspecs->thread_p; - enum c_storage_class storage_class = declspecs->storage_class; - int constp; - int restrictp; - int volatilep; - int atomicp; - int type_quals = TYPE_UNQUALIFIED; - tree name = NULL_TREE; - bool funcdef_flag = false; - bool funcdef_syntax = false; - bool size_varies = false; - tree decl_attr = declspecs->decl_attr; - int array_ptr_quals = TYPE_UNQUALIFIED; - tree array_ptr_attrs = NULL_TREE; - bool array_parm_static = false; - bool array_parm_vla_unspec_p = false; - tree returned_attrs = NULL_TREE; - tree decl_id_attrs = NULL_TREE; - bool bitfield = width != NULL; - tree element_type; - tree orig_qual_type = NULL; - size_t orig_qual_indirect = 0; - struct c_arg_info *arg_info = 0; - addr_space_t as1, as2, address_space; - location_t loc = UNKNOWN_LOCATION; - tree expr_dummy; - bool expr_const_operands_dummy; - enum c_declarator_kind first_non_attr_kind; - unsigned int alignas_align = 0; - - if (TREE_CODE (type) == ERROR_MARK) - return error_mark_node; - if (expr == NULL) - { - expr = &expr_dummy; - expr_dummy = NULL_TREE; - } - if (expr_const_operands == NULL) - expr_const_operands = &expr_const_operands_dummy; - - if (declspecs->expr) - { - if (*expr) - *expr = build2 (COMPOUND_EXPR, TREE_TYPE (declspecs->expr), *expr, - declspecs->expr); - else - *expr = declspecs->expr; - } - *expr_const_operands = declspecs->expr_const_operands; - - if (decl_context == FUNCDEF) - funcdef_flag = true, decl_context = NORMAL; - - /* Look inside a declarator for the name being declared - and get it as an IDENTIFIER_NODE, for an error message. */ - { - const struct c_declarator *decl = declarator; - - first_non_attr_kind = cdk_attrs; - while (decl) - switch (decl->kind) - { - case cdk_array: - loc = decl->id_loc; - /* FALL THRU. */ - - case cdk_function: - case cdk_pointer: - funcdef_syntax = (decl->kind == cdk_function); - if (first_non_attr_kind == cdk_attrs) - first_non_attr_kind = decl->kind; - decl = decl->declarator; - break; - - case cdk_attrs: - decl = decl->declarator; - break; - - case cdk_id: - loc = decl->id_loc; - if (decl->u.id.id) - name = decl->u.id.id; - decl_id_attrs = decl->u.id.attrs; - if (first_non_attr_kind == cdk_attrs) - first_non_attr_kind = decl->kind; - decl = 0; - break; - - default: - gcc_unreachable (); - } - if (name == NULL_TREE) - { - gcc_assert (decl_context == PARM - || decl_context == TYPENAME - || (decl_context == FIELD - && declarator->kind == cdk_id)); - gcc_assert (!initialized); - } - } - - /* A function definition's declarator must have the form of - a function declarator. */ - - if (funcdef_flag && !funcdef_syntax) - return NULL_TREE; - - /* If this looks like a function definition, make it one, - even if it occurs where parms are expected. - Then store_parm_decls will reject it and not use it as a parm. */ - if (decl_context == NORMAL && !funcdef_flag && current_scope->parm_flag) - decl_context = PARM; - - if (deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) - { - if (declspecs->unavailable_p) - error_unavailable_use (declspecs->type, declspecs->decl_attr); - else if (declspecs->deprecated_p - && deprecated_state != DEPRECATED_SUPPRESS) - warn_deprecated_use (declspecs->type, declspecs->decl_attr); - } - - if ((decl_context == NORMAL || decl_context == FIELD) - && current_scope == file_scope - && variably_modified_type_p (type, NULL_TREE)) - { - if (name) - error_at (loc, "variably modified %qE at file scope", name); - else - error_at (loc, "variably modified field at file scope"); - type = integer_type_node; - } - - size_varies = C_TYPE_VARIABLE_SIZE (type) != 0; - - /* Diagnose defaulting to "int". */ - - if (declspecs->default_int_p && !in_system_header_at (input_location)) - { - /* Issue a warning if this is an ISO C 99 program or if - -Wreturn-type and this is a function, or if -Wimplicit; - prefer the former warning since it is more explicit. */ - if ((warn_implicit_int || warn_return_type > 0 || flag_isoc99) - && funcdef_flag) - warn_about_return_type = 1; - else - { - if (name) - warn_defaults_to (loc, OPT_Wimplicit_int, - "type defaults to % in declaration " - "of %qE", name); - else - warn_defaults_to (loc, OPT_Wimplicit_int, - "type defaults to % in type name"); - } - } - - /* Adjust the type if a bit-field is being declared, - -funsigned-bitfields applied and the type is not explicitly - "signed". */ - if (bitfield && !flag_signed_bitfields && !declspecs->explicit_signed_p - && TREE_CODE (type) == INTEGER_TYPE) - type = unsigned_type_for (type); - - /* Figure out the type qualifiers for the declaration. There are - two ways a declaration can become qualified. One is something - like `const int i' where the `const' is explicit. Another is - something like `typedef const int CI; CI i' where the type of the - declaration contains the `const'. A third possibility is that - there is a type qualifier on the element type of a typedefed - array type, in which case we should extract that qualifier so - that c_apply_type_quals_to_decl receives the full list of - qualifiers to work with (C90 is not entirely clear about whether - duplicate qualifiers should be diagnosed in this case, but it - seems most appropriate to do so). */ - element_type = strip_array_types (type); - constp = declspecs->const_p + TYPE_READONLY (element_type); - restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type); - volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type); - atomicp = declspecs->atomic_p + TYPE_ATOMIC (element_type); - as1 = declspecs->address_space; - as2 = TYPE_ADDR_SPACE (element_type); - address_space = ADDR_SPACE_GENERIC_P (as1)? as2 : as1; - - if (constp > 1) - pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %"); - if (restrictp > 1) - pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %"); - if (volatilep > 1) - pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %"); - if (atomicp > 1) - pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %<_Atomic%>"); - - if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2) - error_at (loc, "conflicting named address spaces (%s vs %s)", - c_addr_space_name (as1), c_addr_space_name (as2)); - - if ((TREE_CODE (type) == ARRAY_TYPE - || first_non_attr_kind == cdk_array) - && TYPE_QUALS (element_type)) - { - orig_qual_type = type; - type = TYPE_MAIN_VARIANT (type); - } - type_quals = ((constp ? TYPE_QUAL_CONST : 0) - | (restrictp ? TYPE_QUAL_RESTRICT : 0) - | (volatilep ? TYPE_QUAL_VOLATILE : 0) - | (atomicp ? TYPE_QUAL_ATOMIC : 0) - | ENCODE_QUAL_ADDR_SPACE (address_space)); - if (type_quals != TYPE_QUALS (element_type)) - orig_qual_type = NULL_TREE; - - /* Applying the _Atomic qualifier to an array type (through the use - of typedefs or typeof) must be detected here. If the qualifier - is introduced later, any appearance of applying it to an array is - actually applying it to an element of that array. */ - if (declspecs->atomic_p && TREE_CODE (type) == ARRAY_TYPE) - error_at (loc, "%<_Atomic%>-qualified array type"); - - /* Warn about storage classes that are invalid for certain - kinds of declarations (parameters, typenames, etc.). */ - - if (funcdef_flag - && (threadp - || storage_class == csc_auto - || storage_class == csc_register - || storage_class == csc_typedef)) - { - if (storage_class == csc_auto) - pedwarn (loc, - (current_scope == file_scope) ? 0 : OPT_Wpedantic, - "function definition declared %"); - if (storage_class == csc_register) - error_at (loc, "function definition declared %"); - if (storage_class == csc_typedef) - error_at (loc, "function definition declared %"); - if (threadp) - error_at (loc, "function definition declared %qs", - declspecs->thread_gnu_p ? "__thread" : "_Thread_local"); - threadp = false; - if (storage_class == csc_auto - || storage_class == csc_register - || storage_class == csc_typedef) - storage_class = csc_none; - } - else if (decl_context != NORMAL && (storage_class != csc_none || threadp)) - { - if (decl_context == PARM && storage_class == csc_register) - ; - else - { - switch (decl_context) - { - case FIELD: - if (name) - error_at (loc, "storage class specified for structure " - "field %qE", name); - else - error_at (loc, "storage class specified for structure field"); - break; - case PARM: - if (name) - error_at (loc, "storage class specified for parameter %qE", - name); - else - error_at (loc, "storage class specified for unnamed parameter"); - break; - default: - error_at (loc, "storage class specified for typename"); - break; - } - storage_class = csc_none; - threadp = false; - } - } - else if (storage_class == csc_extern - && initialized - && !funcdef_flag) - { - /* 'extern' with initialization is invalid if not at file scope. */ - if (current_scope == file_scope) - { - /* It is fine to have 'extern const' when compiling at C - and C++ intersection. */ - if (!(warn_cxx_compat && constp)) - warning_at (loc, 0, "%qE initialized and declared %", - name); - } - else - error_at (loc, "%qE has both % and initializer", name); - } - else if (current_scope == file_scope) - { - if (storage_class == csc_auto) - error_at (loc, "file-scope declaration of %qE specifies %", - name); - if (pedantic && storage_class == csc_register) - pedwarn (input_location, OPT_Wpedantic, - "file-scope declaration of %qE specifies %", name); - } - else - { - if (storage_class == csc_extern && funcdef_flag) - error_at (loc, "nested function %qE declared %", name); - else if (threadp && storage_class == csc_none) - { - error_at (loc, "function-scope %qE implicitly auto and declared " - "%qs", name, - declspecs->thread_gnu_p ? "__thread" : "_Thread_local"); - threadp = false; - } - } - - /* Now figure out the structure of the declarator proper. - Descend through it, creating more complex types, until we reach - the declared identifier (or NULL_TREE, in an absolute declarator). - At each stage we maintain an unqualified version of the type - together with any qualifiers that should be applied to it with - c_build_qualified_type; this way, array types including - multidimensional array types are first built up in unqualified - form and then the qualified form is created with - TYPE_MAIN_VARIANT pointing to the unqualified form. */ - - while (declarator && declarator->kind != cdk_id) - { - if (type == error_mark_node) - { - declarator = declarator->declarator; - continue; - } - - /* Each level of DECLARATOR is either a cdk_array (for ...[..]), - a cdk_pointer (for *...), - a cdk_function (for ...(...)), - a cdk_attrs (for nested attributes), - or a cdk_id (for the name being declared - or the place in an absolute declarator - where the name was omitted). - For the last case, we have just exited the loop. - - At this point, TYPE is the type of elements of an array, - or for a function to return, or for a pointer to point to. - After this sequence of ifs, TYPE is the type of the - array or function or pointer, and DECLARATOR has had its - outermost layer removed. */ - - if (array_ptr_quals != TYPE_UNQUALIFIED - || array_ptr_attrs != NULL_TREE - || array_parm_static) - { - /* Only the innermost declarator (making a parameter be of - array type which is converted to pointer type) - may have static or type qualifiers. */ - error_at (loc, "static or type qualifiers in non-parameter array declarator"); - array_ptr_quals = TYPE_UNQUALIFIED; - array_ptr_attrs = NULL_TREE; - array_parm_static = false; - } - - switch (declarator->kind) - { - case cdk_attrs: - { - /* A declarator with embedded attributes. */ - tree attrs = declarator->u.attrs; - const struct c_declarator *inner_decl; - int attr_flags = 0; - declarator = declarator->declarator; - /* Standard attribute syntax precisely defines what entity - an attribute in each position appertains to, so only - apply laxity about positioning to GNU attribute syntax. - Standard attributes applied to a function or array - declarator apply exactly to that type; standard - attributes applied to the identifier apply to the - declaration rather than to the type, and are specified - using a cdk_id declarator rather than using - cdk_attrs. */ - inner_decl = declarator; - while (inner_decl->kind == cdk_attrs) - inner_decl = inner_decl->declarator; - if (!cxx11_attribute_p (attrs)) - { - if (inner_decl->kind == cdk_id) - attr_flags |= (int) ATTR_FLAG_DECL_NEXT; - else if (inner_decl->kind == cdk_function) - attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; - else if (inner_decl->kind == cdk_array) - attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; - } - attrs = c_warn_type_attributes (attrs); - returned_attrs = decl_attributes (&type, - chainon (returned_attrs, attrs), - attr_flags); - break; - } - case cdk_array: - { - tree itype = NULL_TREE; - tree size = declarator->u.array.dimen; - /* The index is a signed object `sizetype' bits wide. */ - tree index_type = c_common_signed_type (sizetype); - - array_ptr_quals = declarator->u.array.quals; - array_ptr_attrs = declarator->u.array.attrs; - array_parm_static = declarator->u.array.static_p; - array_parm_vla_unspec_p = declarator->u.array.vla_unspec_p; - - declarator = declarator->declarator; - - /* Check for some types that there cannot be arrays of. */ - - if (VOID_TYPE_P (type)) - { - if (name) - error_at (loc, "declaration of %qE as array of voids", name); - else - error_at (loc, "declaration of type name as array of voids"); - type = error_mark_node; - } - - if (TREE_CODE (type) == FUNCTION_TYPE) - { - if (name) - error_at (loc, "declaration of %qE as array of functions", - name); - else - error_at (loc, "declaration of type name as array of " - "functions"); - type = error_mark_node; - } - - if (pedantic && !in_system_header_at (input_location) - && flexible_array_type_p (type)) - pedwarn (loc, OPT_Wpedantic, - "invalid use of structure with flexible array member"); - - if (size == error_mark_node) - type = error_mark_node; - - if (type == error_mark_node) - continue; - - if (!verify_type_context (loc, TCTX_ARRAY_ELEMENT, type)) - { - type = error_mark_node; - continue; - } - - /* If size was specified, set ITYPE to a range-type for - that size. Otherwise, ITYPE remains null. finish_decl - may figure it out from an initial value. */ - - if (size) - { - bool size_maybe_const = true; - bool size_int_const = (TREE_CODE (size) == INTEGER_CST - && !TREE_OVERFLOW (size)); - bool this_size_varies = false; - - /* Strip NON_LVALUE_EXPRs since we aren't using as an - lvalue. */ - STRIP_TYPE_NOPS (size); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (size))) - { - if (name) - error_at (loc, "size of array %qE has non-integer type", - name); - else - error_at (loc, - "size of unnamed array has non-integer type"); - size = integer_one_node; - size_int_const = true; - } - /* This can happen with enum forward declaration. */ - else if (!COMPLETE_TYPE_P (TREE_TYPE (size))) - { - if (name) - error_at (loc, "size of array %qE has incomplete type", - name); - else - error_at (loc, "size of unnamed array has incomplete " - "type"); - size = integer_one_node; - size_int_const = true; - } - - size = c_fully_fold (size, false, &size_maybe_const); - - if (pedantic && size_maybe_const && integer_zerop (size)) - { - if (name) - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids zero-size array %qE", name); - else - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids zero-size array"); - } - - if (TREE_CODE (size) == INTEGER_CST && size_maybe_const) - { - constant_expression_warning (size); - if (tree_int_cst_sgn (size) < 0) - { - if (name) - error_at (loc, "size of array %qE is negative", name); - else - error_at (loc, "size of unnamed array is negative"); - size = integer_one_node; - size_int_const = true; - } - /* Handle a size folded to an integer constant but - not an integer constant expression. */ - if (!size_int_const) - { - /* If this is a file scope declaration of an - ordinary identifier, this is invalid code; - diagnosing it here and not subsequently - treating the type as variable-length avoids - more confusing diagnostics later. */ - if ((decl_context == NORMAL || decl_context == FIELD) - && current_scope == file_scope) - pedwarn (input_location, 0, - "variably modified %qE at file scope", - name); - else - this_size_varies = size_varies = true; - warn_variable_length_array (name, size); - } - } - else if ((decl_context == NORMAL || decl_context == FIELD) - && current_scope == file_scope) - { - error_at (loc, "variably modified %qE at file scope", name); - size = integer_one_node; - } - else - { - /* Make sure the array size remains visibly - nonconstant even if it is (eg) a const variable - with known value. */ - this_size_varies = size_varies = true; - warn_variable_length_array (name, size); - if (sanitize_flags_p (SANITIZE_VLA) - && current_function_decl != NULL_TREE - && decl_context == NORMAL) - { - /* Evaluate the array size only once. */ - size = save_expr (size); - size = c_fully_fold (size, false, NULL); - size = fold_build2 (COMPOUND_EXPR, TREE_TYPE (size), - ubsan_instrument_vla (loc, size), - size); - } - } - - if (integer_zerop (size) && !this_size_varies) - { - /* A zero-length array cannot be represented with - an unsigned index type, which is what we'll - get with build_index_type. Create an - open-ended range instead. */ - itype = build_range_type (sizetype, size, NULL_TREE); - } - else - { - /* Arrange for the SAVE_EXPR on the inside of the - MINUS_EXPR, which allows the -1 to get folded - with the +1 that happens when building TYPE_SIZE. */ - if (size_varies) - size = save_expr (size); - if (this_size_varies && TREE_CODE (size) == INTEGER_CST) - size = build2 (COMPOUND_EXPR, TREE_TYPE (size), - integer_zero_node, size); - - /* Compute the maximum valid index, that is, size - - 1. Do the calculation in index_type, so that - if it is a variable the computations will be - done in the proper mode. */ - itype = fold_build2_loc (loc, MINUS_EXPR, index_type, - convert (index_type, size), - convert (index_type, - size_one_node)); - - /* The above overflows when size does not fit - in index_type. - ??? While a size of INT_MAX+1 technically shouldn't - cause an overflow (because we subtract 1), handling - this case seems like an unnecessary complication. */ - if (TREE_CODE (size) == INTEGER_CST - && !int_fits_type_p (size, index_type)) - { - if (name) - error_at (loc, "size of array %qE is too large", - name); - else - error_at (loc, "size of unnamed array is too large"); - type = error_mark_node; - continue; - } - - itype = build_index_type (itype); - } - if (this_size_varies) - { - if (TREE_SIDE_EFFECTS (size)) - { - if (*expr) - *expr = build2 (COMPOUND_EXPR, TREE_TYPE (size), - *expr, size); - else - *expr = size; - } - *expr_const_operands &= size_maybe_const; - } - } - else if (decl_context == FIELD) - { - bool flexible_array_member = false; - if (array_parm_vla_unspec_p) - /* Field names can in fact have function prototype - scope so [*] is disallowed here through making - the field variably modified, not through being - something other than a declaration with function - prototype scope. */ - size_varies = true; - else - { - const struct c_declarator *t = declarator; - while (t->kind == cdk_attrs) - t = t->declarator; - flexible_array_member = (t->kind == cdk_id); - } - if (flexible_array_member - && !in_system_header_at (input_location)) - pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not " - "support flexible array members"); - - /* ISO C99 Flexible array members are effectively - identical to GCC's zero-length array extension. */ - if (flexible_array_member || array_parm_vla_unspec_p) - itype = build_range_type (sizetype, size_zero_node, - NULL_TREE); - } - else if (decl_context == PARM) - { - if (array_parm_vla_unspec_p) - { - itype = build_range_type (sizetype, size_zero_node, NULL_TREE); - size_varies = true; - } - } - else if (decl_context == TYPENAME) - { - if (array_parm_vla_unspec_p) - { - /* C99 6.7.5.2p4 */ - warning (0, "%<[*]%> not in a declaration"); - /* We use this to avoid messing up with incomplete - array types of the same type, that would - otherwise be modified below. */ - itype = build_range_type (sizetype, size_zero_node, - NULL_TREE); - size_varies = true; - } - } - - /* Complain about arrays of incomplete types. */ - if (!COMPLETE_TYPE_P (type)) - { - error_at (loc, "array type has incomplete element type %qT", - type); - /* See if we can be more helpful. */ - if (TREE_CODE (type) == ARRAY_TYPE) - { - if (name) - inform (loc, "declaration of %qE as multidimensional " - "array must have bounds for all dimensions " - "except the first", name); - else - inform (loc, "declaration of multidimensional array " - "must have bounds for all dimensions except " - "the first"); - } - type = error_mark_node; - } - else - /* When itype is NULL, a shared incomplete array type is - returned for all array of a given type. Elsewhere we - make sure we don't complete that type before copying - it, but here we want to make sure we don't ever - modify the shared type, so we gcc_assert (itype) - below. */ - { - addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals); - if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type)) - type = build_qualified_type (type, - ENCODE_QUAL_ADDR_SPACE (as)); - - type = build_array_type (type, itype); - } - - if (type != error_mark_node) - { - if (size_varies) - { - /* It is ok to modify type here even if itype is - NULL: if size_varies, we're in a - multi-dimensional array and the inner type has - variable size, so the enclosing shared array type - must too. */ - if (size && TREE_CODE (size) == INTEGER_CST) - type - = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); - C_TYPE_VARIABLE_SIZE (type) = 1; - } - - /* The GCC extension for zero-length arrays differs from - ISO flexible array members in that sizeof yields - zero. */ - if (size && integer_zerop (size)) - { - gcc_assert (itype); - type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); - TYPE_SIZE (type) = bitsize_zero_node; - TYPE_SIZE_UNIT (type) = size_zero_node; - SET_TYPE_STRUCTURAL_EQUALITY (type); - } - if (array_parm_vla_unspec_p) - { - gcc_assert (itype); - /* The type is complete. C99 6.7.5.2p4 */ - type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); - TYPE_SIZE (type) = bitsize_zero_node; - TYPE_SIZE_UNIT (type) = size_zero_node; - SET_TYPE_STRUCTURAL_EQUALITY (type); - } - - if (!valid_array_size_p (loc, type, name)) - type = error_mark_node; - } - - if (decl_context != PARM - && (array_ptr_quals != TYPE_UNQUALIFIED - || array_ptr_attrs != NULL_TREE - || array_parm_static)) - { - error_at (loc, "static or type qualifiers in non-parameter " - "array declarator"); - array_ptr_quals = TYPE_UNQUALIFIED; - array_ptr_attrs = NULL_TREE; - array_parm_static = false; - } - orig_qual_indirect++; - break; - } - case cdk_function: - { - /* Say it's a definition only for the declarator closest - to the identifier, apart possibly from some - attributes. */ - bool really_funcdef = false; - tree arg_types; - orig_qual_type = NULL_TREE; - if (funcdef_flag) - { - const struct c_declarator *t = declarator->declarator; - while (t->kind == cdk_attrs) - t = t->declarator; - really_funcdef = (t->kind == cdk_id); - } - - /* Declaring a function type. Make sure we have a valid - type for the function to return. */ - if (type == error_mark_node) - continue; - - size_varies = false; - - /* Warn about some types functions can't return. */ - if (TREE_CODE (type) == FUNCTION_TYPE) - { - if (name) - error_at (loc, "%qE declared as function returning a " - "function", name); - else - error_at (loc, "type name declared as function " - "returning a function"); - type = integer_type_node; - } - if (TREE_CODE (type) == ARRAY_TYPE) - { - if (name) - error_at (loc, "%qE declared as function returning an array", - name); - else - error_at (loc, "type name declared as function returning " - "an array"); - type = integer_type_node; - } - - /* Construct the function type and go to the next - inner layer of declarator. */ - arg_info = declarator->u.arg_info; - arg_types = grokparms (arg_info, really_funcdef); - - /* Type qualifiers before the return type of the function - qualify the return type, not the function type. */ - if (type_quals) - { - const enum c_declspec_word ignored_quals_list[] = - { - cdw_const, cdw_volatile, cdw_restrict, cdw_address_space, - cdw_atomic, cdw_number_of_elements - }; - location_t specs_loc - = smallest_type_quals_location (declspecs->locations, - ignored_quals_list); - if (specs_loc == UNKNOWN_LOCATION) - specs_loc = declspecs->locations[cdw_typedef]; - if (specs_loc == UNKNOWN_LOCATION) - specs_loc = loc; - - /* Type qualifiers on a function return type are - normally permitted by the standard but have no - effect, so give a warning at -Wreturn-type. - Qualifiers on a void return type are banned on - function definitions in ISO C; GCC used to used - them for noreturn functions. The resolution of C11 - DR#423 means qualifiers (other than _Atomic) are - actually removed from the return type when - determining the function type. */ - int quals_used = type_quals; - if (flag_isoc11) - quals_used &= TYPE_QUAL_ATOMIC; - if (quals_used && VOID_TYPE_P (type) && really_funcdef) - pedwarn (specs_loc, 0, - "function definition has qualified void " - "return type"); - else - warning_at (specs_loc, OPT_Wignored_qualifiers, - "type qualifiers ignored on function " - "return type"); - - /* Ensure an error for restrict on invalid types; the - DR#423 resolution is not entirely clear about - this. */ - if (flag_isoc11 - && (type_quals & TYPE_QUAL_RESTRICT) - && (!POINTER_TYPE_P (type) - || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))) - error_at (loc, "invalid use of %"); - type = c_build_qualified_type (type, quals_used); - } - type_quals = TYPE_UNQUALIFIED; - - type = build_function_type (type, arg_types); - declarator = declarator->declarator; - - /* Set the TYPE_CONTEXTs for each tagged type which is local to - the formal parameter list of this FUNCTION_TYPE to point to - the FUNCTION_TYPE node itself. */ - { - c_arg_tag *tag; - unsigned ix; - - FOR_EACH_VEC_SAFE_ELT_REVERSE (arg_info->tags, ix, tag) - TYPE_CONTEXT (tag->type) = type; - } - break; - } - case cdk_pointer: - { - /* Merge any constancy or volatility into the target type - for the pointer. */ - if ((type_quals & TYPE_QUAL_ATOMIC) - && TREE_CODE (type) == FUNCTION_TYPE) - { - error_at (loc, - "%<_Atomic%>-qualified function type"); - type_quals &= ~TYPE_QUAL_ATOMIC; - } - else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE - && type_quals) - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids qualified function types"); - if (type_quals) - type = c_build_qualified_type (type, type_quals, orig_qual_type, - orig_qual_indirect); - orig_qual_type = NULL_TREE; - size_varies = false; - - /* When the pointed-to type involves components of variable size, - care must be taken to ensure that the size evaluation code is - emitted early enough to dominate all the possible later uses - and late enough for the variables on which it depends to have - been assigned. - - This is expected to happen automatically when the pointed-to - type has a name/declaration of it's own, but special attention - is required if the type is anonymous. - - We attach an artificial TYPE_DECL to such pointed-to type - and arrange for it to be included in a DECL_EXPR. This - forces the sizes evaluation at a safe point and ensures it - is not deferred until e.g. within a deeper conditional context. - - PARM contexts have no enclosing statement list that - can hold the DECL_EXPR, so we need to use a BIND_EXPR - instead, and add it to the list of expressions that - need to be evaluated. - - TYPENAME contexts do have an enclosing statement list, - but it would be incorrect to use it, as the size should - only be evaluated if the containing expression is - evaluated. We might also be in the middle of an - expression with side effects on the pointed-to type size - "arguments" prior to the pointer declaration point and - the fake TYPE_DECL in the enclosing context would force - the size evaluation prior to the side effects. We therefore - use BIND_EXPRs in TYPENAME contexts too. */ - if (!TYPE_NAME (type) - && variably_modified_type_p (type, NULL_TREE)) - { - tree bind = NULL_TREE; - if (decl_context == TYPENAME || decl_context == PARM) - { - bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, - NULL_TREE, NULL_TREE); - TREE_SIDE_EFFECTS (bind) = 1; - BIND_EXPR_BODY (bind) = push_stmt_list (); - push_scope (); - } - tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type); - DECL_ARTIFICIAL (decl) = 1; - pushdecl (decl); - finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE); - TYPE_NAME (type) = decl; - if (bind) - { - pop_scope (); - BIND_EXPR_BODY (bind) - = pop_stmt_list (BIND_EXPR_BODY (bind)); - if (*expr) - *expr = build2 (COMPOUND_EXPR, void_type_node, *expr, - bind); - else - *expr = bind; - } - } - - type = c_build_pointer_type (type); - - /* Process type qualifiers (such as const or volatile) - that were given inside the `*'. */ - type_quals = declarator->u.pointer_quals; - - declarator = declarator->declarator; - break; - } - default: - gcc_unreachable (); - } - } - *decl_attrs = chainon (returned_attrs, *decl_attrs); - *decl_attrs = chainon (decl_id_attrs, *decl_attrs); - - /* Now TYPE has the actual type, apart from any qualifiers in - TYPE_QUALS. */ - - /* Warn about address space used for things other than static memory or - pointers. */ - address_space = DECODE_QUAL_ADDR_SPACE (type_quals); - if (!ADDR_SPACE_GENERIC_P (address_space)) - { - if (decl_context == NORMAL) - { - switch (storage_class) - { - case csc_auto: - error ("%qs combined with % qualifier for %qE", - c_addr_space_name (address_space), name); - break; - case csc_register: - error ("%qs combined with % qualifier for %qE", - c_addr_space_name (address_space), name); - break; - case csc_none: - if (current_function_scope) - { - error ("%qs specified for auto variable %qE", - c_addr_space_name (address_space), name); - break; - } - break; - case csc_static: - case csc_extern: - case csc_typedef: - break; - default: - gcc_unreachable (); - } - } - else if (decl_context == PARM && TREE_CODE (type) != ARRAY_TYPE) - { - if (name) - error ("%qs specified for parameter %qE", - c_addr_space_name (address_space), name); - else - error ("%qs specified for unnamed parameter", - c_addr_space_name (address_space)); - } - else if (decl_context == FIELD) - { - if (name) - error ("%qs specified for structure field %qE", - c_addr_space_name (address_space), name); - else - error ("%qs specified for structure field", - c_addr_space_name (address_space)); - } - } - - /* Check the type and width of a bit-field. */ - if (bitfield) - { - check_bitfield_type_and_width (loc, &type, width, name); - /* C11 makes it implementation-defined (6.7.2.1#5) whether - atomic types are permitted for bit-fields; we have no code to - make bit-field accesses atomic, so disallow them. */ - if (type_quals & TYPE_QUAL_ATOMIC) - { - if (name) - error_at (loc, "bit-field %qE has atomic type", name); - else - error_at (loc, "bit-field has atomic type"); - type_quals &= ~TYPE_QUAL_ATOMIC; - } - } - - /* Reject invalid uses of _Alignas. */ - if (declspecs->alignas_p) - { - if (storage_class == csc_typedef) - error_at (loc, "alignment specified for typedef %qE", name); - else if (storage_class == csc_register) - error_at (loc, "alignment specified for % object %qE", - name); - else if (decl_context == PARM) - { - if (name) - error_at (loc, "alignment specified for parameter %qE", name); - else - error_at (loc, "alignment specified for unnamed parameter"); - } - else if (bitfield) - { - if (name) - error_at (loc, "alignment specified for bit-field %qE", name); - else - error_at (loc, "alignment specified for unnamed bit-field"); - } - else if (TREE_CODE (type) == FUNCTION_TYPE) - error_at (loc, "alignment specified for function %qE", name); - else if (declspecs->align_log != -1 && TYPE_P (type)) - { - alignas_align = 1U << declspecs->align_log; - if (alignas_align < min_align_of_type (type)) - { - if (name) - error_at (loc, "%<_Alignas%> specifiers cannot reduce " - "alignment of %qE", name); - else - error_at (loc, "%<_Alignas%> specifiers cannot reduce " - "alignment of unnamed field"); - alignas_align = 0; - } - } - } - - /* If this is declaring a typedef name, return a TYPE_DECL. */ - - if (storage_class == csc_typedef) - { - tree decl; - if ((type_quals & TYPE_QUAL_ATOMIC) - && TREE_CODE (type) == FUNCTION_TYPE) - { - error_at (loc, - "%<_Atomic%>-qualified function type"); - type_quals &= ~TYPE_QUAL_ATOMIC; - } - else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE - && type_quals) - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids qualified function types"); - if (type_quals) - type = c_build_qualified_type (type, type_quals, orig_qual_type, - orig_qual_indirect); - decl = build_decl (declarator->id_loc, - TYPE_DECL, declarator->u.id.id, type); - if (declspecs->explicit_signed_p) - C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; - if (declspecs->inline_p) - pedwarn (loc, 0,"typedef %q+D declared %", decl); - if (declspecs->noreturn_p) - pedwarn (loc, 0,"typedef %q+D declared %<_Noreturn%>", decl); - - if (warn_cxx_compat && declarator->u.id.id != NULL_TREE) - { - struct c_binding *b = I_TAG_BINDING (declarator->u.id.id); - - if (b != NULL - && b->decl != NULL_TREE - && (B_IN_CURRENT_SCOPE (b) - || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) - && TYPE_MAIN_VARIANT (b->decl) != TYPE_MAIN_VARIANT (type)) - { - auto_diagnostic_group d; - if (warning_at (declarator->id_loc, OPT_Wc___compat, - ("using %qD as both a typedef and a tag is " - "invalid in C++"), decl) - && b->locus != UNKNOWN_LOCATION) - inform (b->locus, "originally defined here"); - } - } - - return decl; - } - - /* If this is a type name (such as, in a cast or sizeof), - compute the type and return it now. */ - - if (decl_context == TYPENAME) - { - /* Note that the grammar rejects storage classes in typenames - and fields. */ - gcc_assert (storage_class == csc_none && !threadp - && !declspecs->inline_p && !declspecs->noreturn_p); - if ((type_quals & TYPE_QUAL_ATOMIC) - && TREE_CODE (type) == FUNCTION_TYPE) - { - error_at (loc, - "%<_Atomic%>-qualified function type"); - type_quals &= ~TYPE_QUAL_ATOMIC; - } - else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE - && type_quals) - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids const or volatile function types"); - if (type_quals) - type = c_build_qualified_type (type, type_quals, orig_qual_type, - orig_qual_indirect); - return type; - } - - if (pedantic && decl_context == FIELD - && variably_modified_type_p (type, NULL_TREE)) - { - /* C99 6.7.2.1p8 */ - pedwarn (loc, OPT_Wpedantic, "a member of a structure or union cannot " - "have a variably modified type"); - } - - /* Aside from typedefs and type names (handle above), - `void' at top level (not within pointer) - is allowed only in public variables. - We don't complain about parms either, but that is because - a better error message can be made later. */ - - if (VOID_TYPE_P (type) && decl_context != PARM - && !((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE) - && (storage_class == csc_extern - || (current_scope == file_scope - && !(storage_class == csc_static - || storage_class == csc_register))))) - { - error_at (loc, "variable or field %qE declared void", name); - type = integer_type_node; - } - - /* Now create the decl, which may be a VAR_DECL, a PARM_DECL - or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */ - - { - tree decl; - - if (decl_context == PARM) - { - tree promoted_type; - bool array_parameter_p = false; - - /* A parameter declared as an array of T is really a pointer to T. - One declared as a function is really a pointer to a function. */ - - if (TREE_CODE (type) == ARRAY_TYPE) - { - /* Transfer const-ness of array into that of type pointed to. */ - type = TREE_TYPE (type); - if (orig_qual_type != NULL_TREE) - { - if (orig_qual_indirect == 0) - orig_qual_type = TREE_TYPE (orig_qual_type); - else - orig_qual_indirect--; - } - if (type_quals) - type = c_build_qualified_type (type, type_quals, orig_qual_type, - orig_qual_indirect); - type = c_build_pointer_type (type); - type_quals = array_ptr_quals; - if (type_quals) - type = c_build_qualified_type (type, type_quals); - - /* We don't yet implement attributes in this context. */ - if (array_ptr_attrs != NULL_TREE) - warning_at (loc, OPT_Wattributes, - "attributes in parameter array declarator ignored"); - - size_varies = false; - array_parameter_p = true; - } - else if (TREE_CODE (type) == FUNCTION_TYPE) - { - if (type_quals & TYPE_QUAL_ATOMIC) - { - error_at (loc, - "%<_Atomic%>-qualified function type"); - type_quals &= ~TYPE_QUAL_ATOMIC; - } - else if (type_quals) - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids qualified function types"); - if (type_quals) - type = c_build_qualified_type (type, type_quals); - type = c_build_pointer_type (type); - type_quals = TYPE_UNQUALIFIED; - } - else if (type_quals) - type = c_build_qualified_type (type, type_quals); - - decl = build_decl (declarator->id_loc, - PARM_DECL, declarator->u.id.id, type); - if (size_varies) - C_DECL_VARIABLE_SIZE (decl) = 1; - C_ARRAY_PARAMETER (decl) = array_parameter_p; - - /* Compute the type actually passed in the parmlist, - for the case where there is no prototype. - (For example, shorts and chars are passed as ints.) - When there is a prototype, this is overridden later. */ - - if (type == error_mark_node) - promoted_type = type; - else - promoted_type = c_type_promotes_to (type); - - DECL_ARG_TYPE (decl) = promoted_type; - if (declspecs->inline_p) - pedwarn (loc, 0, "parameter %q+D declared %", decl); - if (declspecs->noreturn_p) - pedwarn (loc, 0, "parameter %q+D declared %<_Noreturn%>", decl); - } - else if (decl_context == FIELD) - { - /* Note that the grammar rejects storage classes in typenames - and fields. */ - gcc_assert (storage_class == csc_none && !threadp - && !declspecs->inline_p && !declspecs->noreturn_p); - - /* Structure field. It may not be a function. */ - - if (TREE_CODE (type) == FUNCTION_TYPE) - { - error_at (loc, "field %qE declared as a function", name); - type = build_pointer_type (type); - } - else if (TREE_CODE (type) != ERROR_MARK - && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type)) - { - if (name) - error_at (loc, "field %qE has incomplete type", name); - else - error_at (loc, "unnamed field has incomplete type"); - type = error_mark_node; - } - else if (TREE_CODE (type) == ARRAY_TYPE - && TYPE_DOMAIN (type) == NULL_TREE) - { - /* We have a flexible array member through a typedef. - Set suitable range. Whether this is a correct position - for a flexible array member will be determined elsewhere. */ - if (!in_system_header_at (input_location)) - pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not " - "support flexible array members"); - type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); - TYPE_DOMAIN (type) = build_range_type (sizetype, size_zero_node, - NULL_TREE); - if (orig_qual_indirect == 0) - orig_qual_type = NULL_TREE; - } - if (type != error_mark_node - && !verify_type_context (loc, TCTX_FIELD, type)) - type = error_mark_node; - - type = c_build_qualified_type (type, type_quals, orig_qual_type, - orig_qual_indirect); - decl = build_decl (declarator->id_loc, - FIELD_DECL, declarator->u.id.id, type); - DECL_NONADDRESSABLE_P (decl) = bitfield; - if (bitfield && !declarator->u.id.id) - DECL_PADDING_P (decl) = 1; - - if (size_varies) - C_DECL_VARIABLE_SIZE (decl) = 1; - } - else if (TREE_CODE (type) == FUNCTION_TYPE) - { - if (storage_class == csc_register || threadp) - { - error_at (loc, "invalid storage class for function %qE", name); - } - else if (current_scope != file_scope) - { - /* Function declaration not at file scope. Storage - classes other than `extern' are not allowed, C99 - 6.7.1p5, and `extern' makes no difference. However, - GCC allows 'auto', perhaps with 'inline', to support - nested functions. */ - if (storage_class == csc_auto) - pedwarn (loc, OPT_Wpedantic, - "invalid storage class for function %qE", name); - else if (storage_class == csc_static) - { - error_at (loc, "invalid storage class for function %qE", name); - if (funcdef_flag) - storage_class = declspecs->storage_class = csc_none; - else - return NULL_TREE; - } - } - - decl = build_decl (declarator->id_loc, - FUNCTION_DECL, declarator->u.id.id, type); - decl = build_decl_attribute_variant (decl, decl_attr); - - if (type_quals & TYPE_QUAL_ATOMIC) - { - error_at (loc, - "%<_Atomic%>-qualified function type"); - type_quals &= ~TYPE_QUAL_ATOMIC; - } - else if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl)) - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids qualified function types"); - - /* Every function declaration is an external reference - (DECL_EXTERNAL) except for those which are not at file - scope and are explicitly declared "auto". This is - forbidden by standard C (C99 6.7.1p5) and is interpreted by - GCC to signify a forward declaration of a nested function. */ - if (storage_class == csc_auto && current_scope != file_scope) - DECL_EXTERNAL (decl) = 0; - /* In C99, a function which is declared 'inline' with 'extern' - is not an external reference (which is confusing). It - means that the later definition of the function must be output - in this file, C99 6.7.4p6. In GNU C89, a function declared - 'extern inline' is an external reference. */ - else if (declspecs->inline_p && storage_class != csc_static) - DECL_EXTERNAL (decl) = ((storage_class == csc_extern) - == flag_gnu89_inline); - else - DECL_EXTERNAL (decl) = !initialized; - - /* Record absence of global scope for `static' or `auto'. */ - TREE_PUBLIC (decl) - = !(storage_class == csc_static || storage_class == csc_auto); - - /* For a function definition, record the argument information - block where store_parm_decls will look for it. */ - if (funcdef_flag) - current_function_arg_info = arg_info; - - if (declspecs->default_int_p) - C_FUNCTION_IMPLICIT_INT (decl) = 1; - - /* Record presence of `inline' and `_Noreturn', if it is - reasonable. */ - if (flag_hosted && MAIN_NAME_P (declarator->u.id.id)) - { - if (declspecs->inline_p) - pedwarn (loc, 0, "cannot inline function %"); - if (declspecs->noreturn_p) - pedwarn (loc, 0, "% declared %<_Noreturn%>"); - } - else - { - if (declspecs->inline_p) - /* Record that the function is declared `inline'. */ - DECL_DECLARED_INLINE_P (decl) = 1; - if (declspecs->noreturn_p) - { - if (flag_isoc99) - pedwarn_c99 (loc, OPT_Wpedantic, - "ISO C99 does not support %<_Noreturn%>"); - else - pedwarn_c99 (loc, OPT_Wpedantic, - "ISO C90 does not support %<_Noreturn%>"); - TREE_THIS_VOLATILE (decl) = 1; - } - } - } - else - { - /* It's a variable. */ - /* An uninitialized decl with `extern' is a reference. */ - int extern_ref = !initialized && storage_class == csc_extern; - - type = c_build_qualified_type (type, type_quals, orig_qual_type, - orig_qual_indirect); - - /* C99 6.2.2p7: It is invalid (compile-time undefined - behavior) to create an 'extern' declaration for a - variable if there is a global declaration that is - 'static' and the global declaration is not visible. - (If the static declaration _is_ currently visible, - the 'extern' declaration is taken to refer to that decl.) */ - if (extern_ref && current_scope != file_scope) - { - tree global_decl = identifier_global_value (declarator->u.id.id); - tree visible_decl = lookup_name (declarator->u.id.id); - - if (global_decl - && global_decl != visible_decl - && VAR_P (global_decl) - && !TREE_PUBLIC (global_decl)) - error_at (loc, "variable previously declared % " - "redeclared %"); - } - - decl = build_decl (declarator->id_loc, - VAR_DECL, declarator->u.id.id, type); - if (size_varies) - C_DECL_VARIABLE_SIZE (decl) = 1; - - if (declspecs->inline_p) - pedwarn (loc, 0, "variable %q+D declared %", decl); - if (declspecs->noreturn_p) - pedwarn (loc, 0, "variable %q+D declared %<_Noreturn%>", decl); - - /* At file scope, an initialized extern declaration may follow - a static declaration. In that case, DECL_EXTERNAL will be - reset later in start_decl. */ - DECL_EXTERNAL (decl) = (storage_class == csc_extern); - - /* At file scope, the presence of a `static' or `register' storage - class specifier, or the absence of all storage class specifiers - makes this declaration a definition (perhaps tentative). Also, - the absence of `static' makes it public. */ - if (current_scope == file_scope) - { - TREE_PUBLIC (decl) = storage_class != csc_static; - TREE_STATIC (decl) = !extern_ref; - } - /* Not at file scope, only `static' makes a static definition. */ - else - { - TREE_STATIC (decl) = (storage_class == csc_static); - TREE_PUBLIC (decl) = extern_ref; - } - - if (threadp) - set_decl_tls_model (decl, decl_default_tls_model (decl)); - } - - if ((storage_class == csc_extern - || (storage_class == csc_none - && TREE_CODE (type) == FUNCTION_TYPE - && !funcdef_flag)) - && variably_modified_type_p (type, NULL_TREE)) - { - /* C99 6.7.5.2p2 */ - if (TREE_CODE (type) == FUNCTION_TYPE) - error_at (loc, "non-nested function with variably modified type"); - else - error_at (loc, "object with variably modified type must have " - "no linkage"); - } - - /* For nested functions disqualify ones taking VLAs by value - from inlining since the middle-end cannot deal with this. - ??? We should arrange for those to be passed by reference - with emitting the copy on the caller side in the frontend. */ - if (storage_class == csc_none - && TREE_CODE (type) == FUNCTION_TYPE) - for (tree al = TYPE_ARG_TYPES (type); al; al = TREE_CHAIN (al)) - { - tree arg = TREE_VALUE (al); - if (arg != error_mark_node - && C_TYPE_VARIABLE_SIZE (arg)) - { - DECL_UNINLINABLE (decl) = 1; - break; - } - } - - /* Record `register' declaration for warnings on & - and in case doing stupid register allocation. */ - - if (storage_class == csc_register) - { - C_DECL_REGISTER (decl) = 1; - DECL_REGISTER (decl) = 1; - } - - /* Record constancy and volatility. */ - c_apply_type_quals_to_decl (type_quals, decl); - - /* Apply _Alignas specifiers. */ - if (alignas_align) - { - SET_DECL_ALIGN (decl, alignas_align * BITS_PER_UNIT); - DECL_USER_ALIGN (decl) = 1; - } - - /* If a type has volatile components, it should be stored in memory. - Otherwise, the fact that those components are volatile - will be ignored, and would even crash the compiler. - Of course, this only makes sense on VAR,PARM, and RESULT decl's. */ - if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl)) - && (VAR_P (decl) || TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == RESULT_DECL)) - { - /* It is not an error for a structure with volatile fields to - be declared register, but reset DECL_REGISTER since it - cannot actually go in a register. */ - int was_reg = C_DECL_REGISTER (decl); - C_DECL_REGISTER (decl) = 0; - DECL_REGISTER (decl) = 0; - c_mark_addressable (decl); - C_DECL_REGISTER (decl) = was_reg; - } - - /* This is the earliest point at which we might know the assembler - name of a variable. Thus, if it's known before this, die horribly. */ - gcc_assert (!HAS_DECL_ASSEMBLER_NAME_P (decl) - || !DECL_ASSEMBLER_NAME_SET_P (decl)); - - if (warn_cxx_compat - && VAR_P (decl) - && TREE_PUBLIC (decl) - && TREE_STATIC (decl) - && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)) - || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) - && TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE) - warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, - ("non-local variable %qD with anonymous type is " - "questionable in C++"), - decl); - - return decl; - } -} - -/* Decode the parameter-list info for a function type or function definition. - The argument is the value returned by `get_parm_info' (or made in c-parse.c - if there is an identifier list instead of a parameter decl list). - These two functions are separate because when a function returns - or receives functions then each is called multiple times but the order - of calls is different. The last call to `grokparms' is always the one - that contains the formal parameter names of a function definition. - - Return a list of arg types to use in the FUNCTION_TYPE for this function. - - FUNCDEF_FLAG is true for a function definition, false for - a mere declaration. A nonempty identifier-list gets an error message - when FUNCDEF_FLAG is false. */ - -static tree -grokparms (struct c_arg_info *arg_info, bool funcdef_flag) -{ - tree arg_types = arg_info->types; - - if (funcdef_flag && arg_info->had_vla_unspec) - { - /* A function definition isn't function prototype scope C99 6.2.1p4. */ - /* C99 6.7.5.2p4 */ - error ("%<[*]%> not allowed in other than function prototype scope"); - } - - if (arg_types == NULL_TREE && !funcdef_flag - && !in_system_header_at (input_location)) - warning (OPT_Wstrict_prototypes, - "function declaration isn%'t a prototype"); - - if (arg_types == error_mark_node) - /* Don't set TYPE_ARG_TYPES in this case. */ - return NULL_TREE; - - else if (arg_types && TREE_CODE (TREE_VALUE (arg_types)) == IDENTIFIER_NODE) - { - if (!funcdef_flag) - { - pedwarn (input_location, 0, "parameter names (without types) in " - "function declaration"); - arg_info->parms = NULL_TREE; - } - else - arg_info->parms = arg_info->types; - - arg_info->types = NULL_TREE; - return NULL_TREE; - } - else - { - tree parm, type, typelt; - unsigned int parmno; - - /* In C2X, convert () in a function definition to (void). */ - if (flag_isoc2x - && funcdef_flag - && !arg_types - && !arg_info->parms) - arg_types = arg_info->types = void_list_node; - - /* If there is a parameter of incomplete type in a definition, - this is an error. In a declaration this is valid, and a - struct or union type may be completed later, before any calls - or definition of the function. In the case where the tag was - first declared within the parameter list, a warning has - already been given. If a parameter has void type, then - however the function cannot be defined or called, so - warn. */ - - for (parm = arg_info->parms, typelt = arg_types, parmno = 1; - parm; - parm = DECL_CHAIN (parm), typelt = TREE_CHAIN (typelt), parmno++) - { - type = TREE_VALUE (typelt); - if (type == error_mark_node) - continue; - - if (!COMPLETE_TYPE_P (type)) - { - if (funcdef_flag) - { - if (DECL_NAME (parm)) - error_at (input_location, - "parameter %u (%q+D) has incomplete type", - parmno, parm); - else - error_at (DECL_SOURCE_LOCATION (parm), - "parameter %u has incomplete type", - parmno); - - TREE_VALUE (typelt) = error_mark_node; - TREE_TYPE (parm) = error_mark_node; - arg_types = NULL_TREE; - } - else if (VOID_TYPE_P (type)) - { - if (DECL_NAME (parm)) - warning_at (input_location, 0, - "parameter %u (%q+D) has void type", - parmno, parm); - else - warning_at (DECL_SOURCE_LOCATION (parm), 0, - "parameter %u has void type", - parmno); - } - } - - if (DECL_NAME (parm) && TREE_USED (parm)) - warn_if_shadowing (parm); - } - return arg_types; - } -} - -/* Allocate and initialize a c_arg_info structure from the parser's - obstack. */ - -struct c_arg_info * -build_arg_info (void) -{ - struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = NULL_TREE; - ret->tags = NULL; - ret->types = NULL_TREE; - ret->others = NULL_TREE; - ret->pending_sizes = NULL; - ret->had_vla_unspec = 0; - return ret; -} - -/* Take apart the current scope and return a c_arg_info structure with - info on a parameter list just parsed. - - This structure is later fed to 'grokparms' and 'store_parm_decls'. - - ELLIPSIS being true means the argument list ended in '...' so don't - append a sentinel (void_list_node) to the end of the type-list. - - EXPR is NULL or an expression that needs to be evaluated for the - side effects of array size expressions in the parameters. */ - -struct c_arg_info * -get_parm_info (bool ellipsis, tree expr) -{ - struct c_binding *b = current_scope->bindings; - struct c_arg_info *arg_info = build_arg_info (); - - tree parms = NULL_TREE; - vec *tags = NULL; - tree types = NULL_TREE; - tree others = NULL_TREE; - - bool gave_void_only_once_err = false; - - arg_info->had_vla_unspec = current_scope->had_vla_unspec; - - /* The bindings in this scope must not get put into a block. - We will take care of deleting the binding nodes. */ - current_scope->bindings = 0; - - /* This function is only called if there was *something* on the - parameter list. */ - gcc_assert (b); - - /* A parameter list consisting solely of 'void' indicates that the - function takes no arguments. But if the 'void' is qualified - (by 'const' or 'volatile'), or has a storage class specifier - ('register'), then the behavior is undefined; issue an error. - Typedefs for 'void' are OK (see DR#157). */ - if (b->prev == 0 /* one binding */ - && TREE_CODE (b->decl) == PARM_DECL /* which is a parameter */ - && !DECL_NAME (b->decl) /* anonymous */ - && VOID_TYPE_P (TREE_TYPE (b->decl))) /* of void type */ - { - if (TYPE_QUALS (TREE_TYPE (b->decl)) != TYPE_UNQUALIFIED - || C_DECL_REGISTER (b->decl)) - error_at (b->locus, "% as only parameter may not be qualified"); - - /* There cannot be an ellipsis. */ - if (ellipsis) - error_at (b->locus, "% must be the only parameter"); - - arg_info->types = void_list_node; - return arg_info; - } - - if (!ellipsis) - types = void_list_node; - - /* Break up the bindings list into parms, tags, types, and others; - apply sanity checks; purge the name-to-decl bindings. */ - while (b) - { - tree decl = b->decl; - tree type = TREE_TYPE (decl); - c_arg_tag tag; - const char *keyword; - - switch (TREE_CODE (decl)) - { - case PARM_DECL: - if (b->id) - { - gcc_assert (I_SYMBOL_BINDING (b->id) == b); - I_SYMBOL_BINDING (b->id) = b->shadowed; - } - - /* Check for forward decls that never got their actual decl. */ - if (TREE_ASM_WRITTEN (decl)) - error_at (b->locus, - "parameter %q+D has just a forward declaration", decl); - /* Check for (..., void, ...) and issue an error. */ - else if (VOID_TYPE_P (type) && !DECL_NAME (decl)) - { - if (!gave_void_only_once_err) - { - error_at (b->locus, "% must be the only parameter"); - gave_void_only_once_err = true; - } - } - else - { - /* Valid parameter, add it to the list. */ - DECL_CHAIN (decl) = parms; - parms = decl; - - /* Since there is a prototype, args are passed in their - declared types. The back end may override this later. */ - DECL_ARG_TYPE (decl) = type; - types = tree_cons (0, type, types); - } - break; - - case ENUMERAL_TYPE: keyword = "enum"; goto tag; - case UNION_TYPE: keyword = "union"; goto tag; - case RECORD_TYPE: keyword = "struct"; goto tag; - tag: - /* Types may not have tag-names, in which case the type - appears in the bindings list with b->id NULL. */ - if (b->id) - { - gcc_assert (I_TAG_BINDING (b->id) == b); - I_TAG_BINDING (b->id) = b->shadowed; - } - - /* Warn about any struct, union or enum tags defined in a - parameter list. The scope of such types is limited to - the parameter list, which is rarely if ever desirable - (it's impossible to call such a function with type- - correct arguments). An anonymous union parm type is - meaningful as a GNU extension, so don't warn for that. */ - if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE) - { - if (b->id) - /* The %s will be one of 'struct', 'union', or 'enum'. */ - warning_at (b->locus, 0, - "%<%s %E%> declared inside parameter list" - " will not be visible outside of this definition or" - " declaration", keyword, b->id); - else - /* The %s will be one of 'struct', 'union', or 'enum'. */ - warning_at (b->locus, 0, - "anonymous %s declared inside parameter list" - " will not be visible outside of this definition or" - " declaration", keyword); - } - - tag.id = b->id; - tag.type = decl; - vec_safe_push (tags, tag); - break; - - case FUNCTION_DECL: - /* FUNCTION_DECLs appear when there is an implicit function - declaration in the parameter list. */ - gcc_assert (b->nested || seen_error ()); - goto set_shadowed; - - case CONST_DECL: - case TYPE_DECL: - /* CONST_DECLs appear here when we have an embedded enum, - and TYPE_DECLs appear here when we have an embedded struct - or union. No warnings for this - we already warned about the - type itself. */ - - /* When we reinsert this decl in the function body, we need - to reconstruct whether it was marked as nested. */ - gcc_assert (!b->nested); - DECL_CHAIN (decl) = others; - others = decl; - /* fall through */ - - case ERROR_MARK: - set_shadowed: - /* error_mark_node appears here when we have an undeclared - variable. Just throw it away. */ - if (b->id) - { - gcc_assert (I_SYMBOL_BINDING (b->id) == b); - I_SYMBOL_BINDING (b->id) = b->shadowed; - } - break; - - /* Other things that might be encountered. */ - case LABEL_DECL: - case VAR_DECL: - default: - gcc_unreachable (); - } - - b = free_binding_and_advance (b); - } - - arg_info->parms = parms; - arg_info->tags = tags; - arg_info->types = types; - arg_info->others = others; - arg_info->pending_sizes = expr; - return arg_info; -} - -/* Get the struct, enum or union (CODE says which) with tag NAME. - Define the tag as a forward-reference with location LOC if it is - not defined. HAVE_STD_ATTRS says whether any standard attributes - were present after the struct, union or enum keyword; ATTRS are the - standard attributes present there. Return a c_typespec structure - for the type specifier. */ - -struct c_typespec -parser_xref_tag (location_t loc, enum tree_code code, tree name, - bool have_std_attrs, tree attrs) -{ - struct c_typespec ret; - tree ref; - location_t refloc; - - ret.expr = NULL_TREE; - ret.expr_const_operands = true; - - /* If a cross reference is requested, look up the type - already defined for this tag and return it. */ - - ref = lookup_tag (code, name, false, &refloc); - /* If this is the right type of tag, return what we found. - (This reference will be shadowed by shadow_tag later if appropriate.) - If this is the wrong type of tag, do not return it. If it was the - wrong type in the same scope, we will have had an error - message already; if in a different scope and declaring - a name, pending_xref_error will give an error message; but if in a - different scope and not declaring a name, this tag should - shadow the previous declaration of a different type of tag, and - this would not work properly if we return the reference found. - (For example, with "struct foo" in an outer scope, "union foo;" - must shadow that tag with a new one of union type.) */ - ret.kind = (ref - ? (have_std_attrs ? ctsk_tagref_attrs : ctsk_tagref) - : (have_std_attrs ? ctsk_tagfirstref_attrs : ctsk_tagfirstref)); - if (ref && TREE_CODE (ref) == code) - { - decl_attributes (&ref, attrs, (int) ATTR_FLAG_TYPE_IN_PLACE); - if (C_TYPE_DEFINED_IN_STRUCT (ref) - && loc != UNKNOWN_LOCATION - && warn_cxx_compat) - { - switch (code) - { - case ENUMERAL_TYPE: - warning_at (loc, OPT_Wc___compat, - ("enum type defined in struct or union " - "is not visible in C++")); - inform (refloc, "enum type defined here"); - break; - case RECORD_TYPE: - warning_at (loc, OPT_Wc___compat, - ("struct defined in struct or union " - "is not visible in C++")); - inform (refloc, "struct defined here"); - break; - case UNION_TYPE: - warning_at (loc, OPT_Wc___compat, - ("union defined in struct or union " - "is not visible in C++")); - inform (refloc, "union defined here"); - break; - default: - gcc_unreachable(); - } - } - - ret.spec = ref; - return ret; - } - - /* If no such tag is yet defined, create a forward-reference node - and record it as the "definition". - When a real declaration of this type is found, - the forward-reference will be altered into a real type. */ - - ref = make_node (code); - if (code == ENUMERAL_TYPE) - { - /* Give the type a default layout like unsigned int - to avoid crashing if it does not get defined. */ - SET_TYPE_MODE (ref, TYPE_MODE (unsigned_type_node)); - SET_TYPE_ALIGN (ref, TYPE_ALIGN (unsigned_type_node)); - TYPE_USER_ALIGN (ref) = 0; - TYPE_UNSIGNED (ref) = 1; - TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node); - TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node); - TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); - } - - pushtag (loc, name, ref); - decl_attributes (&ref, attrs, (int) ATTR_FLAG_TYPE_IN_PLACE); - - ret.spec = ref; - return ret; -} - -/* Get the struct, enum or union (CODE says which) with tag NAME. - Define the tag as a forward-reference if it is not defined. - Return a tree for the type. */ - -tree -xref_tag (enum tree_code code, tree name) -{ - return parser_xref_tag (input_location, code, name, false, NULL_TREE).spec; -} - -/* Make sure that the tag NAME is defined *in the current scope* - at least as a forward reference. - LOC is the location of the struct's definition. - CODE says which kind of tag NAME ought to be. - - This stores the current value of the file static STRUCT_PARSE_INFO - in *ENCLOSING_STRUCT_PARSE_INFO, and points STRUCT_PARSE_INFO at a - new c_struct_parse_info structure. The old value of - STRUCT_PARSE_INFO is restored in finish_struct. */ - -tree -start_struct (location_t loc, enum tree_code code, tree name, - class c_struct_parse_info **enclosing_struct_parse_info) -{ - /* If there is already a tag defined at this scope - (as a forward reference), just return it. */ - - tree ref = NULL_TREE; - location_t refloc = UNKNOWN_LOCATION; - - if (name != NULL_TREE) - ref = lookup_tag (code, name, true, &refloc); - if (ref && TREE_CODE (ref) == code) - { - if (TYPE_STUB_DECL (ref)) - refloc = DECL_SOURCE_LOCATION (TYPE_STUB_DECL (ref)); - - if (TYPE_SIZE (ref)) - { - if (code == UNION_TYPE) - error_at (loc, "redefinition of %", name); - else - error_at (loc, "redefinition of %", name); - if (refloc != UNKNOWN_LOCATION) - inform (refloc, "originally defined here"); - /* Don't create structures using a name already in use. */ - ref = NULL_TREE; - } - else if (C_TYPE_BEING_DEFINED (ref)) - { - if (code == UNION_TYPE) - error_at (loc, "nested redefinition of %", name); - else - error_at (loc, "nested redefinition of %", name); - /* Don't bother to report "originally defined here" for a - nested redefinition; the original definition should be - obvious. */ - /* Don't create structures that contain themselves. */ - ref = NULL_TREE; - } - } - - /* Otherwise create a forward-reference just so the tag is in scope. */ - - if (ref == NULL_TREE || TREE_CODE (ref) != code) - { - ref = make_node (code); - pushtag (loc, name, ref); - } - - C_TYPE_BEING_DEFINED (ref) = 1; - for (tree v = TYPE_MAIN_VARIANT (ref); v; v = TYPE_NEXT_VARIANT (v)) - TYPE_PACKED (v) = flag_pack_struct; - - *enclosing_struct_parse_info = struct_parse_info; - struct_parse_info = new c_struct_parse_info (); - - /* FIXME: This will issue a warning for a use of a type defined - within a statement expr used within sizeof, et. al. This is not - terribly serious as C++ doesn't permit statement exprs within - sizeof anyhow. */ - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) - warning_at (loc, OPT_Wc___compat, - "defining type in %qs expression is invalid in C++", - (in_sizeof - ? "sizeof" - : (in_typeof ? "typeof" : "alignof"))); - - return ref; -} - -/* Process the specs, declarator and width (NULL if omitted) - of a structure component, returning a FIELD_DECL node. - WIDTH is non-NULL for bit-fields only, and is an INTEGER_CST node. - DECL_ATTRS is as for grokdeclarator. - - LOC is the location of the structure component. - - This is done during the parsing of the struct declaration. - The FIELD_DECL nodes are chained together and the lot of them - are ultimately passed to `build_struct' to make the RECORD_TYPE node. */ - -tree -grokfield (location_t loc, - struct c_declarator *declarator, struct c_declspecs *declspecs, - tree width, tree *decl_attrs) -{ - tree value; - - if (declarator->kind == cdk_id && declarator->u.id.id == NULL_TREE - && width == NULL_TREE) - { - /* This is an unnamed decl. - - If we have something of the form "union { list } ;" then this - is the anonymous union extension. Similarly for struct. - - If this is something of the form "struct foo;", then - If MS or Plan 9 extensions are enabled, this is handled as - an anonymous struct. - Otherwise this is a forward declaration of a structure tag. - - If this is something of the form "foo;" and foo is a TYPE_DECL, then - If foo names a structure or union without a tag, then this - is an anonymous struct (this is permitted by C11). - If MS or Plan 9 extensions are enabled and foo names a - structure, then again this is an anonymous struct. - Otherwise this is an error. - - Oh what a horrid tangled web we weave. I wonder if MS consciously - took this from Plan 9 or if it was an accident of implementation - that took root before someone noticed the bug... */ - - tree type = declspecs->type; - bool ok = false; - - if (RECORD_OR_UNION_TYPE_P (type) - && (flag_ms_extensions - || flag_plan9_extensions - || !declspecs->typedef_p)) - { - if (flag_ms_extensions || flag_plan9_extensions) - ok = true; - else if (TYPE_NAME (type) == NULL) - ok = true; - else - ok = false; - } - if (!ok) - { - pedwarn (loc, 0, "declaration does not declare anything"); - return NULL_TREE; - } - if (flag_isoc99) - pedwarn_c99 (loc, OPT_Wpedantic, - "ISO C99 doesn%'t support unnamed structs/unions"); - else - pedwarn_c99 (loc, OPT_Wpedantic, - "ISO C90 doesn%'t support unnamed structs/unions"); - } - - value = grokdeclarator (declarator, declspecs, FIELD, false, - width ? &width : NULL, decl_attrs, NULL, NULL, - DEPRECATED_NORMAL); - - finish_decl (value, loc, NULL_TREE, NULL_TREE, NULL_TREE); - DECL_INITIAL (value) = width; - if (width) - SET_DECL_C_BIT_FIELD (value); - - if (warn_cxx_compat && DECL_NAME (value) != NULL_TREE) - { - /* If we currently have a binding for this field, set the - in_struct field in the binding, so that we warn about lookups - which find it. */ - struct c_binding *b = I_SYMBOL_BINDING (DECL_NAME (value)); - if (b != NULL) - { - /* If the in_struct field is not yet set, push it on a list - to be cleared when this struct is finished. */ - if (!b->in_struct) - { - struct_parse_info->fields.safe_push (b); - b->in_struct = 1; - } - } - } - - return value; -} - -/* Subroutine of detect_field_duplicates: return whether X and Y, - which are both fields in the same struct, have duplicate field - names. */ - -static bool -is_duplicate_field (tree x, tree y) -{ - if (DECL_NAME (x) != NULL_TREE && DECL_NAME (x) == DECL_NAME (y)) - return true; - - /* When using -fplan9-extensions, an anonymous field whose name is a - typedef can duplicate a field name. */ - if (flag_plan9_extensions - && (DECL_NAME (x) == NULL_TREE || DECL_NAME (y) == NULL_TREE)) - { - tree xt, xn, yt, yn; - - xt = TREE_TYPE (x); - if (DECL_NAME (x) != NULL_TREE) - xn = DECL_NAME (x); - else if (RECORD_OR_UNION_TYPE_P (xt) - && TYPE_NAME (xt) != NULL_TREE - && TREE_CODE (TYPE_NAME (xt)) == TYPE_DECL) - xn = DECL_NAME (TYPE_NAME (xt)); - else - xn = NULL_TREE; - - yt = TREE_TYPE (y); - if (DECL_NAME (y) != NULL_TREE) - yn = DECL_NAME (y); - else if (RECORD_OR_UNION_TYPE_P (yt) - && TYPE_NAME (yt) != NULL_TREE - && TREE_CODE (TYPE_NAME (yt)) == TYPE_DECL) - yn = DECL_NAME (TYPE_NAME (yt)); - else - yn = NULL_TREE; - - if (xn != NULL_TREE && xn == yn) - return true; - } - - return false; -} - -/* Subroutine of detect_field_duplicates: add the fields of FIELDLIST - to HTAB, giving errors for any duplicates. */ - -static void -detect_field_duplicates_hash (tree fieldlist, - hash_table > *htab) -{ - tree x, y; - tree_node **slot; - - for (x = fieldlist; x ; x = DECL_CHAIN (x)) - if ((y = DECL_NAME (x)) != NULL_TREE) - { - slot = htab->find_slot (y, INSERT); - if (*slot) - { - error ("duplicate member %q+D", x); - DECL_NAME (x) = NULL_TREE; - } - *slot = y; - } - else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) - { - detect_field_duplicates_hash (TYPE_FIELDS (TREE_TYPE (x)), htab); - - /* When using -fplan9-extensions, an anonymous field whose - name is a typedef can duplicate a field name. */ - if (flag_plan9_extensions - && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE - && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL) - { - tree xn = DECL_NAME (TYPE_NAME (TREE_TYPE (x))); - slot = htab->find_slot (xn, INSERT); - if (*slot) - error ("duplicate member %q+D", TYPE_NAME (TREE_TYPE (x))); - *slot = xn; - } - } -} - -/* Generate an error for any duplicate field names in FIELDLIST. Munge - the list such that this does not present a problem later. */ - -static void -detect_field_duplicates (tree fieldlist) -{ - tree x, y; - int timeout = 10; - - /* If the struct is the list of instance variables of an Objective-C - class, then we need to check all the instance variables of - superclasses when checking for duplicates (since you can't have - an instance variable in a subclass with the same name as an - instance variable in a superclass). We pass on this job to the - Objective-C compiler. objc_detect_field_duplicates() will return - false if we are not checking the list of instance variables and - the C frontend should proceed with the standard field duplicate - checks. If we are checking the list of instance variables, the - ObjC frontend will do the check, emit the errors if needed, and - then return true. */ - if (c_dialect_objc ()) - if (objc_detect_field_duplicates (false)) - return; - - /* First, see if there are more than "a few" fields. - This is trivially true if there are zero or one fields. */ - if (!fieldlist || !DECL_CHAIN (fieldlist)) - return; - x = fieldlist; - do { - timeout--; - if (DECL_NAME (x) == NULL_TREE - && RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) - timeout = 0; - x = DECL_CHAIN (x); - } while (timeout > 0 && x); - - /* If there were "few" fields and no anonymous structures or unions, - avoid the overhead of allocating a hash table. Instead just do - the nested traversal thing. */ - if (timeout > 0) - { - for (x = DECL_CHAIN (fieldlist); x; x = DECL_CHAIN (x)) - /* When using -fplan9-extensions, we can have duplicates - between typedef names and fields. */ - if (DECL_NAME (x) - || (flag_plan9_extensions - && DECL_NAME (x) == NULL_TREE - && RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)) - && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE - && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL)) - { - for (y = fieldlist; y != x; y = TREE_CHAIN (y)) - if (is_duplicate_field (y, x)) - { - error ("duplicate member %q+D", x); - DECL_NAME (x) = NULL_TREE; - } - } - } - else - { - hash_table > htab (37); - detect_field_duplicates_hash (fieldlist, &htab); - } -} - -/* Finish up struct info used by -Wc++-compat. */ - -static void -warn_cxx_compat_finish_struct (tree fieldlist, enum tree_code code, - location_t record_loc) -{ - unsigned int ix; - tree x; - struct c_binding *b; - - if (fieldlist == NULL_TREE) - { - if (code == RECORD_TYPE) - warning_at (record_loc, OPT_Wc___compat, - "empty struct has size 0 in C, size 1 in C++"); - else - warning_at (record_loc, OPT_Wc___compat, - "empty union has size 0 in C, size 1 in C++"); - } - - /* Set the C_TYPE_DEFINED_IN_STRUCT flag for each type defined in - the current struct. We do this now at the end of the struct - because the flag is used to issue visibility warnings, and we - only want to issue those warnings if the type is referenced - outside of the struct declaration. */ - FOR_EACH_VEC_ELT (struct_parse_info->struct_types, ix, x) - C_TYPE_DEFINED_IN_STRUCT (x) = 1; - - /* The TYPEDEFS_SEEN field of STRUCT_PARSE_INFO is a list of - typedefs used when declaring fields in this struct. If the name - of any of the fields is also a typedef name then the struct would - not parse in C++, because the C++ lookup rules say that the - typedef name would be looked up in the context of the struct, and - would thus be the field rather than the typedef. */ - if (!struct_parse_info->typedefs_seen.is_empty () - && fieldlist != NULL_TREE) - { - /* Use a hash_set using the name of the typedef. We can use - a hash_set because identifiers are interned. */ - hash_set tset; - - FOR_EACH_VEC_ELT (struct_parse_info->typedefs_seen, ix, x) - tset.add (DECL_NAME (x)); - - for (x = fieldlist; x != NULL_TREE; x = DECL_CHAIN (x)) - { - if (DECL_NAME (x) != NULL_TREE - && tset.contains (DECL_NAME (x))) - { - warning_at (DECL_SOURCE_LOCATION (x), OPT_Wc___compat, - ("using %qD as both field and typedef name is " - "invalid in C++"), - x); - /* FIXME: It would be nice to report the location where - the typedef name is used. */ - } - } - } - - /* For each field which has a binding and which was not defined in - an enclosing struct, clear the in_struct field. */ - FOR_EACH_VEC_ELT (struct_parse_info->fields, ix, b) - b->in_struct = 0; -} - -/* Function to help qsort sort FIELD_DECLs by name order. */ - -static int -field_decl_cmp (const void *x_p, const void *y_p) -{ - const tree *const x = (const tree *) x_p; - const tree *const y = (const tree *) y_p; - - if (DECL_NAME (*x) == DECL_NAME (*y)) - /* A nontype is "greater" than a type. */ - return (TREE_CODE (*y) == TYPE_DECL) - (TREE_CODE (*x) == TYPE_DECL); - if (DECL_NAME (*x) == NULL_TREE) - return -1; - if (DECL_NAME (*y) == NULL_TREE) - return 1; - if (DECL_NAME (*x) < DECL_NAME (*y)) - return -1; - return 1; -} - -/* If this structure or union completes the type of any previous - variable declaration, lay it out and output its rtl. */ -static void -finish_incomplete_vars (tree incomplete_vars, bool toplevel) -{ - for (tree x = incomplete_vars; x; x = TREE_CHAIN (x)) - { - tree decl = TREE_VALUE (x); - if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) - layout_array_type (TREE_TYPE (decl)); - if (TREE_CODE (decl) != TYPE_DECL) - { - relayout_decl (decl); - if (c_dialect_objc ()) - objc_check_decl (decl); - rest_of_decl_compilation (decl, toplevel, 0); - } - } -} - -/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T. - LOC is the location of the RECORD_TYPE or UNION_TYPE's definition. - FIELDLIST is a chain of FIELD_DECL nodes for the fields. - ATTRIBUTES are attributes to be applied to the structure. - - ENCLOSING_STRUCT_PARSE_INFO is the value of STRUCT_PARSE_INFO when - the struct was started. */ - -tree -finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, - class c_struct_parse_info *enclosing_struct_parse_info) -{ - tree x; - bool toplevel = file_scope == current_scope; - - /* If this type was previously laid out as a forward reference, - make sure we lay it out again. */ - - TYPE_SIZE (t) = NULL_TREE; - - decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); - - if (pedantic) - { - for (x = fieldlist; x; x = DECL_CHAIN (x)) - { - if (DECL_NAME (x) != NULL_TREE) - break; - if (flag_isoc11 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) - break; - } - - if (x == NULL_TREE) - { - if (TREE_CODE (t) == UNION_TYPE) - { - if (fieldlist) - pedwarn (loc, OPT_Wpedantic, "union has no named members"); - else - pedwarn (loc, OPT_Wpedantic, "union has no members"); - } - else - { - if (fieldlist) - pedwarn (loc, OPT_Wpedantic, "struct has no named members"); - else - pedwarn (loc, OPT_Wpedantic, "struct has no members"); - } - } - } - - /* Install struct as DECL_CONTEXT of each field decl. - Also process specified field sizes, found in the DECL_INITIAL, - storing 0 there after the type has been changed to precision equal - to its width, rather than the precision of the specified standard - type. (Correct layout requires the original type to have been preserved - until now.) */ - - bool saw_named_field = false; - for (x = fieldlist; x; x = DECL_CHAIN (x)) - { - if (TREE_TYPE (x) == error_mark_node) - continue; - - DECL_CONTEXT (x) = t; - - /* If any field is const, the structure type is pseudo-const. */ - if (TREE_READONLY (x)) - C_TYPE_FIELDS_READONLY (t) = 1; - else - { - /* A field that is pseudo-const makes the structure likewise. */ - tree t1 = strip_array_types (TREE_TYPE (x)); - if (RECORD_OR_UNION_TYPE_P (t1) && C_TYPE_FIELDS_READONLY (t1)) - C_TYPE_FIELDS_READONLY (t) = 1; - } - - /* Any field that is volatile means variables of this type must be - treated in some ways as volatile. */ - if (TREE_THIS_VOLATILE (x)) - C_TYPE_FIELDS_VOLATILE (t) = 1; - - /* Any field of nominal variable size implies structure is too. */ - if (C_DECL_VARIABLE_SIZE (x)) - C_TYPE_VARIABLE_SIZE (t) = 1; - - if (DECL_C_BIT_FIELD (x)) - { - unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x)); - DECL_SIZE (x) = bitsize_int (width); - DECL_BIT_FIELD (x) = 1; - } - - if (TYPE_PACKED (t) - && (DECL_BIT_FIELD (x) - || TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT)) - DECL_PACKED (x) = 1; - - /* Detect flexible array member in an invalid context. */ - if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE - && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE - && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE - && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE) - { - if (TREE_CODE (t) == UNION_TYPE) - { - error_at (DECL_SOURCE_LOCATION (x), - "flexible array member in union"); - TREE_TYPE (x) = error_mark_node; - } - else if (DECL_CHAIN (x) != NULL_TREE) - { - error_at (DECL_SOURCE_LOCATION (x), - "flexible array member not at end of struct"); - TREE_TYPE (x) = error_mark_node; - } - else if (!saw_named_field) - { - error_at (DECL_SOURCE_LOCATION (x), - "flexible array member in a struct with no named " - "members"); - TREE_TYPE (x) = error_mark_node; - } - } - - if (pedantic && TREE_CODE (t) == RECORD_TYPE - && flexible_array_type_p (TREE_TYPE (x))) - pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, - "invalid use of structure with flexible array member"); - - if (DECL_NAME (x) - || RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) - saw_named_field = true; - } - - detect_field_duplicates (fieldlist); - - /* Now we have the nearly final fieldlist. Record it, - then lay out the structure or union (including the fields). */ - - TYPE_FIELDS (t) = fieldlist; - - maybe_apply_pragma_scalar_storage_order (t); - - layout_type (t); - - if (TYPE_SIZE_UNIT (t) - && TREE_CODE (TYPE_SIZE_UNIT (t)) == INTEGER_CST - && !TREE_OVERFLOW (TYPE_SIZE_UNIT (t)) - && !valid_constant_size_p (TYPE_SIZE_UNIT (t))) - error ("type %qT is too large", t); - - /* Give bit-fields their proper types and rewrite the type of array fields - with scalar component if the enclosing type has reverse storage order. */ - for (tree field = fieldlist; field; field = DECL_CHAIN (field)) - { - if (TREE_CODE (field) == FIELD_DECL - && DECL_INITIAL (field) - && TREE_TYPE (field) != error_mark_node) - { - unsigned HOST_WIDE_INT width - = tree_to_uhwi (DECL_INITIAL (field)); - tree type = TREE_TYPE (field); - if (width != TYPE_PRECISION (type)) - { - TREE_TYPE (field) - = c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type)); - SET_DECL_MODE (field, TYPE_MODE (TREE_TYPE (field))); - } - DECL_INITIAL (field) = NULL_TREE; - } - else if (TYPE_REVERSE_STORAGE_ORDER (t) - && TREE_CODE (field) == FIELD_DECL - && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE) - { - tree ftype = TREE_TYPE (field); - tree ctype = strip_array_types (ftype); - if (!RECORD_OR_UNION_TYPE_P (ctype) && TYPE_MODE (ctype) != QImode) - { - tree fmain_type = TYPE_MAIN_VARIANT (ftype); - tree *typep = &fmain_type; - do { - *typep = build_distinct_type_copy (*typep); - TYPE_REVERSE_STORAGE_ORDER (*typep) = 1; - typep = &TREE_TYPE (*typep); - } while (TREE_CODE (*typep) == ARRAY_TYPE); - TREE_TYPE (field) - = c_build_qualified_type (fmain_type, TYPE_QUALS (ftype)); - } - } - - /* Warn on problematic type punning for storage order purposes. */ - if (TREE_CODE (t) == UNION_TYPE - && TREE_CODE (field) == FIELD_DECL - && AGGREGATE_TYPE_P (TREE_TYPE (field))) - { - tree ftype = TREE_TYPE (field); - if (TREE_CODE (ftype) == ARRAY_TYPE) - ftype = strip_array_types (ftype); - if (RECORD_OR_UNION_TYPE_P (ftype) - && TYPE_REVERSE_STORAGE_ORDER (ftype) - != TYPE_REVERSE_STORAGE_ORDER (t)) - warning_at (DECL_SOURCE_LOCATION (field), - OPT_Wscalar_storage_order, - "type punning toggles scalar storage order"); - } - } - - /* Now we have the truly final field list. - Store it in this type and in the variants. */ - - TYPE_FIELDS (t) = fieldlist; - - /* If there are lots of fields, sort so we can look through them fast. - We arbitrarily consider 16 or more elts to be "a lot". */ - - { - int len = 0; - - for (x = fieldlist; x; x = DECL_CHAIN (x)) - { - if (len > 15 || DECL_NAME (x) == NULL) - break; - len += 1; - } - - if (len > 15) - { - tree *field_array; - struct lang_type *space; - struct sorted_fields_type *space2; - - len += list_length (x); - - /* Use the same allocation policy here that make_node uses, to - ensure that this lives as long as the rest of the struct decl. - All decls in an inline function need to be saved. */ - - space = ggc_cleared_alloc (); - space2 = (sorted_fields_type *) ggc_internal_alloc - (sizeof (struct sorted_fields_type) + len * sizeof (tree)); - - len = 0; - space->s = space2; - field_array = &space2->elts[0]; - for (x = fieldlist; x; x = DECL_CHAIN (x)) - { - field_array[len++] = x; - - /* If there is anonymous struct or union, break out of the loop. */ - if (DECL_NAME (x) == NULL) - break; - } - /* Found no anonymous struct/union. Add the TYPE_LANG_SPECIFIC. */ - if (x == NULL) - { - TYPE_LANG_SPECIFIC (t) = space; - TYPE_LANG_SPECIFIC (t)->s->len = len; - field_array = TYPE_LANG_SPECIFIC (t)->s->elts; - qsort (field_array, len, sizeof (tree), field_decl_cmp); - } - } - } - - /* If this was supposed to be a transparent union, but we can't - make it one, warn and turn off the flag. */ - if (TREE_CODE (t) == UNION_TYPE - && TYPE_TRANSPARENT_AGGR (t) - && (!TYPE_FIELDS (t) || TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t)))) - { - TYPE_TRANSPARENT_AGGR (t) = 0; - warning_at (loc, 0, "union cannot be made transparent"); - } - - tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)); - for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) - { - TYPE_FIELDS (x) = TYPE_FIELDS (t); - TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t); - TYPE_TRANSPARENT_AGGR (x) = TYPE_TRANSPARENT_AGGR (t); - C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t); - C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t); - C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); - C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE; - } - - /* Update type location to the one of the definition, instead of e.g. - a forward declaration. */ - if (TYPE_STUB_DECL (t)) - DECL_SOURCE_LOCATION (TYPE_STUB_DECL (t)) = loc; - - /* Finish debugging output for this type. */ - rest_of_type_compilation (t, toplevel); - - finish_incomplete_vars (incomplete_vars, toplevel); - - /* If we're inside a function proper, i.e. not file-scope and not still - parsing parameters, then arrange for the size of a variable sized type - to be bound now. */ - if (building_stmt_list_p () && variably_modified_type_p (t, NULL_TREE)) - add_stmt (build_stmt (loc, - DECL_EXPR, build_decl (loc, TYPE_DECL, NULL, t))); - - if (warn_cxx_compat) - warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc); - - delete struct_parse_info; - - struct_parse_info = enclosing_struct_parse_info; - - /* If this struct is defined inside a struct, add it to - struct_types. */ - if (warn_cxx_compat - && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) - struct_parse_info->struct_types.safe_push (t); - - return t; -} - -static struct { - gt_pointer_operator new_value; - void *cookie; -} resort_data; - -/* This routine compares two fields like field_decl_cmp but using the -pointer operator in resort_data. */ - -static int -resort_field_decl_cmp (const void *x_p, const void *y_p) -{ - const tree *const x = (const tree *) x_p; - const tree *const y = (const tree *) y_p; - - if (DECL_NAME (*x) == DECL_NAME (*y)) - /* A nontype is "greater" than a type. */ - return (TREE_CODE (*y) == TYPE_DECL) - (TREE_CODE (*x) == TYPE_DECL); - if (DECL_NAME (*x) == NULL_TREE) - return -1; - if (DECL_NAME (*y) == NULL_TREE) - return 1; - { - tree d1 = DECL_NAME (*x); - tree d2 = DECL_NAME (*y); - resort_data.new_value (&d1, &d1, resort_data.cookie); - resort_data.new_value (&d2, &d2, resort_data.cookie); - if (d1 < d2) - return -1; - } - return 1; -} - -/* Resort DECL_SORTED_FIELDS because pointers have been reordered. */ - -void -resort_sorted_fields (void *obj, - void * ARG_UNUSED (orig_obj), - gt_pointer_operator new_value, - void *cookie) -{ - struct sorted_fields_type *sf = (struct sorted_fields_type *) obj; - resort_data.new_value = new_value; - resort_data.cookie = cookie; - qsort (&sf->elts[0], sf->len, sizeof (tree), - resort_field_decl_cmp); -} - -/* Lay out the type T, and its element type, and so on. */ - -static void -layout_array_type (tree t) -{ - if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) - layout_array_type (TREE_TYPE (t)); - layout_type (t); -} - -/* Begin compiling the definition of an enumeration type. - NAME is its name (or null if anonymous). - LOC is the enum's location. - Returns the type object, as yet incomplete. - Also records info about it so that build_enumerator - may be used to declare the individual values as they are read. */ - -tree -start_enum (location_t loc, struct c_enum_contents *the_enum, tree name) -{ - tree enumtype = NULL_TREE; - location_t enumloc = UNKNOWN_LOCATION; - - /* If this is the real definition for a previous forward reference, - fill in the contents in the same object that used to be the - forward reference. */ - - if (name != NULL_TREE) - enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc); - - if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE) - { - enumtype = make_node (ENUMERAL_TYPE); - pushtag (loc, name, enumtype); - } - /* Update type location to the one of the definition, instead of e.g. - a forward declaration. */ - else if (TYPE_STUB_DECL (enumtype)) - { - enumloc = DECL_SOURCE_LOCATION (TYPE_STUB_DECL (enumtype)); - DECL_SOURCE_LOCATION (TYPE_STUB_DECL (enumtype)) = loc; - } - - if (C_TYPE_BEING_DEFINED (enumtype)) - error_at (loc, "nested redefinition of %", name); - - C_TYPE_BEING_DEFINED (enumtype) = 1; - - if (TYPE_VALUES (enumtype) != NULL_TREE) - { - /* This enum is a named one that has been declared already. */ - error_at (loc, "redeclaration of %", name); - if (enumloc != UNKNOWN_LOCATION) - inform (enumloc, "originally defined here"); - - /* Completely replace its old definition. - The old enumerators remain defined, however. */ - TYPE_VALUES (enumtype) = NULL_TREE; - } - - the_enum->enum_next_value = integer_zero_node; - the_enum->enum_overflow = 0; - - if (flag_short_enums) - for (tree v = TYPE_MAIN_VARIANT (enumtype); v; v = TYPE_NEXT_VARIANT (v)) - TYPE_PACKED (v) = 1; - - /* FIXME: This will issue a warning for a use of a type defined - within sizeof in a statement expr. This is not terribly serious - as C++ doesn't permit statement exprs within sizeof anyhow. */ - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) - warning_at (loc, OPT_Wc___compat, - "defining type in %qs expression is invalid in C++", - (in_sizeof - ? "sizeof" - : (in_typeof ? "typeof" : "alignof"))); - - return enumtype; -} - -/* After processing and defining all the values of an enumeration type, - install their decls in the enumeration type and finish it off. - ENUMTYPE is the type object, VALUES a list of decl-value pairs, - and ATTRIBUTES are the specified attributes. - Returns ENUMTYPE. */ - -tree -finish_enum (tree enumtype, tree values, tree attributes) -{ - tree pair, tem; - tree minnode = NULL_TREE, maxnode = NULL_TREE; - int precision; - signop sign; - bool toplevel = (file_scope == current_scope); - struct lang_type *lt; - - decl_attributes (&enumtype, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); - - /* Calculate the maximum value of any enumerator in this type. */ - - if (values == error_mark_node) - minnode = maxnode = integer_zero_node; - else - { - minnode = maxnode = TREE_VALUE (values); - for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair)) - { - tree value = TREE_VALUE (pair); - if (tree_int_cst_lt (maxnode, value)) - maxnode = value; - if (tree_int_cst_lt (value, minnode)) - minnode = value; - } - } - - /* Construct the final type of this enumeration. It is the same - as one of the integral types - the narrowest one that fits, except - that normally we only go as narrow as int - and signed iff any of - the values are negative. */ - sign = (tree_int_cst_sgn (minnode) >= 0) ? UNSIGNED : SIGNED; - precision = MAX (tree_int_cst_min_precision (minnode, sign), - tree_int_cst_min_precision (maxnode, sign)); - - /* If the precision of the type was specified with an attribute and it - was too small, give an error. Otherwise, use it. */ - if (TYPE_PRECISION (enumtype) && lookup_attribute ("mode", attributes)) - { - if (precision > TYPE_PRECISION (enumtype)) - { - TYPE_PRECISION (enumtype) = 0; - error ("specified mode too small for enumerated values"); - } - else - precision = TYPE_PRECISION (enumtype); - } - else - TYPE_PRECISION (enumtype) = 0; - - if (TYPE_PACKED (enumtype) - || precision > TYPE_PRECISION (integer_type_node) - || TYPE_PRECISION (enumtype)) - { - tem = c_common_type_for_size (precision, sign == UNSIGNED ? 1 : 0); - if (tem == NULL) - { - warning (0, "enumeration values exceed range of largest integer"); - tem = long_long_integer_type_node; - } - } - else - tem = sign == UNSIGNED ? unsigned_type_node : integer_type_node; - - TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); - TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); - TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); - SET_TYPE_ALIGN (enumtype, TYPE_ALIGN (tem)); - TYPE_SIZE (enumtype) = NULL_TREE; - TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); - - layout_type (enumtype); - - if (values != error_mark_node) - { - /* Change the type of the enumerators to be the enum type. We - need to do this irrespective of the size of the enum, for - proper type checking. Replace the DECL_INITIALs of the - enumerators, and the value slots of the list, with copies - that have the enum type; they cannot be modified in place - because they may be shared (e.g. integer_zero_node) Finally, - change the purpose slots to point to the names of the decls. */ - for (pair = values; pair; pair = TREE_CHAIN (pair)) - { - tree enu = TREE_PURPOSE (pair); - tree ini = DECL_INITIAL (enu); - - TREE_TYPE (enu) = enumtype; - - /* The ISO C Standard mandates enumerators to have type int, - even though the underlying type of an enum type is - unspecified. However, GCC allows enumerators of any - integer type as an extensions. build_enumerator() - converts any enumerators that fit in an int to type int, - to avoid promotions to unsigned types when comparing - integers with enumerators that fit in the int range. - When -pedantic is given, build_enumerator() would have - already warned about those that don't fit. Here we - convert the rest to the enumerator type. */ - if (TREE_TYPE (ini) != integer_type_node) - ini = convert (enumtype, ini); - - DECL_INITIAL (enu) = ini; - TREE_PURPOSE (pair) = DECL_NAME (enu); - TREE_VALUE (pair) = ini; - } - - TYPE_VALUES (enumtype) = values; - } - - /* Record the min/max values so that we can warn about bit-field - enumerations that are too small for the values. */ - lt = ggc_cleared_alloc (); - lt->enum_min = minnode; - lt->enum_max = maxnode; - TYPE_LANG_SPECIFIC (enumtype) = lt; - - /* Fix up all variant types of this enum type. */ - tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (enumtype)); - for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem)) - { - C_TYPE_INCOMPLETE_VARS (tem) = NULL_TREE; - if (tem == enumtype) - continue; - TYPE_VALUES (tem) = TYPE_VALUES (enumtype); - TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype); - TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype); - TYPE_SIZE (tem) = TYPE_SIZE (enumtype); - TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype); - SET_TYPE_MODE (tem, TYPE_MODE (enumtype)); - TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype); - SET_TYPE_ALIGN (tem, TYPE_ALIGN (enumtype)); - TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype); - TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); - TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); - } - - /* Finish debugging output for this type. */ - rest_of_type_compilation (enumtype, toplevel); - - finish_incomplete_vars (incomplete_vars, toplevel); - - /* If this enum is defined inside a struct, add it to - struct_types. */ - if (warn_cxx_compat - && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) - struct_parse_info->struct_types.safe_push (enumtype); - - C_TYPE_BEING_DEFINED (enumtype) = 0; - - return enumtype; -} - -/* Build and install a CONST_DECL for one value of the - current enumeration type (one that was begun with start_enum). - DECL_LOC is the location of the enumerator. - LOC is the location of the '=' operator if any, DECL_LOC otherwise. - Return a tree-list containing the CONST_DECL and its value. - Assignment of sequential values by default is handled here. */ - -tree -build_enumerator (location_t decl_loc, location_t loc, - struct c_enum_contents *the_enum, tree name, tree value) -{ - tree decl, type; - - /* Validate and default VALUE. */ - - if (value != NULL_TREE) - { - /* Don't issue more errors for error_mark_node (i.e. an - undeclared identifier) - just ignore the value expression. */ - if (value == error_mark_node) - value = NULL_TREE; - else if (!INTEGRAL_TYPE_P (TREE_TYPE (value))) - { - error_at (loc, "enumerator value for %qE is not an integer constant", - name); - value = NULL_TREE; - } - else - { - if (TREE_CODE (value) != INTEGER_CST) - { - value = c_fully_fold (value, false, NULL); - if (TREE_CODE (value) == INTEGER_CST) - pedwarn (loc, OPT_Wpedantic, - "enumerator value for %qE is not an integer " - "constant expression", name); - } - if (TREE_CODE (value) != INTEGER_CST) - { - error ("enumerator value for %qE is not an integer constant", - name); - value = NULL_TREE; - } - else - { - value = default_conversion (value); - constant_expression_warning (value); - } - } - } - - /* Default based on previous value. */ - /* It should no longer be possible to have NON_LVALUE_EXPR - in the default. */ - if (value == NULL_TREE) - { - value = the_enum->enum_next_value; - if (the_enum->enum_overflow) - error_at (loc, "overflow in enumeration values"); - } - /* Even though the underlying type of an enum is unspecified, the - type of enumeration constants is explicitly defined as int - (6.4.4.3/2 in the C99 Standard). GCC allows any integer type as - an extension. */ - else if (!int_fits_type_p (value, integer_type_node)) - pedwarn (loc, OPT_Wpedantic, - "ISO C restricts enumerator values to range of %"); - - /* The ISO C Standard mandates enumerators to have type int, even - though the underlying type of an enum type is unspecified. - However, GCC allows enumerators of any integer type as an - extensions. Here we convert any enumerators that fit in an int - to type int, to avoid promotions to unsigned types when comparing - integers with enumerators that fit in the int range. When - -pedantic is given, we would have already warned about those that - don't fit. We have to do this here rather than in finish_enum - because this value may be used to define more enumerators. */ - if (int_fits_type_p (value, integer_type_node)) - value = convert (integer_type_node, value); - - /* Set basis for default for next value. */ - the_enum->enum_next_value - = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), - PLUS_EXPR, value, integer_one_node, false); - the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value); - - /* Now create a declaration for the enum value name. */ - - type = TREE_TYPE (value); - type = c_common_type_for_size (MAX (TYPE_PRECISION (type), - TYPE_PRECISION (integer_type_node)), - (TYPE_PRECISION (type) - >= TYPE_PRECISION (integer_type_node) - && TYPE_UNSIGNED (type))); - - decl = build_decl (decl_loc, CONST_DECL, name, type); - DECL_INITIAL (decl) = convert (type, value); - pushdecl (decl); - - return tree_cons (decl, value, NULL_TREE); -} - -/* Implement LANG_HOOKS_SIMULATE_ENUM_DECL. */ - -tree -c_simulate_enum_decl (location_t loc, const char *name, - vec *values_ptr) -{ - location_t saved_loc = input_location; - input_location = loc; - - struct c_enum_contents the_enum; - tree enumtype = start_enum (loc, &the_enum, get_identifier (name)); - - tree value_chain = NULL_TREE; - string_int_pair *value; - vec values = *values_ptr; - unsigned int i; - FOR_EACH_VEC_ELT (values, i, value) - { - tree decl = build_enumerator (loc, loc, &the_enum, - get_identifier (value->first), - build_int_cst (integer_type_node, - value->second)); - TREE_CHAIN (decl) = value_chain; - value_chain = decl; - } - - finish_enum (enumtype, nreverse (value_chain), NULL_TREE); - - input_location = saved_loc; - return enumtype; -} - -/* Implement LANG_HOOKS_SIMULATE_RECORD_DECL. */ - -tree -c_simulate_record_decl (location_t loc, const char *name, - array_slice fields) -{ - location_t saved_loc = input_location; - input_location = loc; - - class c_struct_parse_info *struct_info; - tree ident = get_identifier (name); - tree type = start_struct (loc, RECORD_TYPE, ident, &struct_info); - - for (unsigned int i = 0; i < fields.size (); ++i) - { - DECL_FIELD_CONTEXT (fields[i]) = type; - if (i > 0) - DECL_CHAIN (fields[i - 1]) = fields[i]; - } - - finish_struct (loc, type, fields[0], NULL_TREE, struct_info); - - tree decl = build_decl (loc, TYPE_DECL, ident, type); - set_underlying_type (decl); - lang_hooks.decls.pushdecl (decl); - - input_location = saved_loc; - return type; -} - -/* Create the FUNCTION_DECL for a function definition. - DECLSPECS, DECLARATOR and ATTRIBUTES are the parts of - the declaration; they describe the function's name and the type it returns, - but twisted together in a fashion that parallels the syntax of C. - - This function creates a binding context for the function body - as well as setting up the FUNCTION_DECL in current_function_decl. - - Returns true on success. If the DECLARATOR is not suitable for a function - (it defines a datum instead), we return false to report a parse error. */ - -bool -start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, - tree attributes) -{ - tree decl1, old_decl; - tree restype, resdecl; - location_t loc; - - current_function_returns_value = 0; /* Assume, until we see it does. */ - current_function_returns_null = 0; - current_function_returns_abnormally = 0; - warn_about_return_type = 0; - c_switch_stack = NULL; - - /* Indicate no valid break/continue context. */ - in_statement = 0; - - decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL, - &attributes, NULL, NULL, DEPRECATED_NORMAL); - invoke_plugin_callbacks (PLUGIN_START_PARSE_FUNCTION, decl1); - - /* If the declarator is not suitable for a function definition, - cause a syntax error. */ - if (decl1 == NULL_TREE - || TREE_CODE (decl1) != FUNCTION_DECL) - return false; - - loc = DECL_SOURCE_LOCATION (decl1); - - /* A nested function is not global. */ - if (current_function_decl != NULL_TREE) - TREE_PUBLIC (decl1) = 0; - - c_decl_attributes (&decl1, attributes, 0); - - if (DECL_DECLARED_INLINE_P (decl1) - && DECL_UNINLINABLE (decl1) - && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl1))) - warning_at (loc, OPT_Wattributes, - "inline function %qD given attribute %qs", - decl1, "noinline"); - - /* Handle gnu_inline attribute. */ - if (declspecs->inline_p - && !flag_gnu89_inline - && TREE_CODE (decl1) == FUNCTION_DECL - && (lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl1)) - || current_function_decl)) - { - if (declspecs->storage_class != csc_static) - DECL_EXTERNAL (decl1) = !DECL_EXTERNAL (decl1); - } - - announce_function (decl1); - - if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1)))) - { - error_at (loc, "return type is an incomplete type"); - /* Make it return void instead. */ - TREE_TYPE (decl1) - = build_function_type (void_type_node, - TYPE_ARG_TYPES (TREE_TYPE (decl1))); - } - - if (warn_about_return_type) - warn_defaults_to (loc, flag_isoc99 ? OPT_Wimplicit_int - : (warn_return_type > 0 ? OPT_Wreturn_type - : OPT_Wimplicit_int), - "return type defaults to %"); - - /* Make the init_value nonzero so pushdecl knows this is not tentative. - error_mark_node is replaced below (in pop_scope) with the BLOCK. */ - DECL_INITIAL (decl1) = error_mark_node; - - /* If this definition isn't a prototype and we had a prototype declaration - before, copy the arg type info from that prototype. */ - old_decl = lookup_name_in_scope (DECL_NAME (decl1), current_scope); - if (old_decl && TREE_CODE (old_decl) != FUNCTION_DECL) - old_decl = NULL_TREE; - - current_function_prototype_locus = UNKNOWN_LOCATION; - current_function_prototype_built_in = false; - current_function_prototype_arg_types = NULL_TREE; - tree newtype = TREE_TYPE (decl1); - tree oldtype = old_decl ? TREE_TYPE (old_decl) : newtype; - if (!prototype_p (newtype)) - { - tree oldrt = TREE_TYPE (oldtype); - tree newrt = TREE_TYPE (newtype); - if (old_decl != NULL_TREE - && TREE_CODE (oldtype) == FUNCTION_TYPE - && comptypes (oldrt, newrt)) - { - if (stdarg_p (oldtype)) - { - auto_diagnostic_group d; - warning_at (loc, 0, "%q+D defined as variadic function " - "without prototype", decl1); - locate_old_decl (old_decl); - } - TREE_TYPE (decl1) = composite_type (oldtype, newtype); - current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl); - current_function_prototype_built_in - = C_DECL_BUILTIN_PROTOTYPE (old_decl); - current_function_prototype_arg_types - = TYPE_ARG_TYPES (newtype); - } - if (TREE_PUBLIC (decl1)) - { - /* If there is an external prototype declaration of this - function, record its location but do not copy information - to this decl. This may be an invisible declaration - (built-in or in a scope which has finished) or simply - have more refined argument types than any declaration - found above. */ - struct c_binding *b; - for (b = I_SYMBOL_BINDING (DECL_NAME (decl1)); b; b = b->shadowed) - if (B_IN_SCOPE (b, external_scope)) - break; - if (b) - { - tree ext_decl, ext_type; - ext_decl = b->decl; - ext_type = b->u.type ? b->u.type : TREE_TYPE (ext_decl); - if (TREE_CODE (ext_type) == FUNCTION_TYPE - && comptypes (TREE_TYPE (TREE_TYPE (decl1)), - TREE_TYPE (ext_type))) - { - current_function_prototype_locus - = DECL_SOURCE_LOCATION (ext_decl); - current_function_prototype_built_in - = C_DECL_BUILTIN_PROTOTYPE (ext_decl); - current_function_prototype_arg_types - = TYPE_ARG_TYPES (ext_type); - } - } - } - } - - /* Optionally warn of old-fashioned def with no previous prototype. */ - if (warn_strict_prototypes - && old_decl != error_mark_node - && !prototype_p (TREE_TYPE (decl1)) - && C_DECL_ISNT_PROTOTYPE (old_decl)) - warning_at (loc, OPT_Wstrict_prototypes, - "function declaration isn%'t a prototype"); - /* Optionally warn of any global def with no previous prototype. */ - else if (warn_missing_prototypes - && old_decl != error_mark_node - && TREE_PUBLIC (decl1) - && !MAIN_NAME_P (DECL_NAME (decl1)) - && C_DECL_ISNT_PROTOTYPE (old_decl) - && !DECL_DECLARED_INLINE_P (decl1)) - warning_at (loc, OPT_Wmissing_prototypes, - "no previous prototype for %qD", decl1); - /* Optionally warn of any def with no previous prototype - if the function has already been used. */ - else if (warn_missing_prototypes - && old_decl != NULL_TREE - && old_decl != error_mark_node - && TREE_USED (old_decl) - && !prototype_p (TREE_TYPE (old_decl))) - warning_at (loc, OPT_Wmissing_prototypes, - "%qD was used with no prototype before its definition", decl1); - /* Optionally warn of any global def with no previous declaration. */ - else if (warn_missing_declarations - && TREE_PUBLIC (decl1) - && old_decl == NULL_TREE - && !MAIN_NAME_P (DECL_NAME (decl1)) - && !DECL_DECLARED_INLINE_P (decl1)) - warning_at (loc, OPT_Wmissing_declarations, - "no previous declaration for %qD", - decl1); - /* Optionally warn of any def with no previous declaration - if the function has already been used. */ - else if (warn_missing_declarations - && old_decl != NULL_TREE - && old_decl != error_mark_node - && TREE_USED (old_decl) - && C_DECL_IMPLICIT (old_decl)) - warning_at (loc, OPT_Wmissing_declarations, - "%qD was used with no declaration before its definition", decl1); - - /* This function exists in static storage. - (This does not mean `static' in the C sense!) */ - TREE_STATIC (decl1) = 1; - - /* This is the earliest point at which we might know the assembler - name of the function. Thus, if it's set before this, die horribly. */ - gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl1)); - - /* If #pragma weak was used, mark the decl weak now. */ - if (current_scope == file_scope) - maybe_apply_pragma_weak (decl1); - - /* Warn for unlikely, improbable, or stupid declarations of `main'. */ - if (warn_main && MAIN_NAME_P (DECL_NAME (decl1))) - { - if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1))) - != integer_type_node) - pedwarn (loc, OPT_Wmain, "return type of %qD is not %", decl1); - else if (TYPE_ATOMIC (TREE_TYPE (TREE_TYPE (decl1)))) - pedwarn (loc, OPT_Wmain, "%<_Atomic%>-qualified return type of %qD", - decl1); - - check_main_parameter_types (decl1); - - if (!TREE_PUBLIC (decl1)) - pedwarn (loc, OPT_Wmain, - "%qD is normally a non-static function", decl1); - } - - tree parms = current_function_arg_info->parms; - if (old_decl) - { - location_t origloc = DECL_SOURCE_LOCATION (old_decl); - warn_parm_array_mismatch (origloc, old_decl, parms); - } - - /* Record the decl so that the function name is defined. - If we already have a decl for this name, and it is a FUNCTION_DECL, - use the old decl. */ - - current_function_decl = pushdecl (decl1); - - if (tree access = build_attr_access_from_parms (parms, false)) - decl_attributes (¤t_function_decl, access, ATTR_FLAG_INTERNAL, - old_decl); - - push_scope (); - declare_parm_level (); - - restype = TREE_TYPE (TREE_TYPE (current_function_decl)); - resdecl = build_decl (loc, RESULT_DECL, NULL_TREE, restype); - DECL_ARTIFICIAL (resdecl) = 1; - DECL_IGNORED_P (resdecl) = 1; - DECL_RESULT (current_function_decl) = resdecl; - - start_fname_decls (); - - return true; -} - -/* Subroutine of store_parm_decls which handles new-style function - definitions (prototype format). The parms already have decls, so we - need only record them as in effect and complain if any redundant - old-style parm decls were written. */ -static void -store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info) -{ - tree decl; - c_arg_tag *tag; - unsigned ix; - - if (current_scope->bindings) - { - error_at (DECL_SOURCE_LOCATION (fndecl), - "old-style parameter declarations in prototyped " - "function definition"); - - /* Get rid of the old-style declarations. */ - pop_scope (); - push_scope (); - } - /* Don't issue this warning for nested functions, and don't issue this - warning if we got here because ARG_INFO_TYPES was error_mark_node - (this happens when a function definition has just an ellipsis in - its parameter list). */ - else if (!in_system_header_at (input_location) - && !current_function_scope - && arg_info->types != error_mark_node) - warning_at (DECL_SOURCE_LOCATION (fndecl), OPT_Wtraditional, - "traditional C rejects ISO C style function definitions"); - - /* Now make all the parameter declarations visible in the function body. - We can bypass most of the grunt work of pushdecl. */ - for (decl = arg_info->parms; decl; decl = DECL_CHAIN (decl)) - { - DECL_CONTEXT (decl) = current_function_decl; - if (DECL_NAME (decl)) - { - bind (DECL_NAME (decl), decl, current_scope, - /*invisible=*/false, /*nested=*/false, - UNKNOWN_LOCATION); - if (!TREE_USED (decl)) - warn_if_shadowing (decl); - } - else - pedwarn_c11 (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic, - "ISO C does not support omitting parameter names in " - "function definitions before C2X"); - } - - /* Record the parameter list in the function declaration. */ - DECL_ARGUMENTS (fndecl) = arg_info->parms; - - /* Now make all the ancillary declarations visible, likewise. */ - for (decl = arg_info->others; decl; decl = DECL_CHAIN (decl)) - { - DECL_CONTEXT (decl) = current_function_decl; - if (DECL_NAME (decl)) - bind (DECL_NAME (decl), decl, current_scope, - /*invisible=*/false, - /*nested=*/(TREE_CODE (decl) == FUNCTION_DECL), - UNKNOWN_LOCATION); - } - - /* And all the tag declarations. */ - FOR_EACH_VEC_SAFE_ELT_REVERSE (arg_info->tags, ix, tag) - if (tag->id) - bind (tag->id, tag->type, current_scope, - /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION); -} - -/* Subroutine of store_parm_decls which handles old-style function - definitions (separate parameter list and declarations). */ - -static void -store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) -{ - struct c_binding *b; - tree parm, decl, last; - tree parmids = arg_info->parms; - hash_set seen_args; - - if (!in_system_header_at (input_location)) - { - if (flag_isoc2x) - pedwarn (DECL_SOURCE_LOCATION (fndecl), - OPT_Wold_style_definition, "old-style function definition"); - else - warning_at (DECL_SOURCE_LOCATION (fndecl), - OPT_Wold_style_definition, - "old-style function definition"); - } - - if (current_scope->had_vla_unspec) - error ("%<[*]%> not allowed in other than function prototype scope"); - - /* Match each formal parameter name with its declaration. Save each - decl in the appropriate TREE_PURPOSE slot of the parmids chain. */ - for (parm = parmids; parm; parm = TREE_CHAIN (parm)) - { - if (TREE_VALUE (parm) == NULL_TREE) - { - error_at (DECL_SOURCE_LOCATION (fndecl), - "parameter name missing from parameter list"); - TREE_PURPOSE (parm) = NULL_TREE; - continue; - } - - b = I_SYMBOL_BINDING (TREE_VALUE (parm)); - if (b && B_IN_CURRENT_SCOPE (b)) - { - decl = b->decl; - /* Skip erroneous parameters. */ - if (decl == error_mark_node) - continue; - /* If we got something other than a PARM_DECL it is an error. */ - if (TREE_CODE (decl) != PARM_DECL) - { - error_at (DECL_SOURCE_LOCATION (decl), - "%qD declared as a non-parameter", decl); - continue; - } - /* If the declaration is already marked, we have a duplicate - name. Complain and ignore the duplicate. */ - else if (seen_args.contains (decl)) - { - error_at (DECL_SOURCE_LOCATION (decl), - "multiple parameters named %qD", decl); - TREE_PURPOSE (parm) = NULL_TREE; - continue; - } - /* If the declaration says "void", complain and turn it into - an int. */ - else if (VOID_TYPE_P (TREE_TYPE (decl))) - { - error_at (DECL_SOURCE_LOCATION (decl), - "parameter %qD declared with void type", decl); - TREE_TYPE (decl) = integer_type_node; - DECL_ARG_TYPE (decl) = integer_type_node; - layout_decl (decl, 0); - } - warn_if_shadowing (decl); - } - /* If no declaration found, default to int. */ - else - { - /* FIXME diagnostics: This should be the location of the argument, - not the FNDECL. E.g., for an old-style declaration - - int f10(v) { blah; } - - We should use the location of the V, not the F10. - Unfortunately, the V is an IDENTIFIER_NODE which has no - location. In the future we need locations for c_arg_info - entries. - - See gcc.dg/Wshadow-3.c for an example of this problem. */ - decl = build_decl (DECL_SOURCE_LOCATION (fndecl), - PARM_DECL, TREE_VALUE (parm), integer_type_node); - DECL_ARG_TYPE (decl) = TREE_TYPE (decl); - pushdecl (decl); - warn_if_shadowing (decl); - - if (flag_isoc99) - pedwarn (DECL_SOURCE_LOCATION (decl), - OPT_Wimplicit_int, "type of %qD defaults to %", - decl); - else - warning_at (DECL_SOURCE_LOCATION (decl), - OPT_Wmissing_parameter_type, - "type of %qD defaults to %", decl); - } - - TREE_PURPOSE (parm) = decl; - seen_args.add (decl); - } - - /* Now examine the parms chain for incomplete declarations - and declarations with no corresponding names. */ - - for (b = current_scope->bindings; b; b = b->prev) - { - parm = b->decl; - if (TREE_CODE (parm) != PARM_DECL) - continue; - - if (TREE_TYPE (parm) != error_mark_node - && !COMPLETE_TYPE_P (TREE_TYPE (parm))) - { - error_at (DECL_SOURCE_LOCATION (parm), - "parameter %qD has incomplete type", parm); - TREE_TYPE (parm) = error_mark_node; - } - - if (!seen_args.contains (parm)) - { - error_at (DECL_SOURCE_LOCATION (parm), - "declaration for parameter %qD but no such parameter", - parm); - - /* Pretend the parameter was not missing. - This gets us to a standard state and minimizes - further error messages. */ - parmids = chainon (parmids, tree_cons (parm, 0, 0)); - } - } - - /* Chain the declarations together in the order of the list of - names. Store that chain in the function decl, replacing the - list of names. Update the current scope to match. */ - DECL_ARGUMENTS (fndecl) = NULL_TREE; - - for (parm = parmids; parm; parm = TREE_CHAIN (parm)) - if (TREE_PURPOSE (parm)) - break; - if (parm && TREE_PURPOSE (parm)) - { - last = TREE_PURPOSE (parm); - DECL_ARGUMENTS (fndecl) = last; - - for (parm = TREE_CHAIN (parm); parm; parm = TREE_CHAIN (parm)) - if (TREE_PURPOSE (parm)) - { - DECL_CHAIN (last) = TREE_PURPOSE (parm); - last = TREE_PURPOSE (parm); - } - DECL_CHAIN (last) = NULL_TREE; - } - - /* If there was a previous prototype, - set the DECL_ARG_TYPE of each argument according to - the type previously specified, and report any mismatches. */ - - if (current_function_prototype_arg_types) - { - tree type; - for (parm = DECL_ARGUMENTS (fndecl), - type = current_function_prototype_arg_types; - parm || (type != NULL_TREE - && TREE_VALUE (type) != error_mark_node - && TYPE_MAIN_VARIANT (TREE_VALUE (type)) != void_type_node); - parm = DECL_CHAIN (parm), type = TREE_CHAIN (type)) - { - if (parm == NULL_TREE - || type == NULL_TREE - || (TREE_VALUE (type) != error_mark_node - && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)) - { - if (current_function_prototype_built_in) - warning_at (DECL_SOURCE_LOCATION (fndecl), - 0, "number of arguments doesn%'t match " - "built-in prototype"); - else - { - /* FIXME diagnostics: This should be the location of - FNDECL, but there is bug when a prototype is - declared inside function context, but defined - outside of it (e.g., gcc.dg/pr15698-2.c). In - which case FNDECL gets the location of the - prototype, not the definition. */ - error_at (input_location, - "number of arguments doesn%'t match prototype"); - - error_at (current_function_prototype_locus, - "prototype declaration"); - } - break; - } - /* Type for passing arg must be consistent with that - declared for the arg. ISO C says we take the unqualified - type for parameters declared with qualified type. */ - if (TREE_TYPE (parm) != error_mark_node - && TREE_VALUE (type) != error_mark_node - && ((TYPE_ATOMIC (DECL_ARG_TYPE (parm)) - != TYPE_ATOMIC (TREE_VALUE (type))) - || !comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)), - TYPE_MAIN_VARIANT (TREE_VALUE (type))))) - { - if ((TYPE_ATOMIC (DECL_ARG_TYPE (parm)) - == TYPE_ATOMIC (TREE_VALUE (type))) - && (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) - == TYPE_MAIN_VARIANT (TREE_VALUE (type)))) - { - /* Adjust argument to match prototype. E.g. a previous - `int foo(float);' prototype causes - `int foo(x) float x; {...}' to be treated like - `int foo(float x) {...}'. This is particularly - useful for argument types like uid_t. */ - DECL_ARG_TYPE (parm) = TREE_TYPE (parm); - - if (targetm.calls.promote_prototypes (TREE_TYPE (current_function_decl)) - && INTEGRAL_TYPE_P (TREE_TYPE (parm)) - && (TYPE_PRECISION (TREE_TYPE (parm)) - < TYPE_PRECISION (integer_type_node))) - DECL_ARG_TYPE (parm) - = c_type_promotes_to (TREE_TYPE (parm)); - - /* ??? Is it possible to get here with a - built-in prototype or will it always have - been diagnosed as conflicting with an - old-style definition and discarded? */ - if (current_function_prototype_built_in) - warning_at (DECL_SOURCE_LOCATION (parm), - OPT_Wpedantic, "promoted argument %qD " - "doesn%'t match built-in prototype", parm); - else - { - pedwarn (DECL_SOURCE_LOCATION (parm), - OPT_Wpedantic, "promoted argument %qD " - "doesn%'t match prototype", parm); - pedwarn (current_function_prototype_locus, OPT_Wpedantic, - "prototype declaration"); - } - } - else - { - if (current_function_prototype_built_in) - warning_at (DECL_SOURCE_LOCATION (parm), - 0, "argument %qD doesn%'t match " - "built-in prototype", parm); - else - { - error_at (DECL_SOURCE_LOCATION (parm), - "argument %qD doesn%'t match prototype", parm); - error_at (current_function_prototype_locus, - "prototype declaration"); - } - } - } - } - TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = NULL_TREE; - } - - /* Otherwise, create a prototype that would match. */ - - else - { - tree actual = NULL_TREE, last = NULL_TREE, type; - - for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm)) - { - type = tree_cons (NULL_TREE, DECL_ARG_TYPE (parm), NULL_TREE); - if (last) - TREE_CHAIN (last) = type; - else - actual = type; - last = type; - } - type = tree_cons (NULL_TREE, void_type_node, NULL_TREE); - if (last) - TREE_CHAIN (last) = type; - else - actual = type; - - /* We are going to assign a new value for the TYPE_ACTUAL_ARG_TYPES - of the type of this function, but we need to avoid having this - affect the types of other similarly-typed functions, so we must - first force the generation of an identical (but separate) type - node for the relevant function type. The new node we create - will be a variant of the main variant of the original function - type. */ - - TREE_TYPE (fndecl) = build_variant_type_copy (TREE_TYPE (fndecl)); - - TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = actual; - } -} - -/* Store parameter declarations passed in ARG_INFO into the current - function declaration. */ - -void -store_parm_decls_from (struct c_arg_info *arg_info) -{ - current_function_arg_info = arg_info; - store_parm_decls (); -} - -/* Called by walk_tree to look for and update context-less labels - or labels with context in the parent function. */ - -static tree -set_labels_context_r (tree *tp, int *walk_subtrees, void *data) -{ - tree ctx = static_cast(data); - if (TREE_CODE (*tp) == LABEL_EXPR - && (DECL_CONTEXT (LABEL_EXPR_LABEL (*tp)) == NULL_TREE - || DECL_CONTEXT (LABEL_EXPR_LABEL (*tp)) == DECL_CONTEXT (ctx))) - { - DECL_CONTEXT (LABEL_EXPR_LABEL (*tp)) = ctx; - *walk_subtrees = 0; - } - - return NULL_TREE; -} - -/* Store the parameter declarations into the current function declaration. - This is called after parsing the parameter declarations, before - digesting the body of the function. - - For an old-style definition, construct a prototype out of the old-style - parameter declarations and inject it into the function's type. */ - -void -store_parm_decls (void) -{ - tree fndecl = current_function_decl; - bool proto; - - /* The argument information block for FNDECL. */ - struct c_arg_info *arg_info = current_function_arg_info; - current_function_arg_info = 0; - - /* True if this definition is written with a prototype. In C2X, an - empty argument list was converted to (void) in grokparms; in - older C standard versions, it does not give the function a type - with a prototype for future calls. */ - proto = arg_info->types != 0; - - if (proto) - store_parm_decls_newstyle (fndecl, arg_info); - else - store_parm_decls_oldstyle (fndecl, arg_info); - - /* The next call to push_scope will be a function body. */ - - next_is_function_body = true; - - /* Write a record describing this function definition to the prototypes - file (if requested). */ - - gen_aux_info_record (fndecl, 1, 0, proto); - - /* Initialize the RTL code for the function. */ - allocate_struct_function (fndecl, false); - - if (warn_unused_local_typedefs) - cfun->language = ggc_cleared_alloc (); - - /* Begin the statement tree for this function. */ - DECL_SAVED_TREE (fndecl) = push_stmt_list (); - - /* ??? Insert the contents of the pending sizes list into the function - to be evaluated. The only reason left to have this is - void foo(int n, int array[n++]) - because we throw away the array type in favor of a pointer type, and - thus won't naturally see the SAVE_EXPR containing the increment. All - other pending sizes would be handled by gimplify_parameters. */ - if (arg_info->pending_sizes) - { - /* In very special circumstances, e.g. for code like - _Atomic int i = 5; - void f (int a[i += 2]) {} - we need to execute the atomic assignment on function entry. - But in this case, it is not just a straight store, it has the - op= form, which means that build_atomic_assign has generated - gotos, labels, etc. Because at that time the function decl - for F has not been created yet, those labels do not have any - function context. But we have the fndecl now, so update the - labels accordingly. gimplify_expr would crash otherwise. - Or with nested functions the labels could be created with parent - function's context, while when the statement is emitted at the - start of the nested function, it needs the nested function's - context. */ - walk_tree_without_duplicates (&arg_info->pending_sizes, - set_labels_context_r, fndecl); - add_stmt (arg_info->pending_sizes); - } -} - -/* Store PARM_DECLs in PARMS into scope temporarily. Used for - c_finish_omp_declare_simd for function prototypes. No diagnostics - should be done. */ - -void -temp_store_parm_decls (tree fndecl, tree parms) -{ - push_scope (); - for (tree p = parms; p; p = DECL_CHAIN (p)) - { - DECL_CONTEXT (p) = fndecl; - if (DECL_NAME (p)) - bind (DECL_NAME (p), p, current_scope, - /*invisible=*/false, /*nested=*/false, - UNKNOWN_LOCATION); - } -} - -/* Undo what temp_store_parm_decls did. */ - -void -temp_pop_parm_decls (void) -{ - /* Clear all bindings in this temporary scope, so that - pop_scope doesn't create a BLOCK. */ - struct c_binding *b = current_scope->bindings; - current_scope->bindings = NULL; - for (; b; b = free_binding_and_advance (b)) - { - gcc_assert (TREE_CODE (b->decl) == PARM_DECL - || b->decl == error_mark_node); - gcc_assert (I_SYMBOL_BINDING (b->id) == b); - I_SYMBOL_BINDING (b->id) = b->shadowed; - if (b->shadowed && b->shadowed->u.type) - TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type; - } - pop_scope (); -} - - -/* Finish up a function declaration and compile that function - all the way to assembler language output. Then free the storage - for the function definition. - - This is called after parsing the body of the function definition. */ - -void -finish_function (location_t end_loc) -{ - tree fndecl = current_function_decl; - - if (c_dialect_objc ()) - objc_finish_function (); - - if (TREE_CODE (fndecl) == FUNCTION_DECL - && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))) - { - tree args = DECL_ARGUMENTS (fndecl); - for (; args; args = DECL_CHAIN (args)) - { - tree type = TREE_TYPE (args); - if (INTEGRAL_TYPE_P (type) - && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) - DECL_ARG_TYPE (args) = c_type_promotes_to (type); - } - } - - if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node) - BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; - - /* Must mark the RESULT_DECL as being in this function. */ - - if (DECL_RESULT (fndecl) && DECL_RESULT (fndecl) != error_mark_node) - DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; - - if (MAIN_NAME_P (DECL_NAME (fndecl)) && flag_hosted - && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) - == integer_type_node && flag_isoc99) - { - /* Hack. We don't want the middle-end to warn that this return - is unreachable, so we mark its location as special. Using - UNKNOWN_LOCATION has the problem that it gets clobbered in - annotate_one_with_locus. A cleaner solution might be to - ensure ! should_carry_locus_p (stmt), but that needs a flag. - */ - c_finish_return (BUILTINS_LOCATION, integer_zero_node, NULL_TREE); - } - - /* Tie off the statement tree for this function. */ - DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl)); - - finish_fname_decls (); - - /* Complain if there's no return statement only if option specified on - command line. */ - if (warn_return_type > 0 - && TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE - && !current_function_returns_value && !current_function_returns_null - /* Don't complain if we are no-return. */ - && !current_function_returns_abnormally - /* Don't complain if we are declared noreturn. */ - && !TREE_THIS_VOLATILE (fndecl) - /* Don't warn for main(). */ - && !MAIN_NAME_P (DECL_NAME (fndecl)) - /* Or if they didn't actually specify a return type. */ - && !C_FUNCTION_IMPLICIT_INT (fndecl) - /* Normally, with -Wreturn-type, flow will complain, but we might - optimize out static functions. */ - && !TREE_PUBLIC (fndecl) - && targetm.warn_func_return (fndecl) - && warning (OPT_Wreturn_type, - "no return statement in function returning non-void")) - suppress_warning (fndecl, OPT_Wreturn_type); - - /* Complain about parameters that are only set, but never otherwise used. */ - if (warn_unused_but_set_parameter) - { - tree decl; - - for (decl = DECL_ARGUMENTS (fndecl); - decl; - decl = DECL_CHAIN (decl)) - if (TREE_USED (decl) - && TREE_CODE (decl) == PARM_DECL - && !DECL_READ_P (decl) - && DECL_NAME (decl) - && !DECL_ARTIFICIAL (decl) - && !warning_suppressed_p (decl, OPT_Wunused_but_set_parameter)) - warning_at (DECL_SOURCE_LOCATION (decl), - OPT_Wunused_but_set_parameter, - "parameter %qD set but not used", decl); - } - - /* Complain about locally defined typedefs that are not used in this - function. */ - maybe_warn_unused_local_typedefs (); - - /* Possibly warn about unused parameters. */ - if (warn_unused_parameter) - do_warn_unused_parameter (fndecl); - - /* Store the end of the function, so that we get good line number - info for the epilogue. */ - cfun->function_end_locus = end_loc; - - /* Finalize the ELF visibility for the function. */ - c_determine_visibility (fndecl); - - /* For GNU C extern inline functions disregard inline limits. */ - if (DECL_EXTERNAL (fndecl) - && DECL_DECLARED_INLINE_P (fndecl) - && (flag_gnu89_inline - || lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (fndecl)))) - DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1; - - /* Genericize before inlining. Delay genericizing nested functions - until their parent function is genericized. Since finalizing - requires GENERIC, delay that as well. */ - - if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node - && !undef_nested_function) - { - if (!decl_function_context (fndecl)) - { - invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl); - c_genericize (fndecl); - - /* ??? Objc emits functions after finalizing the compilation unit. - This should be cleaned up later and this conditional removed. */ - if (symtab->global_info_ready) - { - cgraph_node::add_new_function (fndecl, false); - return; - } - cgraph_node::finalize_function (fndecl, false); - } - else - { - /* Register this function with cgraph just far enough to get it - added to our parent's nested function list. Handy, since the - C front end doesn't have such a list. */ - (void) cgraph_node::get_create (fndecl); - } - } - - if (!decl_function_context (fndecl)) - undef_nested_function = false; - - if (cfun->language != NULL) - { - ggc_free (cfun->language); - cfun->language = NULL; - } - - /* We're leaving the context of this function, so zap cfun. - It's still in DECL_STRUCT_FUNCTION, and we'll restore it in - tree_rest_of_compilation. */ - set_cfun (NULL); - invoke_plugin_callbacks (PLUGIN_FINISH_PARSE_FUNCTION, current_function_decl); - current_function_decl = NULL; -} - -/* Check the declarations given in a for-loop for satisfying the C99 - constraints. If exactly one such decl is found, return it. LOC is - the location of the opening parenthesis of the for loop. The last - parameter allows you to control the "for loop initial declarations - are only allowed in C99 mode". Normally, you should pass - flag_isoc99 as that parameter. But in some cases (Objective-C - foreach loop, for example) we want to run the checks in this - function even if not in C99 mode, so we allow the caller to turn - off the error about not being in C99 mode. -*/ - -tree -check_for_loop_decls (location_t loc, bool turn_off_iso_c99_error) -{ - struct c_binding *b; - tree one_decl = NULL_TREE; - int n_decls = 0; - - if (!turn_off_iso_c99_error) - { - static bool hint = true; - /* If we get here, declarations have been used in a for loop without - the C99 for loop scope. This doesn't make much sense, so don't - allow it. */ - error_at (loc, "% loop initial declarations " - "are only allowed in C99 or C11 mode"); - if (hint) - { - inform (loc, - "use option %<-std=c99%>, %<-std=gnu99%>, %<-std=c11%> or " - "%<-std=gnu11%> to compile your code"); - hint = false; - } - return NULL_TREE; - } - else - pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not support % loop " - "initial declarations"); - - /* C99 subclause 6.8.5 paragraph 3: - - [#3] The declaration part of a for statement shall only - declare identifiers for objects having storage class auto or - register. - - It isn't clear whether, in this sentence, "identifiers" binds to - "shall only declare" or to "objects" - that is, whether all identifiers - declared must be identifiers for objects, or whether the restriction - only applies to those that are. (A question on this in comp.std.c - in November 2000 received no answer.) We implement the strictest - interpretation, to avoid creating an extension which later causes - problems. */ - - for (b = current_scope->bindings; b; b = b->prev) - { - tree id = b->id; - tree decl = b->decl; - - if (!id) - continue; - - switch (TREE_CODE (decl)) - { - case VAR_DECL: - { - location_t decl_loc = DECL_SOURCE_LOCATION (decl); - if (TREE_STATIC (decl)) - error_at (decl_loc, - "declaration of static variable %qD in % loop " - "initial declaration", decl); - else if (DECL_EXTERNAL (decl)) - error_at (decl_loc, - "declaration of % variable %qD in % loop " - "initial declaration", decl); - } - break; - - case RECORD_TYPE: - error_at (loc, - "% declared in % loop initial " - "declaration", id); - break; - case UNION_TYPE: - error_at (loc, - "% declared in % loop initial declaration", - id); - break; - case ENUMERAL_TYPE: - error_at (loc, "% declared in % loop " - "initial declaration", id); - break; - default: - error_at (loc, "declaration of non-variable " - "%qD in % loop initial declaration", decl); - } - - n_decls++; - one_decl = decl; - } - - return n_decls == 1 ? one_decl : NULL_TREE; -} - -/* Save and reinitialize the variables - used during compilation of a C function. */ - -void -c_push_function_context (void) -{ - struct language_function *p = cfun->language; - /* cfun->language might have been already allocated by the use of - -Wunused-local-typedefs. In that case, just re-use it. */ - if (p == NULL) - cfun->language = p = ggc_cleared_alloc (); - - p->base.x_stmt_tree = c_stmt_tree; - c_stmt_tree.x_cur_stmt_list = vec_safe_copy (c_stmt_tree.x_cur_stmt_list); - p->x_in_statement = in_statement; - p->x_switch_stack = c_switch_stack; - p->arg_info = current_function_arg_info; - p->returns_value = current_function_returns_value; - p->returns_null = current_function_returns_null; - p->returns_abnormally = current_function_returns_abnormally; - p->warn_about_return_type = warn_about_return_type; - - push_function_context (); -} - -/* Restore the variables used during compilation of a C function. */ - -void -c_pop_function_context (void) -{ - struct language_function *p; - - pop_function_context (); - p = cfun->language; - - /* When -Wunused-local-typedefs is in effect, cfun->languages is - used to store data throughout the life time of the current cfun, - So don't deallocate it. */ - if (!warn_unused_local_typedefs) - cfun->language = NULL; - - if (DECL_STRUCT_FUNCTION (current_function_decl) == 0 - && DECL_SAVED_TREE (current_function_decl) == NULL_TREE) - { - /* Stop pointing to the local nodes about to be freed. */ - /* But DECL_INITIAL must remain nonzero so we know this - was an actual function definition. */ - DECL_INITIAL (current_function_decl) = error_mark_node; - DECL_ARGUMENTS (current_function_decl) = NULL_TREE; - } - - c_stmt_tree = p->base.x_stmt_tree; - p->base.x_stmt_tree.x_cur_stmt_list = NULL; - in_statement = p->x_in_statement; - c_switch_stack = p->x_switch_stack; - current_function_arg_info = p->arg_info; - current_function_returns_value = p->returns_value; - current_function_returns_null = p->returns_null; - current_function_returns_abnormally = p->returns_abnormally; - warn_about_return_type = p->warn_about_return_type; -} - -/* The functions below are required for functionality of doing - function at once processing in the C front end. Currently these - functions are not called from anywhere in the C front end, but as - these changes continue, that will change. */ - -/* Returns the stmt_tree (if any) to which statements are currently - being added. If there is no active statement-tree, NULL is - returned. */ - -stmt_tree -current_stmt_tree (void) -{ - return &c_stmt_tree; -} - -/* Return the global value of T as a symbol. */ - -tree -identifier_global_value (tree t) -{ - struct c_binding *b; - - for (b = I_SYMBOL_BINDING (t); b; b = b->shadowed) - if (B_IN_FILE_SCOPE (b) || B_IN_EXTERNAL_SCOPE (b)) - return b->decl; - - return NULL_TREE; -} - -/* Return the global value of tag T as a symbol. */ - -tree -identifier_global_tag (tree t) -{ - struct c_binding *b; - - for (b = I_TAG_BINDING (t); b; b = b->shadowed) - if (B_IN_FILE_SCOPE (b) || B_IN_EXTERNAL_SCOPE (b)) - return b->decl; - - return NULL_TREE; -} - -/* Returns true if NAME refers to a built-in function or function-like - operator. */ - -bool -names_builtin_p (const char *name) -{ - tree id = get_identifier (name); - if (tree decl = identifier_global_value (id)) - return TREE_CODE (decl) == FUNCTION_DECL && DECL_IS_UNDECLARED_BUILTIN (decl); - - /* Also detect common reserved C words that aren't strictly built-in - functions. */ - switch (C_RID_CODE (id)) - { - case RID_BUILTIN_CONVERTVECTOR: - case RID_BUILTIN_HAS_ATTRIBUTE: - case RID_BUILTIN_SHUFFLE: - case RID_BUILTIN_SHUFFLEVECTOR: - case RID_BUILTIN_ASSOC_BARRIER: - case RID_CHOOSE_EXPR: - case RID_OFFSETOF: - case RID_TYPES_COMPATIBLE_P: - return true; - default: - break; - } - - return false; -} - -/* In C, the only C-linkage public declaration is at file scope. */ - -tree -c_linkage_bindings (tree name) -{ - return identifier_global_value (name); -} - -/* Record a builtin type for C. If NAME is non-NULL, it is the name used; - otherwise the name is found in ridpointers from RID_INDEX. */ - -void -record_builtin_type (enum rid rid_index, const char *name, tree type) -{ - tree id, decl; - if (name == 0) - id = ridpointers[(int) rid_index]; - else - id = get_identifier (name); - decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL, id, type); - pushdecl (decl); - if (debug_hooks->type_decl) - debug_hooks->type_decl (decl, false); -} - -/* Build the void_list_node (void_type_node having been created). */ -tree -build_void_list_node (void) -{ - tree t = build_tree_list (NULL_TREE, void_type_node); - return t; -} - -/* Return a c_parm structure with the given SPECS, ATTRS and DECLARATOR. */ - -struct c_parm * -build_c_parm (struct c_declspecs *specs, tree attrs, - struct c_declarator *declarator, - location_t loc) -{ - struct c_parm *ret = XOBNEW (&parser_obstack, struct c_parm); - ret->specs = specs; - ret->attrs = attrs; - ret->declarator = declarator; - ret->loc = loc; - return ret; -} - -/* Return a declarator with nested attributes. TARGET is the inner - declarator to which these attributes apply. ATTRS are the - attributes. */ - -struct c_declarator * -build_attrs_declarator (tree attrs, struct c_declarator *target) -{ - struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); - ret->kind = cdk_attrs; - ret->declarator = target; - ret->u.attrs = attrs; - return ret; -} - -/* Return a declarator for a function with arguments specified by ARGS - and return type specified by TARGET. */ - -struct c_declarator * -build_function_declarator (struct c_arg_info *args, - struct c_declarator *target) -{ - struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); - ret->kind = cdk_function; - ret->declarator = target; - ret->u.arg_info = args; - return ret; -} - -/* Return a declarator for the identifier IDENT (which may be - NULL_TREE for an abstract declarator). */ - -struct c_declarator * -build_id_declarator (tree ident) -{ - struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); - ret->kind = cdk_id; - ret->declarator = 0; - ret->u.id.id = ident; - ret->u.id.attrs = NULL_TREE; - /* Default value - may get reset to a more precise location. */ - ret->id_loc = input_location; - return ret; -} - -/* Return something to represent absolute declarators containing a *. - TARGET is the absolute declarator that the * contains. - TYPE_QUALS_ATTRS is a structure for type qualifiers and attributes - to apply to the pointer type. */ - -struct c_declarator * -make_pointer_declarator (struct c_declspecs *type_quals_attrs, - struct c_declarator *target) -{ - tree attrs; - int quals = 0; - struct c_declarator *itarget = target; - struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); - if (type_quals_attrs) - { - attrs = type_quals_attrs->attrs; - quals = quals_from_declspecs (type_quals_attrs); - if (attrs != NULL_TREE) - itarget = build_attrs_declarator (attrs, target); - } - ret->kind = cdk_pointer; - ret->declarator = itarget; - ret->u.pointer_quals = quals; - return ret; -} - -/* Return a pointer to a structure for an empty list of declaration - specifiers. */ - -struct c_declspecs * -build_null_declspecs (void) -{ - struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs); - memset (ret, 0, sizeof *ret); - ret->align_log = -1; - ret->typespec_word = cts_none; - ret->storage_class = csc_none; - ret->expr_const_operands = true; - ret->typespec_kind = ctsk_none; - ret->address_space = ADDR_SPACE_GENERIC; - return ret; -} - -/* Add the address space ADDRSPACE to the declaration specifiers - SPECS, returning SPECS. */ - -struct c_declspecs * -declspecs_add_addrspace (location_t location, - struct c_declspecs *specs, addr_space_t as) -{ - specs->non_sc_seen_p = true; - specs->declspecs_seen_p = true; - specs->non_std_attrs_seen_p = true; - - if (!ADDR_SPACE_GENERIC_P (specs->address_space) - && specs->address_space != as) - error ("incompatible address space qualifiers %qs and %qs", - c_addr_space_name (as), - c_addr_space_name (specs->address_space)); - else - { - specs->address_space = as; - specs->locations[cdw_address_space] = location; - } - return specs; -} - -/* Add the type qualifier QUAL to the declaration specifiers SPECS, - returning SPECS. */ - -struct c_declspecs * -declspecs_add_qual (location_t loc, - struct c_declspecs *specs, tree qual) -{ - enum rid i; - bool dupe = false; - specs->non_sc_seen_p = true; - specs->declspecs_seen_p = true; - specs->non_std_attrs_seen_p = true; - gcc_assert (TREE_CODE (qual) == IDENTIFIER_NODE - && C_IS_RESERVED_WORD (qual)); - i = C_RID_CODE (qual); - location_t prev_loc = UNKNOWN_LOCATION; - switch (i) - { - case RID_CONST: - dupe = specs->const_p; - specs->const_p = true; - prev_loc = specs->locations[cdw_const]; - specs->locations[cdw_const] = loc; - break; - case RID_VOLATILE: - dupe = specs->volatile_p; - specs->volatile_p = true; - prev_loc = specs->locations[cdw_volatile]; - specs->locations[cdw_volatile] = loc; - break; - case RID_RESTRICT: - dupe = specs->restrict_p; - specs->restrict_p = true; - prev_loc = specs->locations[cdw_restrict]; - specs->locations[cdw_restrict] = loc; - break; - case RID_ATOMIC: - dupe = specs->atomic_p; - specs->atomic_p = true; - prev_loc = specs->locations[cdw_atomic]; - specs->locations[cdw_atomic] = loc; - break; - default: - gcc_unreachable (); - } - if (dupe) - { - bool warned = pedwarn_c90 (loc, OPT_Wpedantic, - "duplicate %qE declaration specifier", qual); - if (!warned - && warn_duplicate_decl_specifier - && prev_loc >= RESERVED_LOCATION_COUNT - && !from_macro_expansion_at (prev_loc) - && !from_macro_expansion_at (loc)) - warning_at (loc, OPT_Wduplicate_decl_specifier, - "duplicate %qE declaration specifier", qual); - } - return specs; -} - -/* Add the type specifier TYPE to the declaration specifiers SPECS, - returning SPECS. */ - -struct c_declspecs * -declspecs_add_type (location_t loc, struct c_declspecs *specs, - struct c_typespec spec) -{ - tree type = spec.spec; - specs->non_sc_seen_p = true; - specs->declspecs_seen_p = true; - specs->non_std_attrs_seen_p = true; - specs->typespec_kind = spec.kind; - if (TREE_DEPRECATED (type)) - specs->deprecated_p = true; - if (TREE_UNAVAILABLE (type)) - specs->unavailable_p = true; - - /* Handle type specifier keywords. */ - if (TREE_CODE (type) == IDENTIFIER_NODE - && C_IS_RESERVED_WORD (type) - && C_RID_CODE (type) != RID_CXX_COMPAT_WARN) - { - enum rid i = C_RID_CODE (type); - if (specs->type) - { - error_at (loc, "two or more data types in declaration specifiers"); - return specs; - } - if ((int) i <= (int) RID_LAST_MODIFIER) - { - /* "long", "short", "signed", "unsigned", "_Complex" or "_Sat". */ - bool dupe = false; - switch (i) - { - case RID_LONG: - if (specs->long_long_p) - { - error_at (loc, "% is too long for GCC"); - break; - } - if (specs->long_p) - { - if (specs->typespec_word == cts_double) - { - error_at (loc, - ("both % and % in " - "declaration specifiers")); - break; - } - pedwarn_c90 (loc, OPT_Wlong_long, - "ISO C90 does not support %"); - specs->long_long_p = 1; - specs->locations[cdw_long_long] = loc; - break; - } - if (specs->short_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_auto_type) - error_at (loc, - ("both % and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_void) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_int_n) - error_at (loc, - ("both % and %<__int%d%> in " - "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); - else if (specs->typespec_word == cts_bool) - error_at (loc, - ("both % and %<_Bool%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_char) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_float) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_floatn_nx) - error_at (loc, - ("both % and %<_Float%d%s%> in " - "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - else if (specs->typespec_word == cts_dfloat32) - error_at (loc, - ("both % and %<_Decimal32%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat64) - error_at (loc, - ("both % and %<_Decimal64%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat128) - error_at (loc, - ("both % and %<_Decimal128%> in " - "declaration specifiers")); - else - { - specs->long_p = true; - specs->locations[cdw_long] = loc; - } - break; - case RID_SHORT: - dupe = specs->short_p; - if (specs->long_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_auto_type) - error_at (loc, - ("both % and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_void) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_int_n) - error_at (loc, - ("both % and %<__int%d%> in " - "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); - else if (specs->typespec_word == cts_bool) - error_at (loc, - ("both % and %<_Bool%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_char) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_float) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_double) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_floatn_nx) - error_at (loc, - ("both % and %<_Float%d%s%> in " - "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - else if (specs->typespec_word == cts_dfloat32) - error_at (loc, - ("both % and %<_Decimal32%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat64) - error_at (loc, - ("both % and %<_Decimal64%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat128) - error_at (loc, - ("both % and %<_Decimal128%> in " - "declaration specifiers")); - else - { - specs->short_p = true; - specs->locations[cdw_short] = loc; - } - break; - case RID_SIGNED: - dupe = specs->signed_p; - if (specs->unsigned_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_auto_type) - error_at (loc, - ("both % and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_void) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_bool) - error_at (loc, - ("both % and %<_Bool%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_float) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_double) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_floatn_nx) - error_at (loc, - ("both % and %<_Float%d%s%> in " - "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - else if (specs->typespec_word == cts_dfloat32) - error_at (loc, - ("both % and %<_Decimal32%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat64) - error_at (loc, - ("both % and %<_Decimal64%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat128) - error_at (loc, - ("both % and %<_Decimal128%> in " - "declaration specifiers")); - else - { - specs->signed_p = true; - specs->locations[cdw_signed] = loc; - } - break; - case RID_UNSIGNED: - dupe = specs->unsigned_p; - if (specs->signed_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_auto_type) - error_at (loc, - ("both % and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_void) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_bool) - error_at (loc, - ("both % and %<_Bool%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_float) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_double) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_floatn_nx) - error_at (loc, - ("both % and %<_Float%d%s%> in " - "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - else if (specs->typespec_word == cts_dfloat32) - error_at (loc, - ("both % and %<_Decimal32%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat64) - error_at (loc, - ("both % and %<_Decimal64%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat128) - error_at (loc, - ("both % and %<_Decimal128%> in " - "declaration specifiers")); - else - { - specs->unsigned_p = true; - specs->locations[cdw_unsigned] = loc; - } - break; - case RID_COMPLEX: - dupe = specs->complex_p; - if (!in_system_header_at (loc)) - pedwarn_c90 (loc, OPT_Wpedantic, - "ISO C90 does not support complex types"); - if (specs->typespec_word == cts_auto_type) - error_at (loc, - ("both % and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_void) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_bool) - error_at (loc, - ("both % and %<_Bool%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat32) - error_at (loc, - ("both % and %<_Decimal32%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat64) - error_at (loc, - ("both % and %<_Decimal64%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat128) - error_at (loc, - ("both % and %<_Decimal128%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_fract) - error_at (loc, - ("both % and %<_Fract%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_accum) - error_at (loc, - ("both % and %<_Accum%> in " - "declaration specifiers")); - else if (specs->saturating_p) - error_at (loc, - ("both % and %<_Sat%> in " - "declaration specifiers")); - else - { - specs->complex_p = true; - specs->locations[cdw_complex] = loc; - } - break; - case RID_SAT: - dupe = specs->saturating_p; - pedwarn (loc, OPT_Wpedantic, - "ISO C does not support saturating types"); - if (specs->typespec_word == cts_int_n) - { - error_at (loc, - ("both %<_Sat%> and %<__int%d%> in " - "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); - } - else if (specs->typespec_word == cts_auto_type) - error_at (loc, - ("both %<_Sat%> and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_void) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_bool) - error_at (loc, - ("both %<_Sat%> and %<_Bool%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_char) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_int) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_float) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_double) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else if (specs->typespec_word == cts_floatn_nx) - error_at (loc, - ("both %<_Sat%> and %<_Float%d%s%> in " - "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - else if (specs->typespec_word == cts_dfloat32) - error_at (loc, - ("both %<_Sat%> and %<_Decimal32%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat64) - error_at (loc, - ("both %<_Sat%> and %<_Decimal64%> in " - "declaration specifiers")); - else if (specs->typespec_word == cts_dfloat128) - error_at (loc, - ("both %<_Sat%> and %<_Decimal128%> in " - "declaration specifiers")); - else if (specs->complex_p) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else - { - specs->saturating_p = true; - specs->locations[cdw_saturating] = loc; - } - break; - default: - gcc_unreachable (); - } - - if (dupe) - error_at (loc, "duplicate %qE", type); - - return specs; - } - else - { - /* "void", "_Bool", "char", "int", "float", "double", - "_FloatN", "_FloatNx", "_Decimal32", "__intN", - "_Decimal64", "_Decimal128", "_Fract", "_Accum" or - "__auto_type". */ - if (specs->typespec_word != cts_none) - { - error_at (loc, - "two or more data types in declaration specifiers"); - return specs; - } - switch (i) - { - case RID_AUTO_TYPE: - if (specs->long_p) - error_at (loc, - ("both % and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->short_p) - error_at (loc, - ("both % and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->signed_p) - error_at (loc, - ("both % and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->unsigned_p) - error_at (loc, - ("both % and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->complex_p) - error_at (loc, - ("both % and %<__auto_type%> in " - "declaration specifiers")); - else if (specs->saturating_p) - error_at (loc, - ("both %<_Sat%> and %<__auto_type%> in " - "declaration specifiers")); - else - { - specs->typespec_word = cts_auto_type; - specs->locations[cdw_typespec] = loc; - } - return specs; - case RID_INT_N_0: - case RID_INT_N_1: - case RID_INT_N_2: - case RID_INT_N_3: - specs->int_n_idx = i - RID_INT_N_0; - if (!in_system_header_at (input_location) - /* If the INT_N type ends in "__", and so is of the format - "__intN__", don't pedwarn. */ - && (strncmp (IDENTIFIER_POINTER (type) - + (IDENTIFIER_LENGTH (type) - 2), "__", 2) != 0)) - pedwarn (loc, OPT_Wpedantic, - "ISO C does not support %<__int%d%> types", - int_n_data[specs->int_n_idx].bitsize); - - if (specs->long_p) - error_at (loc, - ("both %<__int%d%> and % in " - "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); - else if (specs->saturating_p) - error_at (loc, - ("both %<_Sat%> and %<__int%d%> in " - "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); - else if (specs->short_p) - error_at (loc, - ("both %<__int%d%> and % in " - "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); - else if (! int_n_enabled_p[specs->int_n_idx]) - { - specs->typespec_word = cts_int_n; - error_at (loc, - "%<__int%d%> is not supported on this target", - int_n_data[specs->int_n_idx].bitsize); - } - else - { - specs->typespec_word = cts_int_n; - specs->locations[cdw_typespec] = loc; - } - return specs; - case RID_VOID: - if (specs->long_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->short_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->signed_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->unsigned_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->complex_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->saturating_p) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else - { - specs->typespec_word = cts_void; - specs->locations[cdw_typespec] = loc; - } - return specs; - case RID_BOOL: - if (!in_system_header_at (loc)) - pedwarn_c90 (loc, OPT_Wpedantic, - "ISO C90 does not support boolean types"); - if (specs->long_p) - error_at (loc, - ("both % and %<_Bool%> in " - "declaration specifiers")); - else if (specs->short_p) - error_at (loc, - ("both % and %<_Bool%> in " - "declaration specifiers")); - else if (specs->signed_p) - error_at (loc, - ("both % and %<_Bool%> in " - "declaration specifiers")); - else if (specs->unsigned_p) - error_at (loc, - ("both % and %<_Bool%> in " - "declaration specifiers")); - else if (specs->complex_p) - error_at (loc, - ("both % and %<_Bool%> in " - "declaration specifiers")); - else if (specs->saturating_p) - error_at (loc, - ("both %<_Sat%> and %<_Bool%> in " - "declaration specifiers")); - else - { - specs->typespec_word = cts_bool; - specs->locations[cdw_typespec] = loc; - } - return specs; - case RID_CHAR: - if (specs->long_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->short_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->saturating_p) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else - { - specs->typespec_word = cts_char; - specs->locations[cdw_typespec] = loc; - } - return specs; - case RID_INT: - if (specs->saturating_p) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else - { - specs->typespec_word = cts_int; - specs->locations[cdw_typespec] = loc; - } - return specs; - case RID_FLOAT: - if (specs->long_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->short_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->signed_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->unsigned_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->saturating_p) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else - { - specs->typespec_word = cts_float; - specs->locations[cdw_typespec] = loc; - } - return specs; - case RID_DOUBLE: - if (specs->long_long_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->short_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->signed_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->unsigned_p) - error_at (loc, - ("both % and % in " - "declaration specifiers")); - else if (specs->saturating_p) - error_at (loc, - ("both %<_Sat%> and % in " - "declaration specifiers")); - else - { - specs->typespec_word = cts_double; - specs->locations[cdw_typespec] = loc; - } - return specs; - CASE_RID_FLOATN_NX: - specs->floatn_nx_idx = i - RID_FLOATN_NX_FIRST; - if (!in_system_header_at (input_location)) - pedwarn (loc, OPT_Wpedantic, - "ISO C does not support the %<_Float%d%s%> type", - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - - if (specs->long_p) - error_at (loc, - ("both % and %<_Float%d%s%> in " - "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - else if (specs->short_p) - error_at (loc, - ("both % and %<_Float%d%s%> in " - "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - else if (specs->signed_p) - error_at (loc, - ("both % and %<_Float%d%s%> in " - "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - else if (specs->unsigned_p) - error_at (loc, - ("both % and %<_Float%d%s%> in " - "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - else if (specs->saturating_p) - error_at (loc, - ("both %<_Sat%> and %<_Float%d%s%> in " - "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - else if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE) - { - specs->typespec_word = cts_floatn_nx; - error_at (loc, - "%<_Float%d%s%> is not supported on this target", - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended - ? "x" - : "")); - } - else - { - specs->typespec_word = cts_floatn_nx; - specs->locations[cdw_typespec] = loc; - } - return specs; - case RID_DFLOAT32: - case RID_DFLOAT64: - case RID_DFLOAT128: - { - const char *str; - if (i == RID_DFLOAT32) - str = "_Decimal32"; - else if (i == RID_DFLOAT64) - str = "_Decimal64"; - else - str = "_Decimal128"; - if (specs->long_long_p) - error_at (loc, - ("both % and %qs in " - "declaration specifiers"), - str); - if (specs->long_p) - error_at (loc, - ("both % and %qs in " - "declaration specifiers"), - str); - else if (specs->short_p) - error_at (loc, - ("both % and %qs in " - "declaration specifiers"), - str); - else if (specs->signed_p) - error_at (loc, - ("both % and %qs in " - "declaration specifiers"), - str); - else if (specs->unsigned_p) - error_at (loc, - ("both % and %qs in " - "declaration specifiers"), - str); - else if (specs->complex_p) - error_at (loc, - ("both % and %qs in " - "declaration specifiers"), - str); - else if (specs->saturating_p) - error_at (loc, - ("both %<_Sat%> and %qs in " - "declaration specifiers"), - str); - else if (i == RID_DFLOAT32) - specs->typespec_word = cts_dfloat32; - else if (i == RID_DFLOAT64) - specs->typespec_word = cts_dfloat64; - else - specs->typespec_word = cts_dfloat128; - specs->locations[cdw_typespec] = loc; - } - if (!targetm.decimal_float_supported_p ()) - error_at (loc, - ("decimal floating-point not supported " - "for this target")); - pedwarn_c11 (loc, OPT_Wpedantic, - "ISO C does not support decimal floating-point " - "before C2X"); - return specs; - case RID_FRACT: - case RID_ACCUM: - { - const char *str; - if (i == RID_FRACT) - str = "_Fract"; - else - str = "_Accum"; - if (specs->complex_p) - error_at (loc, - ("both % and %qs in " - "declaration specifiers"), - str); - else if (i == RID_FRACT) - specs->typespec_word = cts_fract; - else - specs->typespec_word = cts_accum; - specs->locations[cdw_typespec] = loc; - } - if (!targetm.fixed_point_supported_p ()) - error_at (loc, - "fixed-point types not supported for this target"); - pedwarn (loc, OPT_Wpedantic, - "ISO C does not support fixed-point types"); - return specs; - default: - /* ObjC reserved word "id", handled below. */ - break; - } - } - } - - /* Now we have a typedef (a TYPE_DECL node), an identifier (some - form of ObjC type, cases such as "int" and "long" being handled - above), a TYPE (struct, union, enum and typeof specifiers) or an - ERROR_MARK. In none of these cases may there have previously - been any type specifiers. */ - if (specs->type || specs->typespec_word != cts_none - || specs->long_p || specs->short_p || specs->signed_p - || specs->unsigned_p || specs->complex_p) - error_at (loc, "two or more data types in declaration specifiers"); - else if (TREE_CODE (type) == TYPE_DECL) - { - if (TREE_TYPE (type) == error_mark_node) - ; /* Allow the type to default to int to avoid cascading errors. */ - else - { - specs->type = TREE_TYPE (type); - specs->decl_attr = DECL_ATTRIBUTES (type); - specs->typedef_p = true; - specs->explicit_signed_p = C_TYPEDEF_EXPLICITLY_SIGNED (type); - specs->locations[cdw_typedef] = loc; - - /* If this typedef name is defined in a struct, then a C++ - lookup would return a different value. */ - if (warn_cxx_compat - && I_SYMBOL_BINDING (DECL_NAME (type))->in_struct) - warning_at (loc, OPT_Wc___compat, - "C++ lookup of %qD would return a field, not a type", - type); - - /* If we are parsing a struct, record that a struct field - used a typedef. */ - if (warn_cxx_compat && struct_parse_info != NULL) - struct_parse_info->typedefs_seen.safe_push (type); - } - } - else if (TREE_CODE (type) == IDENTIFIER_NODE) - { - tree t = lookup_name (type); - if (!t || TREE_CODE (t) != TYPE_DECL) - error_at (loc, "%qE fails to be a typedef or built in type", type); - else if (TREE_TYPE (t) == error_mark_node) - ; - else - { - specs->type = TREE_TYPE (t); - specs->locations[cdw_typespec] = loc; - } - } - else - { - if (TREE_CODE (type) != ERROR_MARK && spec.kind == ctsk_typeof) - { - specs->typedef_p = true; - specs->locations[cdw_typedef] = loc; - if (spec.expr) - { - if (specs->expr) - specs->expr = build2 (COMPOUND_EXPR, TREE_TYPE (spec.expr), - specs->expr, spec.expr); - else - specs->expr = spec.expr; - specs->expr_const_operands &= spec.expr_const_operands; - } - } - specs->type = type; - } - - return specs; -} - -/* Add the storage class specifier or function specifier SCSPEC to the - declaration specifiers SPECS, returning SPECS. */ - -struct c_declspecs * -declspecs_add_scspec (location_t loc, - struct c_declspecs *specs, - tree scspec) -{ - enum rid i; - enum c_storage_class n = csc_none; - bool dupe = false; - specs->declspecs_seen_p = true; - specs->non_std_attrs_seen_p = true; - gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE - && C_IS_RESERVED_WORD (scspec)); - i = C_RID_CODE (scspec); - if (specs->non_sc_seen_p) - warning (OPT_Wold_style_declaration, - "%qE is not at beginning of declaration", scspec); - switch (i) - { - case RID_INLINE: - /* C99 permits duplicate inline. Although of doubtful utility, - it seems simplest to permit it in gnu89 mode as well, as - there is also little utility in maintaining this as a - difference between gnu89 and C99 inline. */ - dupe = false; - specs->inline_p = true; - specs->locations[cdw_inline] = loc; - break; - case RID_NORETURN: - /* Duplicate _Noreturn is permitted. */ - dupe = false; - specs->noreturn_p = true; - specs->locations[cdw_noreturn] = loc; - break; - case RID_THREAD: - dupe = specs->thread_p; - if (specs->storage_class == csc_auto) - error ("%qE used with %", scspec); - else if (specs->storage_class == csc_register) - error ("%qE used with %", scspec); - else if (specs->storage_class == csc_typedef) - error ("%qE used with %", scspec); - else - { - specs->thread_p = true; - specs->thread_gnu_p = (strcmp (IDENTIFIER_POINTER (scspec), - "__thread") == 0); - /* A diagnostic is not required for the use of this - identifier in the implementation namespace; only diagnose - it for the C11 spelling because of existing code using - the other spelling. */ - if (!specs->thread_gnu_p) - { - if (flag_isoc99) - pedwarn_c99 (loc, OPT_Wpedantic, - "ISO C99 does not support %qE", scspec); - else - pedwarn_c99 (loc, OPT_Wpedantic, - "ISO C90 does not support %qE", scspec); - } - specs->locations[cdw_thread] = loc; - } - break; - case RID_AUTO: - n = csc_auto; - break; - case RID_EXTERN: - n = csc_extern; - /* Diagnose "__thread extern". */ - if (specs->thread_p && specs->thread_gnu_p) - error ("%<__thread%> before %"); - break; - case RID_REGISTER: - n = csc_register; - break; - case RID_STATIC: - n = csc_static; - /* Diagnose "__thread static". */ - if (specs->thread_p && specs->thread_gnu_p) - error ("%<__thread%> before %"); - break; - case RID_TYPEDEF: - n = csc_typedef; - break; - default: - gcc_unreachable (); - } - if (n != csc_none && n == specs->storage_class) - dupe = true; - if (dupe) - { - if (i == RID_THREAD) - error ("duplicate %<_Thread_local%> or %<__thread%>"); - else - error ("duplicate %qE", scspec); - } - if (n != csc_none) - { - if (specs->storage_class != csc_none && n != specs->storage_class) - { - error ("multiple storage classes in declaration specifiers"); - } - else - { - specs->storage_class = n; - specs->locations[cdw_storage_class] = loc; - if (n != csc_extern && n != csc_static && specs->thread_p) - { - error ("%qs used with %qE", - specs->thread_gnu_p ? "__thread" : "_Thread_local", - scspec); - specs->thread_p = false; - } - } - } - return specs; -} - -/* Add the attributes ATTRS to the declaration specifiers SPECS, - returning SPECS. */ - -struct c_declspecs * -declspecs_add_attrs (location_t loc, struct c_declspecs *specs, tree attrs) -{ - specs->attrs = chainon (attrs, specs->attrs); - specs->locations[cdw_attributes] = loc; - specs->declspecs_seen_p = true; - /* In the case of standard attributes at the start of the - declaration, the caller will reset this. */ - specs->non_std_attrs_seen_p = true; - return specs; -} - -/* Add an _Alignas specifier (expression ALIGN, or type whose - alignment is ALIGN) to the declaration specifiers SPECS, returning - SPECS. */ -struct c_declspecs * -declspecs_add_alignas (location_t loc, - struct c_declspecs *specs, tree align) -{ - specs->alignas_p = true; - specs->locations[cdw_alignas] = loc; - if (align == error_mark_node) - return specs; - - /* Only accept the alignment if it's valid and greater than - the current one. Zero is invalid but by C11 required to - be silently ignored. */ - int align_log = check_user_alignment (align, false, /* warn_zero = */false); - if (align_log > specs->align_log) - specs->align_log = align_log; - return specs; -} - -/* Combine "long", "short", "signed", "unsigned" and "_Complex" type - specifiers with any other type specifier to determine the resulting - type. This is where ISO C checks on complex types are made, since - "_Complex long" is a prefix of the valid ISO C type "_Complex long - double". Also apply postfix standard attributes to modify the type. */ - -struct c_declspecs * -finish_declspecs (struct c_declspecs *specs) -{ - /* If a type was specified as a whole, we have no modifiers and are - done. */ - if (specs->type != NULL_TREE) - { - gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p - && !specs->complex_p); - - /* Set a dummy type. */ - if (TREE_CODE (specs->type) == ERROR_MARK) - specs->type = integer_type_node; - goto handle_postfix_attrs; - } - - /* If none of "void", "_Bool", "char", "int", "float" or "double" - has been specified, treat it as "int" unless "_Complex" is - present and there are no other specifiers. If we just have - "_Complex", it is equivalent to "_Complex double", but e.g. - "_Complex short" is equivalent to "_Complex short int". */ - if (specs->typespec_word == cts_none) - { - if (specs->saturating_p) - { - error_at (specs->locations[cdw_saturating], - "%<_Sat%> is used without %<_Fract%> or %<_Accum%>"); - if (!targetm.fixed_point_supported_p ()) - error_at (specs->locations[cdw_saturating], - "fixed-point types not supported for this target"); - specs->typespec_word = cts_fract; - } - else if (specs->long_p || specs->short_p - || specs->signed_p || specs->unsigned_p) - { - specs->typespec_word = cts_int; - } - else if (specs->complex_p) - { - specs->typespec_word = cts_double; - pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, - "ISO C does not support plain % meaning " - "%"); - } - else - { - specs->typespec_word = cts_int; - specs->default_int_p = true; - /* We don't diagnose this here because grokdeclarator will - give more specific diagnostics according to whether it is - a function definition. */ - } - } - - /* If "signed" was specified, record this to distinguish "int" and - "signed int" in the case of a bit-field with - -funsigned-bitfields. */ - specs->explicit_signed_p = specs->signed_p; - - /* Now compute the actual type. */ - switch (specs->typespec_word) - { - case cts_auto_type: - gcc_assert (!specs->long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p - && !specs->complex_p); - /* Type to be filled in later. */ - if (specs->postfix_attrs) - error ("%<__auto_type%> followed by %<[[]]%> attributes"); - break; - case cts_void: - gcc_assert (!specs->long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p - && !specs->complex_p); - specs->type = void_type_node; - break; - case cts_bool: - gcc_assert (!specs->long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p - && !specs->complex_p); - specs->type = boolean_type_node; - break; - case cts_char: - gcc_assert (!specs->long_p && !specs->short_p); - gcc_assert (!(specs->signed_p && specs->unsigned_p)); - if (specs->signed_p) - specs->type = signed_char_type_node; - else if (specs->unsigned_p) - specs->type = unsigned_char_type_node; - else - specs->type = char_type_node; - if (specs->complex_p) - { - pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, - "ISO C does not support complex integer types"); - specs->type = build_complex_type (specs->type); - } - break; - case cts_int_n: - gcc_assert (!specs->long_p && !specs->short_p && !specs->long_long_p); - gcc_assert (!(specs->signed_p && specs->unsigned_p)); - if (! int_n_enabled_p[specs->int_n_idx]) - specs->type = integer_type_node; - else - specs->type = (specs->unsigned_p - ? int_n_trees[specs->int_n_idx].unsigned_type - : int_n_trees[specs->int_n_idx].signed_type); - if (specs->complex_p) - { - pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, - "ISO C does not support complex integer types"); - specs->type = build_complex_type (specs->type); - } - break; - case cts_int: - gcc_assert (!(specs->long_p && specs->short_p)); - gcc_assert (!(specs->signed_p && specs->unsigned_p)); - if (specs->long_long_p) - specs->type = (specs->unsigned_p - ? long_long_unsigned_type_node - : long_long_integer_type_node); - else if (specs->long_p) - specs->type = (specs->unsigned_p - ? long_unsigned_type_node - : long_integer_type_node); - else if (specs->short_p) - specs->type = (specs->unsigned_p - ? short_unsigned_type_node - : short_integer_type_node); - else - specs->type = (specs->unsigned_p - ? unsigned_type_node - : integer_type_node); - if (specs->complex_p) - { - pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, - "ISO C does not support complex integer types"); - specs->type = build_complex_type (specs->type); - } - break; - case cts_float: - gcc_assert (!specs->long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p); - specs->type = (specs->complex_p - ? complex_float_type_node - : float_type_node); - break; - case cts_double: - gcc_assert (!specs->long_long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p); - if (specs->long_p) - { - specs->type = (specs->complex_p - ? complex_long_double_type_node - : long_double_type_node); - } - else - { - specs->type = (specs->complex_p - ? complex_double_type_node - : double_type_node); - } - break; - case cts_floatn_nx: - gcc_assert (!specs->long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p); - if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE) - specs->type = integer_type_node; - else if (specs->complex_p) - specs->type = COMPLEX_FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx); - else - specs->type = FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx); - break; - case cts_dfloat32: - case cts_dfloat64: - case cts_dfloat128: - gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p && !specs->complex_p); - if (!targetm.decimal_float_supported_p ()) - specs->type = integer_type_node; - else if (specs->typespec_word == cts_dfloat32) - specs->type = dfloat32_type_node; - else if (specs->typespec_word == cts_dfloat64) - specs->type = dfloat64_type_node; - else - specs->type = dfloat128_type_node; - break; - case cts_fract: - gcc_assert (!specs->complex_p); - if (!targetm.fixed_point_supported_p ()) - specs->type = integer_type_node; - else if (specs->saturating_p) - { - if (specs->long_long_p) - specs->type = specs->unsigned_p - ? sat_unsigned_long_long_fract_type_node - : sat_long_long_fract_type_node; - else if (specs->long_p) - specs->type = specs->unsigned_p - ? sat_unsigned_long_fract_type_node - : sat_long_fract_type_node; - else if (specs->short_p) - specs->type = specs->unsigned_p - ? sat_unsigned_short_fract_type_node - : sat_short_fract_type_node; - else - specs->type = specs->unsigned_p - ? sat_unsigned_fract_type_node - : sat_fract_type_node; - } - else - { - if (specs->long_long_p) - specs->type = specs->unsigned_p - ? unsigned_long_long_fract_type_node - : long_long_fract_type_node; - else if (specs->long_p) - specs->type = specs->unsigned_p - ? unsigned_long_fract_type_node - : long_fract_type_node; - else if (specs->short_p) - specs->type = specs->unsigned_p - ? unsigned_short_fract_type_node - : short_fract_type_node; - else - specs->type = specs->unsigned_p - ? unsigned_fract_type_node - : fract_type_node; - } - break; - case cts_accum: - gcc_assert (!specs->complex_p); - if (!targetm.fixed_point_supported_p ()) - specs->type = integer_type_node; - else if (specs->saturating_p) - { - if (specs->long_long_p) - specs->type = specs->unsigned_p - ? sat_unsigned_long_long_accum_type_node - : sat_long_long_accum_type_node; - else if (specs->long_p) - specs->type = specs->unsigned_p - ? sat_unsigned_long_accum_type_node - : sat_long_accum_type_node; - else if (specs->short_p) - specs->type = specs->unsigned_p - ? sat_unsigned_short_accum_type_node - : sat_short_accum_type_node; - else - specs->type = specs->unsigned_p - ? sat_unsigned_accum_type_node - : sat_accum_type_node; - } - else - { - if (specs->long_long_p) - specs->type = specs->unsigned_p - ? unsigned_long_long_accum_type_node - : long_long_accum_type_node; - else if (specs->long_p) - specs->type = specs->unsigned_p - ? unsigned_long_accum_type_node - : long_accum_type_node; - else if (specs->short_p) - specs->type = specs->unsigned_p - ? unsigned_short_accum_type_node - : short_accum_type_node; - else - specs->type = specs->unsigned_p - ? unsigned_accum_type_node - : accum_type_node; - } - break; - default: - gcc_unreachable (); - } - handle_postfix_attrs: - if (specs->type != NULL) - { - specs->postfix_attrs = c_warn_type_attributes (specs->postfix_attrs); - decl_attributes (&specs->type, specs->postfix_attrs, 0); - specs->postfix_attrs = NULL_TREE; - } - - return specs; -} - -/* Perform final processing on one file scope's declarations (or the - external scope's declarations), GLOBALS. */ - -static void -c_write_global_declarations_1 (tree globals) -{ - tree decl; - bool reconsider; - - /* Process the decls in the order they were written. */ - for (decl = globals; decl; decl = DECL_CHAIN (decl)) - { - /* Check for used but undefined static functions using the C - standard's definition of "used", and set TREE_NO_WARNING so - that check_global_declaration doesn't repeat the check. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_INITIAL (decl) == NULL_TREE - && DECL_EXTERNAL (decl) - && !TREE_PUBLIC (decl)) - { - if (C_DECL_USED (decl)) - { - /* TODO: Add OPT_Wundefined-inline. */ - if (pedwarn (input_location, 0, "%q+F used but never defined", - decl)) - suppress_warning (decl /* OPT_Wundefined-inline. */); - } - /* For -Wunused-function warn about unused static prototypes. */ - else if (warn_unused_function - && ! DECL_ARTIFICIAL (decl) - && ! warning_suppressed_p (decl, OPT_Wunused_function)) - { - if (warning (OPT_Wunused_function, - "%q+F declared % but never defined", - decl)) - suppress_warning (decl, OPT_Wunused_function); - } - } - - wrapup_global_declaration_1 (decl); - } - - do - { - reconsider = false; - for (decl = globals; decl; decl = DECL_CHAIN (decl)) - reconsider |= wrapup_global_declaration_2 (decl); - } - while (reconsider); -} - -/* Preserve the external declarations scope across a garbage collect. */ -static GTY(()) tree ext_block; - -/* Collect all references relevant to SOURCE_FILE. */ - -static void -collect_all_refs (const char *source_file) -{ - tree t; - unsigned i; - - FOR_EACH_VEC_ELT (*all_translation_units, i, t) - collect_ada_nodes (BLOCK_VARS (DECL_INITIAL (t)), source_file); - - collect_ada_nodes (BLOCK_VARS (ext_block), source_file); -} - -/* Collect source file references at global level. */ - -static void -collect_source_refs (void) -{ - tree t; - tree decls; - tree decl; - unsigned i; - - FOR_EACH_VEC_ELT (*all_translation_units, i, t) - { - decls = DECL_INITIAL (t); - for (decl = BLOCK_VARS (decls); decl; decl = TREE_CHAIN (decl)) - if (!DECL_IS_UNDECLARED_BUILTIN (decl)) - collect_source_ref (DECL_SOURCE_FILE (decl)); - } - - for (decl = BLOCK_VARS (ext_block); decl; decl = TREE_CHAIN (decl)) - if (!DECL_IS_UNDECLARED_BUILTIN (decl)) - collect_source_ref (DECL_SOURCE_FILE (decl)); -} - -/* Free attribute access data that are not needed by the middle end. */ - -static void -free_attr_access_data () -{ - struct cgraph_node *n; - - /* Iterate over all functions declared in the translation unit. */ - FOR_EACH_FUNCTION (n) - { - for (tree parm = DECL_ARGUMENTS (n->decl); parm; parm = TREE_CHAIN (parm)) - if (tree attrs = DECL_ATTRIBUTES (parm)) - attr_access::free_lang_data (attrs); - - tree fntype = TREE_TYPE (n->decl); - if (!fntype || fntype == error_mark_node) - continue; - tree attrs = TYPE_ATTRIBUTES (fntype); - if (!attrs) - continue; - - attr_access::free_lang_data (attrs); - } -} - -/* Perform any final parser cleanups and generate initial debugging - information. */ - -void -c_parse_final_cleanups (void) -{ - tree t; - unsigned i; - - /* We don't want to do this if generating a PCH. */ - if (pch_file) - return; - - timevar_stop (TV_PHASE_PARSING); - timevar_start (TV_PHASE_DEFERRED); - - /* Do the Objective-C stuff. This is where all the Objective-C - module stuff gets generated (symtab, class/protocol/selector - lists etc). */ - if (c_dialect_objc ()) - objc_write_global_declarations (); - - /* Close the external scope. */ - ext_block = pop_scope (); - external_scope = 0; - gcc_assert (!current_scope); - - /* Handle -fdump-ada-spec[-slim]. */ - if (flag_dump_ada_spec || flag_dump_ada_spec_slim) - { - /* Build a table of files to generate specs for */ - collect_source_ref (main_input_filename); - if (!flag_dump_ada_spec_slim) - collect_source_refs (); - - dump_ada_specs (collect_all_refs, NULL); - } - - /* Process all file scopes in this compilation, and the external_scope, - through wrapup_global_declarations. */ - FOR_EACH_VEC_ELT (*all_translation_units, i, t) - c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t))); - c_write_global_declarations_1 (BLOCK_VARS (ext_block)); - - if (!in_lto_p) - free_attr_access_data (); - - timevar_stop (TV_PHASE_DEFERRED); - timevar_start (TV_PHASE_PARSING); - - ext_block = NULL; -} - -/* Register reserved keyword WORD as qualifier for address space AS. */ - -void -c_register_addr_space (const char *word, addr_space_t as) -{ - int rid = RID_FIRST_ADDR_SPACE + as; - tree id; - - /* Address space qualifiers are only supported - in C with GNU extensions enabled. */ - if (c_dialect_objc () || flag_no_asm) - return; - - id = get_identifier (word); - C_SET_RID_CODE (id, rid); - C_IS_RESERVED_WORD (id) = 1; - ridpointers [rid] = id; -} - -/* Return identifier to look up for omp declare reduction. */ - -tree -c_omp_reduction_id (enum tree_code reduction_code, tree reduction_id) -{ - const char *p = NULL; - switch (reduction_code) - { - case PLUS_EXPR: p = "+"; break; - case MULT_EXPR: p = "*"; break; - case MINUS_EXPR: p = "-"; break; - case BIT_AND_EXPR: p = "&"; break; - case BIT_XOR_EXPR: p = "^"; break; - case BIT_IOR_EXPR: p = "|"; break; - case TRUTH_ANDIF_EXPR: p = "&&"; break; - case TRUTH_ORIF_EXPR: p = "||"; break; - case MIN_EXPR: p = "min"; break; - case MAX_EXPR: p = "max"; break; - default: - break; - } - - if (p == NULL) - { - if (TREE_CODE (reduction_id) != IDENTIFIER_NODE) - return error_mark_node; - p = IDENTIFIER_POINTER (reduction_id); - } - - const char prefix[] = "omp declare reduction "; - size_t lenp = sizeof (prefix); - size_t len = strlen (p); - char *name = XALLOCAVEC (char, lenp + len); - memcpy (name, prefix, lenp - 1); - memcpy (name + lenp - 1, p, len + 1); - return get_identifier (name); -} - -/* Lookup REDUCTION_ID in the current scope, or create an artificial - VAR_DECL, bind it into the current scope and return it. */ - -tree -c_omp_reduction_decl (tree reduction_id) -{ - struct c_binding *b = I_SYMBOL_BINDING (reduction_id); - if (b != NULL && B_IN_CURRENT_SCOPE (b)) - return b->decl; - - tree decl = build_decl (BUILTINS_LOCATION, VAR_DECL, - reduction_id, integer_type_node); - DECL_ARTIFICIAL (decl) = 1; - DECL_EXTERNAL (decl) = 1; - TREE_STATIC (decl) = 1; - TREE_PUBLIC (decl) = 0; - bind (reduction_id, decl, current_scope, true, false, BUILTINS_LOCATION); - return decl; -} - -/* Lookup REDUCTION_ID in the first scope where it has entry for TYPE. */ - -tree -c_omp_reduction_lookup (tree reduction_id, tree type) -{ - struct c_binding *b = I_SYMBOL_BINDING (reduction_id); - while (b) - { - tree t; - for (t = DECL_INITIAL (b->decl); t; t = TREE_CHAIN (t)) - if (comptypes (TREE_PURPOSE (t), type)) - return TREE_VALUE (t); - b = b->shadowed; - } - return error_mark_node; -} - -/* Helper function called via walk_tree, to diagnose invalid - #pragma omp declare reduction combiners or initializers. */ - -tree -c_check_omp_declare_reduction_r (tree *tp, int *, void *data) -{ - tree *vars = (tree *) data; - if (SSA_VAR_P (*tp) - && !DECL_ARTIFICIAL (*tp) - && *tp != vars[0] - && *tp != vars[1]) - { - location_t loc = DECL_SOURCE_LOCATION (vars[0]); - if (strcmp (IDENTIFIER_POINTER (DECL_NAME (vars[0])), "omp_out") == 0) - error_at (loc, "%<#pragma omp declare reduction%> combiner refers to " - "variable %qD which is not % nor %", - *tp); - else - error_at (loc, "%<#pragma omp declare reduction%> initializer refers " - "to variable %qD which is not % nor " - "%", - *tp); - return *tp; - } - return NULL_TREE; -} - - -bool -c_check_in_current_scope (tree decl) -{ - struct c_binding *b = I_SYMBOL_BINDING (DECL_NAME (decl)); - return b != NULL && B_IN_CURRENT_SCOPE (b); -} - -#include "gt-c-c-decl.h" diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc new file mode 100644 index 0000000..29a79eb --- /dev/null +++ b/gcc/c/c-decl.cc @@ -0,0 +1,12469 @@ +/* Process declarations and variables for C compiler. + Copyright (C) 1988-2022 Free Software Foundation, Inc. + +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 +. */ + +/* Process declarations and symbol lookup for C front end. + Also constructs types; the standard scalar types at initialization, + and structure, union, array and enum types when they are declared. */ + +/* ??? not all decl nodes are given the most useful possible + line numbers. For example, the CONST_DECLs for enum values. */ + +#include "config.h" +#define INCLUDE_STRING +#define INCLUDE_MEMORY +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "function.h" +#include "c-tree.h" +#include "timevar.h" +#include "stringpool.h" +#include "cgraph.h" +#include "intl.h" +#include "print-tree.h" +#include "stor-layout.h" +#include "varasm.h" +#include "attribs.h" +#include "toplev.h" +#include "debug.h" +#include "c-family/c-objc.h" +#include "c-family/c-pragma.h" +#include "c-family/c-ubsan.h" +#include "c-lang.h" +#include "langhooks.h" +#include "tree-iterator.h" +#include "dumpfile.h" +#include "plugin.h" +#include "c-family/c-ada-spec.h" +#include "builtins.h" +#include "spellcheck-tree.h" +#include "gcc-rich-location.h" +#include "asan.h" +#include "c-family/name-hint.h" +#include "c-family/known-headers.h" +#include "c-family/c-spellcheck.h" +#include "context.h" /* For 'g'. */ +#include "omp-general.h" +#include "omp-offload.h" /* For offload_vars. */ + +#include "tree-pretty-print.h" + +/* In grokdeclarator, distinguish syntactic contexts of declarators. */ +enum decl_context +{ NORMAL, /* Ordinary declaration */ + FUNCDEF, /* Function definition */ + PARM, /* Declaration of parm before function body */ + FIELD, /* Declaration inside struct or union */ + TYPENAME}; /* Typename (inside cast or sizeof) */ + +/* States indicating how grokdeclarator() should handle declspecs marked + with __attribute__((deprecated)) or __attribute__((unavailable)). + An object declared as __attribute__((unavailable)) should suppress + any reports of being declared with unavailable or deprecated items. + An object declared as __attribute__((deprecated)) should suppress + warnings of uses of other deprecated items. */ + +enum deprecated_states { + DEPRECATED_NORMAL, + DEPRECATED_SUPPRESS, + UNAVAILABLE_DEPRECATED_SUPPRESS +}; + + +/* Nonzero if we have seen an invalid cross reference + to a struct, union, or enum, but not yet printed the message. */ +tree pending_invalid_xref; + +/* File and line to appear in the eventual error message. */ +location_t pending_invalid_xref_location; + +/* The file and line that the prototype came from if this is an + old-style definition; used for diagnostics in + store_parm_decls_oldstyle. */ + +static location_t current_function_prototype_locus; + +/* Whether this prototype was built-in. */ + +static bool current_function_prototype_built_in; + +/* The argument type information of this prototype. */ + +static tree current_function_prototype_arg_types; + +/* The argument information structure for the function currently being + defined. */ + +static struct c_arg_info *current_function_arg_info; + +/* The obstack on which parser and related data structures, which are + not live beyond their top-level declaration or definition, are + allocated. */ +struct obstack parser_obstack; + +/* The current statement tree. */ + +static GTY(()) struct stmt_tree_s c_stmt_tree; + +/* Zero if we are not in an iteration or switch statement, otherwise + a bitmask. See bitmask definitions in c-tree.h. */ +unsigned char in_statement; + +/* A list of decls to be made automatically visible in each file scope. */ +static GTY(()) tree visible_builtins; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement that specifies a return value is seen. */ + +int current_function_returns_value; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement with no argument is seen. */ + +int current_function_returns_null; + +/* Set to 0 at beginning of a function definition, set to 1 if + a call to a noreturn function is seen. */ + +int current_function_returns_abnormally; + +/* Set to nonzero by `grokdeclarator' for a function + whose return type is defaulted, if warnings for this are desired. */ + +static int warn_about_return_type; + +/* Nonzero when the current toplevel function contains a declaration + of a nested function which is never defined. */ + +static bool undef_nested_function; + +/* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ +int current_omp_declare_target_attribute; + +/* Each c_binding structure describes one binding of an identifier to + a decl. All the decls in a scope - irrespective of namespace - are + chained together by the ->prev field, which (as the name implies) + runs in reverse order. All the decls in a given namespace bound to + a given identifier are chained by the ->shadowed field, which runs + from inner to outer scopes. + + The ->decl field usually points to a DECL node, but there are two + exceptions. In the namespace of type tags, the bound entity is a + RECORD_TYPE, UNION_TYPE, or ENUMERAL_TYPE node. If an undeclared + identifier is encountered, it is bound to error_mark_node to + suppress further errors about that identifier in the current + function. + + The ->u.type field stores the type of the declaration in this scope; + if NULL, the type is the type of the ->decl field. This is only of + relevance for objects with external or internal linkage which may + be redeclared in inner scopes, forming composite types that only + persist for the duration of those scopes. In the external scope, + this stores the composite of all the types declared for this + object, visible or not. The ->inner_comp field (used only at file + scope) stores whether an incomplete array type at file scope was + completed at an inner scope to an array size other than 1. + + The ->u.label field is used for labels. It points to a structure + which stores additional information used for warnings. + + The depth field is copied from the scope structure that holds this + decl. It is used to preserve the proper ordering of the ->shadowed + field (see bind()) and also for a handful of special-case checks. + Finally, the invisible bit is true for a decl which should be + ignored for purposes of normal name lookup, and the nested bit is + true for a decl that's been bound a second time in an inner scope; + in all such cases, the binding in the outer scope will have its + invisible bit true. */ + +struct GTY((chain_next ("%h.prev"))) c_binding { + union GTY(()) { /* first so GTY desc can use decl */ + tree GTY((tag ("0"))) type; /* the type in this scope */ + struct c_label_vars * GTY((tag ("1"))) label; /* for warnings */ + } GTY((desc ("TREE_CODE (%0.decl) == LABEL_DECL"))) u; + tree decl; /* the decl bound */ + tree id; /* the identifier it's bound to */ + struct c_binding *prev; /* the previous decl in this scope */ + struct c_binding *shadowed; /* the innermost decl shadowed by this one */ + unsigned int depth : 28; /* depth of this scope */ + BOOL_BITFIELD invisible : 1; /* normal lookup should ignore this binding */ + BOOL_BITFIELD nested : 1; /* do not set DECL_CONTEXT when popping */ + BOOL_BITFIELD inner_comp : 1; /* incomplete array completed in inner scope */ + BOOL_BITFIELD in_struct : 1; /* currently defined as struct field */ + location_t locus; /* location for nested bindings */ +}; +#define B_IN_SCOPE(b1, b2) ((b1)->depth == (b2)->depth) +#define B_IN_CURRENT_SCOPE(b) ((b)->depth == current_scope->depth) +#define B_IN_FILE_SCOPE(b) ((b)->depth == 1 /*file_scope->depth*/) +#define B_IN_EXTERNAL_SCOPE(b) ((b)->depth == 0 /*external_scope->depth*/) + +/* Each C symbol points to three linked lists of c_binding structures. + These describe the values of the identifier in the three different + namespaces defined by the language. */ + +struct GTY(()) lang_identifier { + struct c_common_identifier common_id; + struct c_binding *symbol_binding; /* vars, funcs, constants, typedefs */ + struct c_binding *tag_binding; /* struct/union/enum tags */ + struct c_binding *label_binding; /* labels */ +}; + +/* Validate c-lang.c's assumptions. */ +extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate +[(sizeof(struct lang_identifier) == C_SIZEOF_STRUCT_LANG_IDENTIFIER) ? 1 : -1]; + +/* The binding oracle; see c-tree.h. */ +void (*c_binding_oracle) (enum c_oracle_request, tree identifier); + +/* This flag is set on an identifier if we have previously asked the + binding oracle for this identifier's symbol binding. */ +#define I_SYMBOL_CHECKED(node) \ + (TREE_LANG_FLAG_4 (IDENTIFIER_NODE_CHECK (node))) + +static inline struct c_binding* * +i_symbol_binding (tree node) +{ + struct lang_identifier *lid + = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node); + + if (lid->symbol_binding == NULL + && c_binding_oracle != NULL + && !I_SYMBOL_CHECKED (node)) + { + /* Set the "checked" flag first, to avoid infinite recursion + when the binding oracle calls back into gcc. */ + I_SYMBOL_CHECKED (node) = 1; + c_binding_oracle (C_ORACLE_SYMBOL, node); + } + + return &lid->symbol_binding; +} + +#define I_SYMBOL_BINDING(node) (*i_symbol_binding (node)) + +#define I_SYMBOL_DECL(node) \ + (I_SYMBOL_BINDING(node) ? I_SYMBOL_BINDING(node)->decl : 0) + +/* This flag is set on an identifier if we have previously asked the + binding oracle for this identifier's tag binding. */ +#define I_TAG_CHECKED(node) \ + (TREE_LANG_FLAG_5 (IDENTIFIER_NODE_CHECK (node))) + +static inline struct c_binding ** +i_tag_binding (tree node) +{ + struct lang_identifier *lid + = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node); + + if (lid->tag_binding == NULL + && c_binding_oracle != NULL + && !I_TAG_CHECKED (node)) + { + /* Set the "checked" flag first, to avoid infinite recursion + when the binding oracle calls back into gcc. */ + I_TAG_CHECKED (node) = 1; + c_binding_oracle (C_ORACLE_TAG, node); + } + + return &lid->tag_binding; +} + +#define I_TAG_BINDING(node) (*i_tag_binding (node)) + +#define I_TAG_DECL(node) \ + (I_TAG_BINDING(node) ? I_TAG_BINDING(node)->decl : 0) + +/* This flag is set on an identifier if we have previously asked the + binding oracle for this identifier's label binding. */ +#define I_LABEL_CHECKED(node) \ + (TREE_LANG_FLAG_6 (IDENTIFIER_NODE_CHECK (node))) + +static inline struct c_binding ** +i_label_binding (tree node) +{ + struct lang_identifier *lid + = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node); + + if (lid->label_binding == NULL + && c_binding_oracle != NULL + && !I_LABEL_CHECKED (node)) + { + /* Set the "checked" flag first, to avoid infinite recursion + when the binding oracle calls back into gcc. */ + I_LABEL_CHECKED (node) = 1; + c_binding_oracle (C_ORACLE_LABEL, node); + } + + return &lid->label_binding; +} + +#define I_LABEL_BINDING(node) (*i_label_binding (node)) + +#define I_LABEL_DECL(node) \ + (I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0) + +/* The resulting tree type. */ + +union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), + chain_next ("(union lang_tree_node *) c_tree_chain_next (&%h.generic)"))) lang_tree_node + { + union tree_node GTY ((tag ("0"), + desc ("tree_node_structure (&%h)"))) + generic; + struct lang_identifier GTY ((tag ("1"))) identifier; +}; + +/* Track bindings and other things that matter for goto warnings. For + efficiency, we do not gather all the decls at the point of + definition. Instead, we point into the bindings structure. As + scopes are popped, we update these structures and gather the decls + that matter at that time. */ + +struct GTY(()) c_spot_bindings { + /* The currently open scope which holds bindings defined when the + label was defined or the goto statement was found. */ + struct c_scope *scope; + /* The bindings in the scope field which were defined at the point + of the label or goto. This lets us look at older or newer + bindings in the scope, as appropriate. */ + struct c_binding *bindings_in_scope; + /* The number of statement expressions that have started since this + label or goto statement was defined. This is zero if we are at + the same statement expression level. It is positive if we are in + a statement expression started since this spot. It is negative + if this spot was in a statement expression and we have left + it. */ + int stmt_exprs; + /* Whether we started in a statement expression but are no longer in + it. This is set to true if stmt_exprs ever goes negative. */ + bool left_stmt_expr; +}; + +/* This structure is used to keep track of bindings seen when a goto + statement is defined. This is only used if we see the goto + statement before we see the label. */ + +struct GTY(()) c_goto_bindings { + /* The location of the goto statement. */ + location_t loc; + /* The bindings of the goto statement. */ + struct c_spot_bindings goto_bindings; +}; + +typedef struct c_goto_bindings *c_goto_bindings_p; + +/* The additional information we keep track of for a label binding. + These fields are updated as scopes are popped. */ + +struct GTY(()) c_label_vars { + /* The shadowed c_label_vars, when one label shadows another (which + can only happen using a __label__ declaration). */ + struct c_label_vars *shadowed; + /* The bindings when the label was defined. */ + struct c_spot_bindings label_bindings; + /* A list of decls that we care about: decls about which we should + warn if a goto branches to this label from later in the function. + Decls are added to this list as scopes are popped. We only add + the decls that matter. */ + vec *decls_in_scope; + /* A list of goto statements to this label. This is only used for + goto statements seen before the label was defined, so that we can + issue appropriate warnings for them. */ + vec *gotos; +}; + +/* Each c_scope structure describes the complete contents of one + scope. Four scopes are distinguished specially: the innermost or + current scope, the innermost function scope, the file scope (always + the second to outermost) and the outermost or external scope. + + Most declarations are recorded in the current scope. + + All normal label declarations are recorded in the innermost + function scope, as are bindings of undeclared identifiers to + error_mark_node. (GCC permits nested functions as an extension, + hence the 'innermost' qualifier.) Explicitly declared labels + (using the __label__ extension) appear in the current scope. + + Being in the file scope (current_scope == file_scope) causes + special behavior in several places below. Also, under some + conditions the Objective-C front end records declarations in the + file scope even though that isn't the current scope. + + All declarations with external linkage are recorded in the external + scope, even if they aren't visible there; this models the fact that + such declarations are visible to the entire program, and (with a + bit of cleverness, see pushdecl) allows diagnosis of some violations + of C99 6.2.2p7 and 6.2.7p2: + + If, within the same translation unit, the same identifier appears + with both internal and external linkage, the behavior is + undefined. + + All declarations that refer to the same object or function shall + have compatible type; otherwise, the behavior is undefined. + + Initially only the built-in declarations, which describe compiler + intrinsic functions plus a subset of the standard library, are in + this scope. + + The order of the blocks list matters, and it is frequently appended + to. To avoid having to walk all the way to the end of the list on + each insertion, or reverse the list later, we maintain a pointer to + the last list entry. (FIXME: It should be feasible to use a reversed + list here.) + + The bindings list is strictly in reverse order of declarations; + pop_scope relies on this. */ + + +struct GTY((chain_next ("%h.outer"))) c_scope { + /* The scope containing this one. */ + struct c_scope *outer; + + /* The next outermost function scope. */ + struct c_scope *outer_function; + + /* All bindings in this scope. */ + struct c_binding *bindings; + + /* For each scope (except the global one), a chain of BLOCK nodes + for all the scopes that were entered and exited one level down. */ + tree blocks; + tree blocks_last; + + /* The depth of this scope. Used to keep the ->shadowed chain of + bindings sorted innermost to outermost. */ + unsigned int depth : 28; + + /* True if we are currently filling this scope with parameter + declarations. */ + BOOL_BITFIELD parm_flag : 1; + + /* True if we saw [*] in this scope. Used to give an error messages + if these appears in a function definition. */ + BOOL_BITFIELD had_vla_unspec : 1; + + /* True if we already complained about forward parameter decls + in this scope. This prevents double warnings on + foo (int a; int b; ...) */ + BOOL_BITFIELD warned_forward_parm_decls : 1; + + /* True if this is the outermost block scope of a function body. + This scope contains the parameters, the local variables declared + in the outermost block, and all the labels (except those in + nested functions, or declared at block scope with __label__). */ + BOOL_BITFIELD function_body : 1; + + /* True means make a BLOCK for this scope no matter what. */ + BOOL_BITFIELD keep : 1; + + /* True means that an unsuffixed float constant is _Decimal64. */ + BOOL_BITFIELD float_const_decimal64 : 1; + + /* True if this scope has any label bindings. This is used to speed + up searching for labels when popping scopes, particularly since + labels are normally only found at function scope. */ + BOOL_BITFIELD has_label_bindings : 1; + + /* True if we should issue a warning if a goto statement crosses any + of the bindings. We still need to check the list of bindings to + find the specific ones we need to warn about. This is true if + decl_jump_unsafe would return true for any of the bindings. This + is used to avoid looping over all the bindings unnecessarily. */ + BOOL_BITFIELD has_jump_unsafe_decl : 1; +}; + +/* The scope currently in effect. */ + +static GTY(()) struct c_scope *current_scope; + +/* The innermost function scope. Ordinary (not explicitly declared) + labels, bindings to error_mark_node, and the lazily-created + bindings of __func__ and its friends get this scope. */ + +static GTY(()) struct c_scope *current_function_scope; + +/* The C file scope. This is reset for each input translation unit. */ + +static GTY(()) struct c_scope *file_scope; + +/* The outermost scope. This is used for all declarations with + external linkage, and only these, hence the name. */ + +static GTY(()) struct c_scope *external_scope; + +/* A chain of c_scope structures awaiting reuse. */ + +static GTY((deletable)) struct c_scope *scope_freelist; + +/* A chain of c_binding structures awaiting reuse. */ + +static GTY((deletable)) struct c_binding *binding_freelist; + +/* Append VAR to LIST in scope SCOPE. */ +#define SCOPE_LIST_APPEND(scope, list, decl) do { \ + struct c_scope *s_ = (scope); \ + tree d_ = (decl); \ + if (s_->list##_last) \ + BLOCK_CHAIN (s_->list##_last) = d_; \ + else \ + s_->list = d_; \ + s_->list##_last = d_; \ +} while (0) + +/* Concatenate FROM in scope FSCOPE onto TO in scope TSCOPE. */ +#define SCOPE_LIST_CONCAT(tscope, to, fscope, from) do { \ + struct c_scope *t_ = (tscope); \ + struct c_scope *f_ = (fscope); \ + if (t_->to##_last) \ + BLOCK_CHAIN (t_->to##_last) = f_->from; \ + else \ + t_->to = f_->from; \ + t_->to##_last = f_->from##_last; \ +} while (0) + +/* A c_inline_static structure stores details of a static identifier + referenced in a definition of a function that may be an inline + definition if no subsequent declaration of that function uses + "extern" or does not use "inline". */ + +struct GTY((chain_next ("%h.next"))) c_inline_static { + /* The location for a diagnostic. */ + location_t location; + + /* The function that may be an inline definition. */ + tree function; + + /* The object or function referenced. */ + tree static_decl; + + /* What sort of reference this is. */ + enum c_inline_static_type type; + + /* The next such structure or NULL. */ + struct c_inline_static *next; +}; + +/* List of static identifiers used or referenced in functions that may + be inline definitions. */ +static GTY(()) struct c_inline_static *c_inline_statics; + +/* True means unconditionally make a BLOCK for the next scope pushed. */ + +static bool keep_next_level_flag; + +/* True means the next call to push_scope will be the outermost scope + of a function body, so do not push a new scope, merely cease + expecting parameter decls. */ + +static bool next_is_function_body; + +/* A vector of pointers to c_binding structures. */ + +typedef struct c_binding *c_binding_ptr; + +/* Information that we keep for a struct or union while it is being + parsed. */ + +class c_struct_parse_info +{ +public: + /* If warn_cxx_compat, a list of types defined within this + struct. */ + auto_vec struct_types; + /* If warn_cxx_compat, a list of field names which have bindings, + and which are defined in this struct, but which are not defined + in any enclosing struct. This is used to clear the in_struct + field of the c_bindings structure. */ + auto_vec fields; + /* If warn_cxx_compat, a list of typedef names used when defining + fields in this struct. */ + auto_vec typedefs_seen; +}; + +/* Information for the struct or union currently being parsed, or + NULL if not parsing a struct or union. */ +static class c_struct_parse_info *struct_parse_info; + +/* Forward declarations. */ +static tree lookup_name_in_scope (tree, struct c_scope *); +static tree c_make_fname_decl (location_t, tree, int); +static tree grokdeclarator (const struct c_declarator *, + struct c_declspecs *, + enum decl_context, bool, tree *, tree *, tree *, + bool *, enum deprecated_states); +static tree grokparms (struct c_arg_info *, bool); +static void layout_array_type (tree); +static void warn_defaults_to (location_t, int, const char *, ...) + ATTRIBUTE_GCC_DIAG(3,4); +static const char *header_for_builtin_fn (tree); + +/* T is a statement. Add it to the statement-tree. This is the + C/ObjC version--C++ has a slightly different version of this + function. */ + +tree +add_stmt (tree t) +{ + enum tree_code code = TREE_CODE (t); + + if (CAN_HAVE_LOCATION_P (t) && code != LABEL_EXPR) + { + if (!EXPR_HAS_LOCATION (t)) + SET_EXPR_LOCATION (t, input_location); + } + + if (code == LABEL_EXPR || code == CASE_LABEL_EXPR) + STATEMENT_LIST_HAS_LABEL (cur_stmt_list) = 1; + + /* Add T to the statement-tree. Non-side-effect statements need to be + recorded during statement expressions. */ + if (!building_stmt_list_p ()) + push_stmt_list (); + append_to_statement_list_force (t, &cur_stmt_list); + + return t; +} + +/* Build a pointer type using the default pointer mode. */ + +static tree +c_build_pointer_type (tree to_type) +{ + addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC + : TYPE_ADDR_SPACE (to_type); + machine_mode pointer_mode; + + if (as != ADDR_SPACE_GENERIC || c_default_pointer_mode == VOIDmode) + pointer_mode = targetm.addr_space.pointer_mode (as); + else + pointer_mode = c_default_pointer_mode; + return build_pointer_type_for_mode (to_type, pointer_mode, false); +} + + +/* Return true if we will want to say something if a goto statement + crosses DECL. */ + +static bool +decl_jump_unsafe (tree decl) +{ + if (error_operand_p (decl)) + return false; + + /* Don't warn for compound literals. If a goto statement crosses + their initialization, it should cross also all the places where + the complit is used or where the complit address might be saved + into some variable, so code after the label to which goto jumps + should not be able to refer to the compound literal. */ + if (VAR_P (decl) && C_DECL_COMPOUND_LITERAL_P (decl)) + return false; + + /* Always warn about crossing variably modified types. */ + if ((VAR_P (decl) || TREE_CODE (decl) == TYPE_DECL) + && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + return true; + + /* Otherwise, only warn if -Wgoto-misses-init and this is an + initialized automatic decl. */ + if (warn_jump_misses_init + && VAR_P (decl) + && !TREE_STATIC (decl) + && DECL_INITIAL (decl) != NULL_TREE) + return true; + + return false; +} + + +void +c_print_identifier (FILE *file, tree node, int indent) +{ + void (*save) (enum c_oracle_request, tree identifier); + + /* Temporarily hide any binding oracle. Without this, calls to + debug_tree from the debugger will end up calling into the oracle, + making for a confusing debug session. As the oracle isn't needed + here for normal operation, it's simplest to suppress it. */ + save = c_binding_oracle; + c_binding_oracle = NULL; + + print_node (file, "symbol", I_SYMBOL_DECL (node), indent + 4); + print_node (file, "tag", I_TAG_DECL (node), indent + 4); + print_node (file, "label", I_LABEL_DECL (node), indent + 4); + if (C_IS_RESERVED_WORD (node) && C_RID_CODE (node) != RID_CXX_COMPAT_WARN) + { + tree rid = ridpointers[C_RID_CODE (node)]; + indent_to (file, indent + 4); + fprintf (file, "rid " HOST_PTR_PRINTF " \"%s\"", + (void *) rid, IDENTIFIER_POINTER (rid)); + } + + c_binding_oracle = save; +} + +/* Establish a binding between NAME, an IDENTIFIER_NODE, and DECL, + which may be any of several kinds of DECL or TYPE or error_mark_node, + in the scope SCOPE. */ +static void +bind (tree name, tree decl, struct c_scope *scope, bool invisible, + bool nested, location_t locus) +{ + struct c_binding *b, **here; + + if (binding_freelist) + { + b = binding_freelist; + binding_freelist = b->prev; + } + else + b = ggc_alloc (); + + b->shadowed = 0; + b->decl = decl; + b->id = name; + b->depth = scope->depth; + b->invisible = invisible; + b->nested = nested; + b->inner_comp = 0; + b->in_struct = 0; + b->locus = locus; + + b->u.type = NULL; + + b->prev = scope->bindings; + scope->bindings = b; + + if (decl_jump_unsafe (decl)) + scope->has_jump_unsafe_decl = 1; + + if (!name) + return; + + switch (TREE_CODE (decl)) + { + case LABEL_DECL: here = &I_LABEL_BINDING (name); break; + case ENUMERAL_TYPE: + case UNION_TYPE: + case RECORD_TYPE: here = &I_TAG_BINDING (name); break; + case VAR_DECL: + case FUNCTION_DECL: + case TYPE_DECL: + case CONST_DECL: + case PARM_DECL: + case ERROR_MARK: here = &I_SYMBOL_BINDING (name); break; + + default: + gcc_unreachable (); + } + + /* Locate the appropriate place in the chain of shadowed decls + to insert this binding. Normally, scope == current_scope and + this does nothing. */ + while (*here && (*here)->depth > scope->depth) + here = &(*here)->shadowed; + + b->shadowed = *here; + *here = b; +} + +/* Clear the binding structure B, stick it on the binding_freelist, + and return the former value of b->prev. This is used by pop_scope + and get_parm_info to iterate destructively over all the bindings + from a given scope. */ +static struct c_binding * +free_binding_and_advance (struct c_binding *b) +{ + struct c_binding *prev = b->prev; + + memset (b, 0, sizeof (struct c_binding)); + b->prev = binding_freelist; + binding_freelist = b; + + return prev; +} + +/* Bind a label. Like bind, but skip fields which aren't used for + labels, and add the LABEL_VARS value. */ +static void +bind_label (tree name, tree label, struct c_scope *scope, + struct c_label_vars *label_vars) +{ + struct c_binding *b; + + bind (name, label, scope, /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); + + scope->has_label_bindings = true; + + b = scope->bindings; + gcc_assert (b->decl == label); + label_vars->shadowed = b->u.label; + b->u.label = label_vars; +} + +/* Hook called at end of compilation to assume 1 elt + for a file-scope tentative array defn that wasn't complete before. */ + +void +c_finish_incomplete_decl (tree decl) +{ + if (VAR_P (decl)) + { + tree type = TREE_TYPE (decl); + if (type != error_mark_node + && TREE_CODE (type) == ARRAY_TYPE + && !DECL_EXTERNAL (decl) + && TYPE_DOMAIN (type) == NULL_TREE) + { + warning_at (DECL_SOURCE_LOCATION (decl), + 0, "array %q+D assumed to have one element", decl); + + complete_array_type (&TREE_TYPE (decl), NULL_TREE, true); + + relayout_decl (decl); + } + } +} + +/* Record that inline function FUNC contains a reference (location + LOC) to static DECL (file-scope or function-local according to + TYPE). */ + +void +record_inline_static (location_t loc, tree func, tree decl, + enum c_inline_static_type type) +{ + c_inline_static *csi = ggc_alloc (); + csi->location = loc; + csi->function = func; + csi->static_decl = decl; + csi->type = type; + csi->next = c_inline_statics; + c_inline_statics = csi; +} + +/* Check for references to static declarations in inline functions at + the end of the translation unit and diagnose them if the functions + are still inline definitions. */ + +static void +check_inline_statics (void) +{ + struct c_inline_static *csi; + for (csi = c_inline_statics; csi; csi = csi->next) + { + if (DECL_EXTERNAL (csi->function)) + switch (csi->type) + { + case csi_internal: + pedwarn (csi->location, 0, + "%qD is static but used in inline function %qD " + "which is not static", csi->static_decl, csi->function); + break; + case csi_modifiable: + pedwarn (csi->location, 0, + "%q+D is static but declared in inline function %qD " + "which is not static", csi->static_decl, csi->function); + break; + default: + gcc_unreachable (); + } + } + c_inline_statics = NULL; +} + +/* Fill in a c_spot_bindings structure. If DEFINING is true, set it + for the current state, otherwise set it to uninitialized. */ + +static void +set_spot_bindings (struct c_spot_bindings *p, bool defining) +{ + if (defining) + { + p->scope = current_scope; + p->bindings_in_scope = current_scope->bindings; + } + else + { + p->scope = NULL; + p->bindings_in_scope = NULL; + } + p->stmt_exprs = 0; + p->left_stmt_expr = false; +} + +/* Update spot bindings P as we pop out of SCOPE. Return true if we + should push decls for a label. */ + +static bool +update_spot_bindings (struct c_scope *scope, struct c_spot_bindings *p) +{ + if (p->scope != scope) + { + /* This label or goto is defined in some other scope, or it is a + label which is not yet defined. There is nothing to + update. */ + return false; + } + + /* Adjust the spot bindings to refer to the bindings already defined + in the enclosing scope. */ + p->scope = scope->outer; + p->bindings_in_scope = p->scope->bindings; + + return true; +} + +/* The Objective-C front-end often needs to determine the current scope. */ + +void * +objc_get_current_scope (void) +{ + return current_scope; +} + +/* The following function is used only by Objective-C. It needs to live here + because it accesses the innards of c_scope. */ + +void +objc_mark_locals_volatile (void *enclosing_blk) +{ + struct c_scope *scope; + struct c_binding *b; + + for (scope = current_scope; + scope && scope != enclosing_blk; + scope = scope->outer) + { + for (b = scope->bindings; b; b = b->prev) + objc_volatilize_decl (b->decl); + + /* Do not climb up past the current function. */ + if (scope->function_body) + break; + } +} + +/* Return true if we are in the global binding level. */ + +bool +global_bindings_p (void) +{ + return current_scope == file_scope; +} + +/* Return true if we're declaring parameters in an old-style function + declaration. */ + +bool +old_style_parameter_scope (void) +{ + /* If processing parameters and there is no function statement list, we + * have an old-style function declaration. */ + return (current_scope->parm_flag && !DECL_SAVED_TREE (current_function_decl)); +} + +void +keep_next_level (void) +{ + keep_next_level_flag = true; +} + +/* Set the flag for the FLOAT_CONST_DECIMAL64 pragma being ON. */ + +void +set_float_const_decimal64 (void) +{ + current_scope->float_const_decimal64 = true; +} + +/* Clear the flag for the FLOAT_CONST_DECIMAL64 pragma. */ + +void +clear_float_const_decimal64 (void) +{ + current_scope->float_const_decimal64 = false; +} + +/* Return nonzero if an unsuffixed float constant is _Decimal64. */ + +bool +float_const_decimal64_p (void) +{ + return current_scope->float_const_decimal64; +} + +/* Identify this scope as currently being filled with parameters. */ + +void +declare_parm_level (void) +{ + current_scope->parm_flag = true; +} + +void +push_scope (void) +{ + if (next_is_function_body) + { + /* This is the transition from the parameters to the top level + of the function body. These are the same scope + (C99 6.2.1p4,6) so we do not push another scope structure. + next_is_function_body is set only by store_parm_decls, which + in turn is called when and only when we are about to + encounter the opening curly brace for the function body. + + The outermost block of a function always gets a BLOCK node, + because the debugging output routines expect that each + function has at least one BLOCK. */ + current_scope->parm_flag = false; + current_scope->function_body = true; + current_scope->keep = true; + current_scope->outer_function = current_function_scope; + current_function_scope = current_scope; + + keep_next_level_flag = false; + next_is_function_body = false; + + /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes. */ + if (current_scope->outer) + current_scope->float_const_decimal64 + = current_scope->outer->float_const_decimal64; + else + current_scope->float_const_decimal64 = false; + } + else + { + struct c_scope *scope; + if (scope_freelist) + { + scope = scope_freelist; + scope_freelist = scope->outer; + } + else + scope = ggc_cleared_alloc (); + + /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes. */ + if (current_scope) + scope->float_const_decimal64 = current_scope->float_const_decimal64; + else + scope->float_const_decimal64 = false; + + scope->keep = keep_next_level_flag; + scope->outer = current_scope; + scope->depth = current_scope ? (current_scope->depth + 1) : 0; + + /* Check for scope depth overflow. Unlikely (2^28 == 268,435,456) but + possible. */ + if (current_scope && scope->depth == 0) + { + scope->depth--; + sorry ("GCC supports only %u nested scopes", scope->depth); + } + + current_scope = scope; + keep_next_level_flag = false; + } +} + +/* This is called when we are leaving SCOPE. For each label defined + in SCOPE, add any appropriate decls to its decls_in_scope fields. + These are the decls whose initialization will be skipped by a goto + later in the function. */ + +static void +update_label_decls (struct c_scope *scope) +{ + struct c_scope *s; + + s = scope; + while (s != NULL) + { + if (s->has_label_bindings) + { + struct c_binding *b; + + for (b = s->bindings; b != NULL; b = b->prev) + { + struct c_label_vars *label_vars; + struct c_binding *b1; + bool hjud; + unsigned int ix; + struct c_goto_bindings *g; + + if (TREE_CODE (b->decl) != LABEL_DECL) + continue; + label_vars = b->u.label; + + b1 = label_vars->label_bindings.bindings_in_scope; + if (label_vars->label_bindings.scope == NULL) + hjud = false; + else + hjud = label_vars->label_bindings.scope->has_jump_unsafe_decl; + if (update_spot_bindings (scope, &label_vars->label_bindings)) + { + /* This label is defined in this scope. */ + if (hjud) + { + for (; b1 != NULL; b1 = b1->prev) + { + /* A goto from later in the function to this + label will never see the initialization + of B1, if any. Save it to issue a + warning if needed. */ + if (decl_jump_unsafe (b1->decl)) + vec_safe_push(label_vars->decls_in_scope, b1->decl); + } + } + } + + /* Update the bindings of any goto statements associated + with this label. */ + FOR_EACH_VEC_SAFE_ELT (label_vars->gotos, ix, g) + update_spot_bindings (scope, &g->goto_bindings); + } + } + + /* Don't search beyond the current function. */ + if (s == current_function_scope) + break; + + s = s->outer; + } +} + +/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT. */ + +static void +set_type_context (tree type, tree context) +{ + for (type = TYPE_MAIN_VARIANT (type); type; + type = TYPE_NEXT_VARIANT (type)) + TYPE_CONTEXT (type) = context; +} + +/* Exit a scope. Restore the state of the identifier-decl mappings + that were in effect when this scope was entered. Return a BLOCK + node containing all the DECLs in this scope that are of interest + to debug info generation. */ + +tree +pop_scope (void) +{ + struct c_scope *scope = current_scope; + tree block, context, p; + struct c_binding *b; + + bool functionbody = scope->function_body; + bool keep = functionbody || scope->keep || scope->bindings; + + update_label_decls (scope); + + /* If appropriate, create a BLOCK to record the decls for the life + of this function. */ + block = NULL_TREE; + if (keep) + { + block = make_node (BLOCK); + BLOCK_SUBBLOCKS (block) = scope->blocks; + TREE_USED (block) = 1; + + /* In each subblock, record that this is its superior. */ + for (p = scope->blocks; p; p = BLOCK_CHAIN (p)) + BLOCK_SUPERCONTEXT (p) = block; + + BLOCK_VARS (block) = NULL_TREE; + } + + /* The TYPE_CONTEXTs for all of the tagged types belonging to this + scope must be set so that they point to the appropriate + construct, i.e. either to the current FUNCTION_DECL node, or + else to the BLOCK node we just constructed. + + Note that for tagged types whose scope is just the formal + parameter list for some function type specification, we can't + properly set their TYPE_CONTEXTs here, because we don't have a + pointer to the appropriate FUNCTION_TYPE node readily available + to us. For those cases, the TYPE_CONTEXTs of the relevant tagged + type nodes get set in `grokdeclarator' as soon as we have created + the FUNCTION_TYPE node which will represent the "scope" for these + "parameter list local" tagged types. */ + if (scope->function_body) + context = current_function_decl; + else if (scope == file_scope) + { + tree file_decl + = build_translation_unit_decl (get_identifier (main_input_filename)); + context = file_decl; + debug_hooks->register_main_translation_unit (file_decl); + } + else + context = block; + + /* Clear all bindings in this scope. */ + for (b = scope->bindings; b; b = free_binding_and_advance (b)) + { + p = b->decl; + switch (TREE_CODE (p)) + { + case LABEL_DECL: + /* Warnings for unused labels, errors for undefined labels. */ + if (TREE_USED (p) && !DECL_INITIAL (p)) + { + error ("label %q+D used but not defined", p); + DECL_INITIAL (p) = error_mark_node; + } + else + warn_for_unused_label (p); + + /* Labels go in BLOCK_VARS. */ + DECL_CHAIN (p) = BLOCK_VARS (block); + BLOCK_VARS (block) = p; + gcc_assert (I_LABEL_BINDING (b->id) == b); + I_LABEL_BINDING (b->id) = b->shadowed; + + /* Also pop back to the shadowed label_vars. */ + release_tree_vector (b->u.label->decls_in_scope); + b->u.label = b->u.label->shadowed; + break; + + case ENUMERAL_TYPE: + case UNION_TYPE: + case RECORD_TYPE: + set_type_context (p, context); + + /* Types may not have tag-names, in which case the type + appears in the bindings list with b->id NULL. */ + if (b->id) + { + gcc_assert (I_TAG_BINDING (b->id) == b); + I_TAG_BINDING (b->id) = b->shadowed; + } + break; + + case FUNCTION_DECL: + /* Propagate TREE_ADDRESSABLE from nested functions to their + containing functions. */ + if (!TREE_ASM_WRITTEN (p) + && DECL_INITIAL (p) != NULL_TREE + && TREE_ADDRESSABLE (p) + && DECL_ABSTRACT_ORIGIN (p) != NULL_TREE + && DECL_ABSTRACT_ORIGIN (p) != p) + TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (p)) = 1; + if (!TREE_PUBLIC (p) + && !DECL_INITIAL (p) + && !b->nested + && scope != file_scope + && scope != external_scope) + { + error ("nested function %q+D declared but never defined", p); + undef_nested_function = true; + } + else if (DECL_DECLARED_INLINE_P (p) + && TREE_PUBLIC (p) + && !DECL_INITIAL (p)) + { + /* C99 6.7.4p6: "a function with external linkage... declared + with an inline function specifier ... shall also be defined + in the same translation unit." */ + if (!flag_gnu89_inline + && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (p)) + && scope == external_scope) + pedwarn (input_location, 0, + "inline function %q+D declared but never defined", p); + DECL_EXTERNAL (p) = 1; + } + + goto common_symbol; + + case VAR_DECL: + /* Warnings for unused variables. */ + if ((!TREE_USED (p) || !DECL_READ_P (p)) + && !warning_suppressed_p (p, OPT_Wunused_but_set_variable) + && !DECL_IN_SYSTEM_HEADER (p) + && DECL_NAME (p) + && !DECL_ARTIFICIAL (p) + && scope != file_scope + && scope != external_scope) + { + if (!TREE_USED (p)) + warning (OPT_Wunused_variable, "unused variable %q+D", p); + else if (DECL_CONTEXT (p) == current_function_decl) + warning_at (DECL_SOURCE_LOCATION (p), + OPT_Wunused_but_set_variable, + "variable %qD set but not used", p); + } + + if (b->inner_comp) + { + error ("type of array %q+D completed incompatibly with" + " implicit initialization", p); + } + + /* Fall through. */ + case TYPE_DECL: + case CONST_DECL: + common_symbol: + /* All of these go in BLOCK_VARS, but only if this is the + binding in the home scope. */ + if (!b->nested) + { + DECL_CHAIN (p) = BLOCK_VARS (block); + BLOCK_VARS (block) = p; + } + else if (VAR_OR_FUNCTION_DECL_P (p) && scope != file_scope) + { + /* For block local externs add a special + DECL_EXTERNAL decl for debug info generation. */ + tree extp = copy_node (p); + + DECL_EXTERNAL (extp) = 1; + TREE_STATIC (extp) = 0; + TREE_PUBLIC (extp) = 1; + DECL_INITIAL (extp) = NULL_TREE; + DECL_LANG_SPECIFIC (extp) = NULL; + DECL_CONTEXT (extp) = current_function_decl; + if (TREE_CODE (p) == FUNCTION_DECL) + { + DECL_RESULT (extp) = NULL_TREE; + DECL_SAVED_TREE (extp) = NULL_TREE; + DECL_STRUCT_FUNCTION (extp) = NULL; + } + if (b->locus != UNKNOWN_LOCATION) + DECL_SOURCE_LOCATION (extp) = b->locus; + DECL_CHAIN (extp) = BLOCK_VARS (block); + BLOCK_VARS (block) = extp; + } + /* If this is the file scope set DECL_CONTEXT of each decl to + the TRANSLATION_UNIT_DECL. This makes same_translation_unit_p + work. */ + if (scope == file_scope) + { + DECL_CONTEXT (p) = context; + if (TREE_CODE (p) == TYPE_DECL + && TREE_TYPE (p) != error_mark_node) + set_type_context (TREE_TYPE (p), context); + } + + gcc_fallthrough (); + /* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have + already been put there by store_parm_decls. Unused- + parameter warnings are handled by function.c. + error_mark_node obviously does not go in BLOCK_VARS and + does not get unused-variable warnings. */ + case PARM_DECL: + case ERROR_MARK: + /* It is possible for a decl not to have a name. We get + here with b->id NULL in this case. */ + if (b->id) + { + gcc_assert (I_SYMBOL_BINDING (b->id) == b); + I_SYMBOL_BINDING (b->id) = b->shadowed; + if (b->shadowed && b->shadowed->u.type) + TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type; + } + break; + + default: + gcc_unreachable (); + } + } + + + /* Dispose of the block that we just made inside some higher level. */ + if ((scope->function_body || scope == file_scope) && context) + { + DECL_INITIAL (context) = block; + BLOCK_SUPERCONTEXT (block) = context; + } + else if (scope->outer) + { + if (block) + SCOPE_LIST_APPEND (scope->outer, blocks, block); + /* If we did not make a block for the scope just exited, any + blocks made for inner scopes must be carried forward so they + will later become subblocks of something else. */ + else if (scope->blocks) + SCOPE_LIST_CONCAT (scope->outer, blocks, scope, blocks); + } + + /* Pop the current scope, and free the structure for reuse. */ + current_scope = scope->outer; + if (scope->function_body) + current_function_scope = scope->outer_function; + + memset (scope, 0, sizeof (struct c_scope)); + scope->outer = scope_freelist; + scope_freelist = scope; + + return block; +} + +void +push_file_scope (void) +{ + tree decl; + + if (file_scope) + return; + + push_scope (); + file_scope = current_scope; + + start_fname_decls (); + + for (decl = visible_builtins; decl; decl = DECL_CHAIN (decl)) + bind (DECL_NAME (decl), decl, file_scope, + /*invisible=*/false, /*nested=*/true, DECL_SOURCE_LOCATION (decl)); +} + +void +pop_file_scope (void) +{ + /* In case there were missing closebraces, get us back to the global + binding level. */ + while (current_scope != file_scope) + pop_scope (); + + /* __FUNCTION__ is defined at file scope (""). This + call may not be necessary as my tests indicate it + still works without it. */ + finish_fname_decls (); + + check_inline_statics (); + + /* This is the point to write out a PCH if we're doing that. + In that case we do not want to do anything else. */ + if (pch_file) + { + c_common_write_pch (); + /* Ensure even the callers don't try to finalize the CU. */ + flag_syntax_only = 1; + return; + } + + /* Pop off the file scope and close this translation unit. */ + pop_scope (); + file_scope = 0; + + maybe_apply_pending_pragma_weaks (); +} + +/* Adjust the bindings for the start of a statement expression. */ + +void +c_bindings_start_stmt_expr (struct c_spot_bindings* switch_bindings) +{ + struct c_scope *scope; + + for (scope = current_scope; scope != NULL; scope = scope->outer) + { + struct c_binding *b; + + if (!scope->has_label_bindings) + continue; + + for (b = scope->bindings; b != NULL; b = b->prev) + { + struct c_label_vars *label_vars; + unsigned int ix; + struct c_goto_bindings *g; + + if (TREE_CODE (b->decl) != LABEL_DECL) + continue; + label_vars = b->u.label; + ++label_vars->label_bindings.stmt_exprs; + FOR_EACH_VEC_SAFE_ELT (label_vars->gotos, ix, g) + ++g->goto_bindings.stmt_exprs; + } + } + + if (switch_bindings != NULL) + ++switch_bindings->stmt_exprs; +} + +/* Adjust the bindings for the end of a statement expression. */ + +void +c_bindings_end_stmt_expr (struct c_spot_bindings *switch_bindings) +{ + struct c_scope *scope; + + for (scope = current_scope; scope != NULL; scope = scope->outer) + { + struct c_binding *b; + + if (!scope->has_label_bindings) + continue; + + for (b = scope->bindings; b != NULL; b = b->prev) + { + struct c_label_vars *label_vars; + unsigned int ix; + struct c_goto_bindings *g; + + if (TREE_CODE (b->decl) != LABEL_DECL) + continue; + label_vars = b->u.label; + --label_vars->label_bindings.stmt_exprs; + if (label_vars->label_bindings.stmt_exprs < 0) + { + label_vars->label_bindings.left_stmt_expr = true; + label_vars->label_bindings.stmt_exprs = 0; + } + FOR_EACH_VEC_SAFE_ELT (label_vars->gotos, ix, g) + { + --g->goto_bindings.stmt_exprs; + if (g->goto_bindings.stmt_exprs < 0) + { + g->goto_bindings.left_stmt_expr = true; + g->goto_bindings.stmt_exprs = 0; + } + } + } + } + + if (switch_bindings != NULL) + { + --switch_bindings->stmt_exprs; + gcc_assert (switch_bindings->stmt_exprs >= 0); + } +} + +/* Push a definition or a declaration of struct, union or enum tag "name". + "type" should be the type node. + We assume that the tag "name" is not already defined, and has a location + of LOC. + + Note that the definition may really be just a forward reference. + In that case, the TYPE_SIZE will be zero. */ + +static void +pushtag (location_t loc, tree name, tree type) +{ + /* Record the identifier as the type's name if it has none. */ + if (name && !TYPE_NAME (type)) + TYPE_NAME (type) = name; + bind (name, type, current_scope, /*invisible=*/false, /*nested=*/false, loc); + + /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE will be the + tagged type we just added to the current scope. This fake + NULL-named TYPE_DECL node helps dwarfout.c to know when it needs + to output a representation of a tagged type, and it also gives + us a convenient place to record the "scope start" address for the + tagged type. */ + + TYPE_STUB_DECL (type) = pushdecl (build_decl (loc, + TYPE_DECL, NULL_TREE, type)); + + /* An approximation for now, so we can tell this is a function-scope tag. + This will be updated in pop_scope. */ + TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type)); + + if (warn_cxx_compat && name != NULL_TREE) + { + struct c_binding *b = I_SYMBOL_BINDING (name); + + if (b != NULL + && b->decl != NULL_TREE + && TREE_CODE (b->decl) == TYPE_DECL + && (B_IN_CURRENT_SCOPE (b) + || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) + && (TYPE_MAIN_VARIANT (TREE_TYPE (b->decl)) + != TYPE_MAIN_VARIANT (type))) + { + auto_diagnostic_group d; + if (warning_at (loc, OPT_Wc___compat, + ("using %qD as both a typedef and a tag is " + "invalid in C++"), b->decl) + && b->locus != UNKNOWN_LOCATION) + inform (b->locus, "originally defined here"); + } + } +} + +/* An exported interface to pushtag. This is used by the gdb plugin's + binding oracle to introduce a new tag binding. */ + +void +c_pushtag (location_t loc, tree name, tree type) +{ + pushtag (loc, name, type); +} + +/* An exported interface to bind a declaration. LOC is the location + to use. DECL is the declaration to bind. The decl's name is used + to determine how it is bound. If DECL is a VAR_DECL, then + IS_GLOBAL determines whether the decl is put into the global (file + and external) scope or the current function's scope; if DECL is not + a VAR_DECL then it is always put into the file scope. */ + +void +c_bind (location_t loc, tree decl, bool is_global) +{ + struct c_scope *scope; + bool nested = false; + + if (!VAR_P (decl) || current_function_scope == NULL) + { + /* Types and functions are always considered to be global. */ + scope = file_scope; + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + } + else if (is_global) + { + /* Also bind it into the external scope. */ + bind (DECL_NAME (decl), decl, external_scope, true, false, loc); + nested = true; + scope = file_scope; + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + } + else + { + DECL_CONTEXT (decl) = current_function_decl; + TREE_PUBLIC (decl) = 0; + scope = current_function_scope; + } + + bind (DECL_NAME (decl), decl, scope, false, nested, loc); +} + + +/* Stores the first FILE*, const struct tm* etc. argument type (whatever + it is) seen in a declaration of a file I/O etc. built-in, corresponding + to the builtin_structptr_types array. Subsequent declarations of such + built-ins are expected to refer to it rather than to fileptr_type_node, + etc. which is just void* (or to any other type). + Used only by match_builtin_function_types. */ + +static const unsigned builtin_structptr_type_count + = sizeof builtin_structptr_types / sizeof builtin_structptr_types[0]; + +static GTY(()) tree last_structptr_types[builtin_structptr_type_count]; + +/* Returns true if types T1 and T2 representing return types or types + of function arguments are close enough to be considered interchangeable + in redeclarations of built-in functions. */ + +static bool +types_close_enough_to_match (tree t1, tree t2) +{ + return (TYPE_MODE (t1) == TYPE_MODE (t2) + && POINTER_TYPE_P (t1) == POINTER_TYPE_P (t2) + && FUNCTION_POINTER_TYPE_P (t1) == FUNCTION_POINTER_TYPE_P (t2)); +} + +/* Subroutine of compare_decls. Allow harmless mismatches in return + and argument types provided that the type modes match. Set *STRICT + and *ARGNO to the expected argument type and number in case of + an argument type mismatch or null and zero otherwise. Return + a unified type given a suitable match, and 0 otherwise. */ + +static tree +match_builtin_function_types (tree newtype, tree oldtype, + tree *strict, unsigned *argno) +{ + *argno = 0; + *strict = NULL_TREE; + + /* Accept the return type of the new declaration if it has the same + mode and if they're both pointers or if neither is. */ + tree oldrettype = TREE_TYPE (oldtype); + tree newrettype = TREE_TYPE (newtype); + + if (!types_close_enough_to_match (oldrettype, newrettype)) + return NULL_TREE; + + /* Check that the return types are compatible but don't fail if they + are not (e.g., int vs long in ILP32) and just let the caller know. */ + if (!comptypes (TYPE_MAIN_VARIANT (oldrettype), + TYPE_MAIN_VARIANT (newrettype))) + *strict = oldrettype; + + tree oldargs = TYPE_ARG_TYPES (oldtype); + tree newargs = TYPE_ARG_TYPES (newtype); + tree tryargs = newargs; + + const unsigned nlst + = sizeof last_structptr_types / sizeof last_structptr_types[0]; + const unsigned nbst + = sizeof builtin_structptr_types / sizeof builtin_structptr_types[0]; + + gcc_checking_assert (nlst == nbst); + + for (unsigned i = 1; oldargs || newargs; ++i) + { + if (!oldargs + || !newargs + || !TREE_VALUE (oldargs) + || !TREE_VALUE (newargs)) + return NULL_TREE; + + tree oldtype = TYPE_MAIN_VARIANT (TREE_VALUE (oldargs)); + tree newtype = TREE_VALUE (newargs); + if (newtype == error_mark_node) + return NULL_TREE; + newtype = TYPE_MAIN_VARIANT (newtype); + + if (!types_close_enough_to_match (oldtype, newtype)) + return NULL_TREE; + + unsigned j = nbst; + if (POINTER_TYPE_P (oldtype)) + /* Iterate over well-known struct types like FILE (whose types + aren't known to us) and compare the pointer to each to + the pointer argument. */ + for (j = 0; j < nbst; ++j) + { + if (TREE_VALUE (oldargs) != builtin_structptr_types[j].node) + continue; + /* Store the first FILE* etc. argument type (whatever it is), and + expect any subsequent declarations of file I/O etc. built-ins + to refer to it rather than to fileptr_type_node etc. which is + just void* (or const void*). */ + if (last_structptr_types[j]) + { + if (!comptypes (last_structptr_types[j], newtype)) + { + *argno = i; + *strict = last_structptr_types[j]; + } + } + else + last_structptr_types[j] = newtype; + break; + } + + if (j == nbst && !comptypes (oldtype, newtype)) + { + if (POINTER_TYPE_P (oldtype)) + { + /* For incompatible pointers, only reject differences in + the unqualified variants of the referenced types but + consider differences in qualifiers as benign (report + those to caller via *STRICT below). */ + tree oldref = TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)); + tree newref = TYPE_MAIN_VARIANT (TREE_TYPE (newtype)); + if (!comptypes (oldref, newref)) + return NULL_TREE; + } + + if (!*strict) + { + *argno = i; + *strict = oldtype; + } + } + + oldargs = TREE_CHAIN (oldargs); + newargs = TREE_CHAIN (newargs); + } + + tree trytype = build_function_type (newrettype, tryargs); + + /* Allow declaration to change transaction_safe attribute. */ + tree oldattrs = TYPE_ATTRIBUTES (oldtype); + tree oldtsafe = lookup_attribute ("transaction_safe", oldattrs); + tree newattrs = TYPE_ATTRIBUTES (newtype); + tree newtsafe = lookup_attribute ("transaction_safe", newattrs); + if (oldtsafe && !newtsafe) + oldattrs = remove_attribute ("transaction_safe", oldattrs); + else if (newtsafe && !oldtsafe) + oldattrs = tree_cons (get_identifier ("transaction_safe"), + NULL_TREE, oldattrs); + + return build_type_attribute_variant (trytype, oldattrs); +} + +/* Subroutine of diagnose_mismatched_decls. Check for function type + mismatch involving an empty arglist vs a nonempty one and give clearer + diagnostics. */ +static void +diagnose_arglist_conflict (tree newdecl, tree olddecl, + tree newtype, tree oldtype) +{ + tree t; + + if (TREE_CODE (olddecl) != FUNCTION_DECL + || !comptypes (TREE_TYPE (oldtype), TREE_TYPE (newtype)) + || !((!prototype_p (oldtype) && DECL_INITIAL (olddecl) == NULL_TREE) + || (!prototype_p (newtype) && DECL_INITIAL (newdecl) == NULL_TREE))) + return; + + t = TYPE_ARG_TYPES (oldtype); + if (t == NULL_TREE) + t = TYPE_ARG_TYPES (newtype); + for (; t; t = TREE_CHAIN (t)) + { + tree type = TREE_VALUE (t); + + if (TREE_CHAIN (t) == NULL_TREE + && TYPE_MAIN_VARIANT (type) != void_type_node) + { + inform (input_location, "a parameter list with an ellipsis " + "cannot match an empty parameter name list declaration"); + break; + } + + if (c_type_promotes_to (type) != type) + { + inform (input_location, "an argument type that has a default " + "promotion cannot match an empty parameter name list " + "declaration"); + break; + } + } +} + +/* Another subroutine of diagnose_mismatched_decls. OLDDECL is an + old-style function definition, NEWDECL is a prototype declaration. + Diagnose inconsistencies in the argument list. Returns TRUE if + the prototype is compatible, FALSE if not. */ +static bool +validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype) +{ + tree newargs, oldargs; + int i; + +#define END_OF_ARGLIST(t) ((t) == void_type_node) + + oldargs = TYPE_ACTUAL_ARG_TYPES (oldtype); + newargs = TYPE_ARG_TYPES (newtype); + i = 1; + + for (;;) + { + tree oldargtype = TREE_VALUE (oldargs); + tree newargtype = TREE_VALUE (newargs); + + if (oldargtype == error_mark_node || newargtype == error_mark_node) + return false; + + oldargtype = (TYPE_ATOMIC (oldargtype) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (oldargtype), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (oldargtype)); + newargtype = (TYPE_ATOMIC (newargtype) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (newargtype), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (newargtype)); + + if (END_OF_ARGLIST (oldargtype) && END_OF_ARGLIST (newargtype)) + break; + + /* Reaching the end of just one list means the two decls don't + agree on the number of arguments. */ + if (END_OF_ARGLIST (oldargtype)) + { + error ("prototype for %q+D declares more arguments " + "than previous old-style definition", newdecl); + return false; + } + else if (END_OF_ARGLIST (newargtype)) + { + error ("prototype for %q+D declares fewer arguments " + "than previous old-style definition", newdecl); + return false; + } + + /* Type for passing arg must be consistent with that declared + for the arg. */ + else if (!comptypes (oldargtype, newargtype)) + { + error ("prototype for %q+D declares argument %d" + " with incompatible type", + newdecl, i); + return false; + } + + oldargs = TREE_CHAIN (oldargs); + newargs = TREE_CHAIN (newargs); + i++; + } + + /* If we get here, no errors were found, but do issue a warning + for this poor-style construct. */ + warning (0, "prototype for %q+D follows non-prototype definition", + newdecl); + return true; +#undef END_OF_ARGLIST +} + +/* Subroutine of diagnose_mismatched_decls. Report the location of DECL, + first in a pair of mismatched declarations, using the diagnostic + function DIAG. */ +static void +locate_old_decl (tree decl) +{ + if (TREE_CODE (decl) == FUNCTION_DECL + && fndecl_built_in_p (decl) + && !C_DECL_DECLARED_BUILTIN (decl)) + ; + else if (DECL_INITIAL (decl)) + inform (input_location, + "previous definition of %q+D with type %qT", + decl, TREE_TYPE (decl)); + else if (C_DECL_IMPLICIT (decl)) + inform (input_location, + "previous implicit declaration of %q+D with type %qT", + decl, TREE_TYPE (decl)); + else + inform (input_location, + "previous declaration of %q+D with type %qT", + decl, TREE_TYPE (decl)); +} + +/* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL. + Returns true if the caller should proceed to merge the two, false + if OLDDECL should simply be discarded. As a side effect, issues + all necessary diagnostics for invalid or poor-style combinations. + If it returns true, writes the types of NEWDECL and OLDDECL to + *NEWTYPEP and *OLDTYPEP - these may have been adjusted from + TREE_TYPE (NEWDECL, OLDDECL) respectively. */ + +static bool +diagnose_mismatched_decls (tree newdecl, tree olddecl, + tree *newtypep, tree *oldtypep) +{ + tree newtype, oldtype; + bool retval = true; + +#define DECL_EXTERN_INLINE(DECL) (DECL_DECLARED_INLINE_P (DECL) \ + && DECL_EXTERNAL (DECL)) + + /* If we have error_mark_node for either decl or type, just discard + the previous decl - we're in an error cascade already. */ + if (olddecl == error_mark_node || newdecl == error_mark_node) + return false; + *oldtypep = oldtype = TREE_TYPE (olddecl); + *newtypep = newtype = TREE_TYPE (newdecl); + if (oldtype == error_mark_node || newtype == error_mark_node) + return false; + + /* Two different categories of symbol altogether. This is an error + unless OLDDECL is a builtin. OLDDECL will be discarded in any case. */ + if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) + { + if (!(TREE_CODE (olddecl) == FUNCTION_DECL + && fndecl_built_in_p (olddecl) + && !C_DECL_DECLARED_BUILTIN (olddecl))) + { + auto_diagnostic_group d; + error ("%q+D redeclared as different kind of symbol", newdecl); + locate_old_decl (olddecl); + } + else if (TREE_PUBLIC (newdecl)) + warning (OPT_Wbuiltin_declaration_mismatch, + "built-in function %q+D declared as non-function", + newdecl); + else + warning (OPT_Wshadow, "declaration of %q+D shadows " + "a built-in function", newdecl); + return false; + } + + /* Enumerators have no linkage, so may only be declared once in a + given scope. */ + if (TREE_CODE (olddecl) == CONST_DECL) + { + auto_diagnostic_group d; + error ("redeclaration of enumerator %q+D", newdecl); + locate_old_decl (olddecl); + return false; + } + + bool pedwarned = false; + bool warned = false; + auto_diagnostic_group d; + + if (!comptypes (oldtype, newtype)) + { + if (TREE_CODE (olddecl) == FUNCTION_DECL + && fndecl_built_in_p (olddecl, BUILT_IN_NORMAL) + && !C_DECL_DECLARED_BUILTIN (olddecl)) + { + /* Accept "harmless" mismatches in function types such + as missing qualifiers or int vs long when they're the same + size. However, diagnose return and argument types that are + incompatible according to language rules. */ + tree mismatch_expect; + unsigned mismatch_argno; + + tree trytype = match_builtin_function_types (newtype, oldtype, + &mismatch_expect, + &mismatch_argno); + + if (trytype && comptypes (newtype, trytype)) + *oldtypep = oldtype = trytype; + else + { + /* If types don't match for a built-in, throw away the + built-in. No point in calling locate_old_decl here, it + won't print anything. */ + const char *header = header_for_builtin_fn (olddecl); + location_t loc = DECL_SOURCE_LOCATION (newdecl); + if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch, + "conflicting types for built-in function %q+D; " + "expected %qT", + newdecl, oldtype) + && header) + { + /* Suggest the right header to include as the preferred + solution rather than the spelling of the declaration. */ + rich_location richloc (line_table, loc); + maybe_add_include_fixit (&richloc, header, true); + inform (&richloc, + "%qD is declared in header %qs", olddecl, header); + } + return false; + } + + if (mismatch_expect && extra_warnings) + { + location_t newloc = DECL_SOURCE_LOCATION (newdecl); + bool warned = false; + if (mismatch_argno) + warned = warning_at (newloc, OPT_Wbuiltin_declaration_mismatch, + "mismatch in argument %u type of built-in " + "function %qD; expected %qT", + mismatch_argno, newdecl, mismatch_expect); + else + warned = warning_at (newloc, OPT_Wbuiltin_declaration_mismatch, + "mismatch in return type of built-in " + "function %qD; expected %qT", + newdecl, mismatch_expect); + const char *header = header_for_builtin_fn (olddecl); + if (warned && header) + { + rich_location richloc (line_table, newloc); + maybe_add_include_fixit (&richloc, header, true); + inform (&richloc, + "%qD is declared in header %qs", olddecl, header); + } + } + } + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_IS_UNDECLARED_BUILTIN (olddecl)) + { + /* A conflicting function declaration for a predeclared + function that isn't actually built in. Objective C uses + these. The new declaration silently overrides everything + but the volatility (i.e. noreturn) indication. See also + below. FIXME: Make Objective C use normal builtins. */ + TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); + return false; + } + /* Permit void foo (...) to match int foo (...) if the latter is + the definition and implicit int was used. See + c-torture/compile/920625-2.c. */ + else if (TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) + && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node + && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node + && C_FUNCTION_IMPLICIT_INT (newdecl) && !DECL_INITIAL (olddecl)) + { + pedwarned = pedwarn (input_location, 0, + "conflicting types for %q+D", newdecl); + /* Make sure we keep void as the return type. */ + TREE_TYPE (newdecl) = *newtypep = newtype = oldtype; + C_FUNCTION_IMPLICIT_INT (newdecl) = 0; + } + /* Permit void foo (...) to match an earlier call to foo (...) with + no declared type (thus, implicitly int). */ + else if (TREE_CODE (newdecl) == FUNCTION_DECL + && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == void_type_node + && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == integer_type_node + && C_DECL_IMPLICIT (olddecl) && !DECL_INITIAL (olddecl)) + { + pedwarned = pedwarn (input_location, 0, + "conflicting types for %q+D; have %qT", + newdecl, newtype); + /* Make sure we keep void as the return type. */ + TREE_TYPE (olddecl) = *oldtypep = oldtype = newtype; + } + else + { + int new_quals = TYPE_QUALS (newtype); + int old_quals = TYPE_QUALS (oldtype); + + if (new_quals != old_quals) + { + addr_space_t new_addr = DECODE_QUAL_ADDR_SPACE (new_quals); + addr_space_t old_addr = DECODE_QUAL_ADDR_SPACE (old_quals); + if (new_addr != old_addr) + { + if (ADDR_SPACE_GENERIC_P (new_addr)) + error ("conflicting named address spaces (generic vs %s) " + "for %q+D", + c_addr_space_name (old_addr), newdecl); + else if (ADDR_SPACE_GENERIC_P (old_addr)) + error ("conflicting named address spaces (%s vs generic) " + "for %q+D", + c_addr_space_name (new_addr), newdecl); + else + error ("conflicting named address spaces (%s vs %s) " + "for %q+D", + c_addr_space_name (new_addr), + c_addr_space_name (old_addr), + newdecl); + } + + if (CLEAR_QUAL_ADDR_SPACE (new_quals) + != CLEAR_QUAL_ADDR_SPACE (old_quals)) + error ("conflicting type qualifiers for %q+D", newdecl); + } + else + error ("conflicting types for %q+D; have %qT", newdecl, newtype); + diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype); + locate_old_decl (olddecl); + return false; + } + } + + /* Redeclaration of a type is a constraint violation (6.7.2.3p1), + but silently ignore the redeclaration if either is in a system + header. (Conflicting redeclarations were handled above.) This + is allowed for C11 if the types are the same, not just + compatible. */ + if (TREE_CODE (newdecl) == TYPE_DECL) + { + bool types_different = false; + int comptypes_result; + + comptypes_result + = comptypes_check_different_types (oldtype, newtype, &types_different); + + if (comptypes_result != 1 || types_different) + { + error ("redefinition of typedef %q+D with different type", newdecl); + locate_old_decl (olddecl); + return false; + } + + if (DECL_IN_SYSTEM_HEADER (newdecl) + || DECL_IN_SYSTEM_HEADER (olddecl) + || warning_suppressed_p (newdecl, OPT_Wpedantic) + || warning_suppressed_p (olddecl, OPT_Wpedantic)) + return true; /* Allow OLDDECL to continue in use. */ + + if (variably_modified_type_p (newtype, NULL)) + { + error ("redefinition of typedef %q+D with variably modified type", + newdecl); + locate_old_decl (olddecl); + } + else if (pedwarn_c99 (input_location, OPT_Wpedantic, + "redefinition of typedef %q+D", newdecl)) + locate_old_decl (olddecl); + + return true; + } + + /* Function declarations can either be 'static' or 'extern' (no + qualifier is equivalent to 'extern' - C99 6.2.2p5) and therefore + can never conflict with each other on account of linkage + (6.2.2p4). Multiple definitions are not allowed (6.9p3,5) but + gnu89 mode permits two definitions if one is 'extern inline' and + one is not. The non- extern-inline definition supersedes the + extern-inline definition. */ + + else if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* If you declare a built-in function name as static, or + define the built-in with an old-style definition (so we + can't validate the argument list) the built-in definition is + overridden, but optionally warn this was a bad choice of name. */ + if (fndecl_built_in_p (olddecl) + && !C_DECL_DECLARED_BUILTIN (olddecl)) + { + if (!TREE_PUBLIC (newdecl) + || (DECL_INITIAL (newdecl) + && !prototype_p (TREE_TYPE (newdecl)))) + { + warning_at (DECL_SOURCE_LOCATION (newdecl), + OPT_Wshadow, "declaration of %qD shadows " + "a built-in function", newdecl); + /* Discard the old built-in function. */ + return false; + } + + if (!prototype_p (TREE_TYPE (newdecl))) + { + /* Set for built-ins that take no arguments. */ + bool func_void_args = false; + if (tree at = TYPE_ARG_TYPES (oldtype)) + func_void_args = VOID_TYPE_P (TREE_VALUE (at)); + + if (extra_warnings && !func_void_args) + warning_at (DECL_SOURCE_LOCATION (newdecl), + OPT_Wbuiltin_declaration_mismatch, + "declaration of built-in function %qD without " + "a prototype; expected %qT", + newdecl, TREE_TYPE (olddecl)); + } + } + + if (DECL_INITIAL (newdecl)) + { + if (DECL_INITIAL (olddecl)) + { + /* If both decls are in the same TU and the new declaration + isn't overriding an extern inline reject the new decl. + In c99, no overriding is allowed in the same translation + unit. */ + if ((!DECL_EXTERN_INLINE (olddecl) + || DECL_EXTERN_INLINE (newdecl) + || (!flag_gnu89_inline + && (!DECL_DECLARED_INLINE_P (olddecl) + || !lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (olddecl))) + && (!DECL_DECLARED_INLINE_P (newdecl) + || !lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (newdecl)))) + ) + && same_translation_unit_p (newdecl, olddecl)) + { + auto_diagnostic_group d; + error ("redefinition of %q+D", newdecl); + locate_old_decl (olddecl); + return false; + } + } + } + /* If we have a prototype after an old-style function definition, + the argument types must be checked specially. */ + else if (DECL_INITIAL (olddecl) + && !prototype_p (oldtype) && prototype_p (newtype) + && TYPE_ACTUAL_ARG_TYPES (oldtype)) + { + auto_diagnostic_group d; + if (!validate_proto_after_old_defn (newdecl, newtype, oldtype)) + { + locate_old_decl (olddecl); + return false; + } + } + /* A non-static declaration (even an "extern") followed by a + static declaration is undefined behavior per C99 6.2.2p3-5,7. + The same is true for a static forward declaration at block + scope followed by a non-static declaration/definition at file + scope. Static followed by non-static at the same scope is + not undefined behavior, and is the most convenient way to get + some effects (see e.g. what unwind-dw2-fde-glibc.c does to + the definition of _Unwind_Find_FDE in unwind-dw2-fde.c), but + we do diagnose it if -Wtraditional. */ + if (TREE_PUBLIC (olddecl) && !TREE_PUBLIC (newdecl)) + { + /* Two exceptions to the rule. If olddecl is an extern + inline, or a predeclared function that isn't actually + built in, newdecl silently overrides olddecl. The latter + occur only in Objective C; see also above. (FIXME: Make + Objective C use normal builtins.) */ + if (!DECL_IS_UNDECLARED_BUILTIN (olddecl) + && !DECL_EXTERN_INLINE (olddecl)) + { + auto_diagnostic_group d; + error ("static declaration of %q+D follows " + "non-static declaration", newdecl); + locate_old_decl (olddecl); + } + return false; + } + else if (TREE_PUBLIC (newdecl) && !TREE_PUBLIC (olddecl)) + { + if (DECL_CONTEXT (olddecl)) + { + auto_diagnostic_group d; + error ("non-static declaration of %q+D follows " + "static declaration", newdecl); + locate_old_decl (olddecl); + return false; + } + else if (warn_traditional) + { + warned |= warning (OPT_Wtraditional, + "non-static declaration of %q+D " + "follows static declaration", newdecl); + } + } + + /* Make sure gnu_inline attribute is either not present, or + present on all inline decls. */ + if (DECL_DECLARED_INLINE_P (olddecl) + && DECL_DECLARED_INLINE_P (newdecl)) + { + bool newa = lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (newdecl)) != NULL; + bool olda = lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (olddecl)) != NULL; + if (newa != olda) + { + auto_diagnostic_group d; + error_at (input_location, "% attribute present on %q+D", + newa ? newdecl : olddecl); + error_at (DECL_SOURCE_LOCATION (newa ? olddecl : newdecl), + "but not here"); + } + } + } + else if (VAR_P (newdecl)) + { + /* Only variables can be thread-local, and all declarations must + agree on this property. */ + if (C_DECL_THREADPRIVATE_P (olddecl) && !DECL_THREAD_LOCAL_P (newdecl)) + { + /* Nothing to check. Since OLDDECL is marked threadprivate + and NEWDECL does not have a thread-local attribute, we + will merge the threadprivate attribute into NEWDECL. */ + ; + } + else if (DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl)) + { + auto_diagnostic_group d; + if (DECL_THREAD_LOCAL_P (newdecl)) + error ("thread-local declaration of %q+D follows " + "non-thread-local declaration", newdecl); + else + error ("non-thread-local declaration of %q+D follows " + "thread-local declaration", newdecl); + + locate_old_decl (olddecl); + return false; + } + + /* Multiple initialized definitions are not allowed (6.9p3,5). */ + if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl)) + { + auto_diagnostic_group d; + error ("redefinition of %q+D", newdecl); + locate_old_decl (olddecl); + return false; + } + + /* Objects declared at file scope: if the first declaration had + external linkage (even if it was an external reference) the + second must have external linkage as well, or the behavior is + undefined. If the first declaration had internal linkage, then + the second must too, or else be an external reference (in which + case the composite declaration still has internal linkage). + As for function declarations, we warn about the static-then- + extern case only for -Wtraditional. See generally 6.2.2p3-5,7. */ + if (DECL_FILE_SCOPE_P (newdecl) + && TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl)) + { + if (DECL_EXTERNAL (newdecl)) + { + if (!DECL_FILE_SCOPE_P (olddecl)) + { + auto_diagnostic_group d; + error ("extern declaration of %q+D follows " + "declaration with no linkage", newdecl); + locate_old_decl (olddecl); + return false; + } + else if (warn_traditional) + { + warned |= warning (OPT_Wtraditional, + "non-static declaration of %q+D " + "follows static declaration", newdecl); + } + } + else + { + auto_diagnostic_group d; + if (TREE_PUBLIC (newdecl)) + error ("non-static declaration of %q+D follows " + "static declaration", newdecl); + else + error ("static declaration of %q+D follows " + "non-static declaration", newdecl); + + locate_old_decl (olddecl); + return false; + } + } + /* Two objects with the same name declared at the same block + scope must both be external references (6.7p3). */ + else if (!DECL_FILE_SCOPE_P (newdecl)) + { + if (DECL_EXTERNAL (newdecl)) + { + /* Extern with initializer at block scope, which will + already have received an error. */ + } + else if (DECL_EXTERNAL (olddecl)) + { + auto_diagnostic_group d; + error ("declaration of %q+D with no linkage follows " + "extern declaration", newdecl); + locate_old_decl (olddecl); + } + else + { + auto_diagnostic_group d; + error ("redeclaration of %q+D with no linkage", newdecl); + locate_old_decl (olddecl); + } + + return false; + } + + /* C++ does not permit a decl to appear multiple times at file + scope. */ + if (warn_cxx_compat + && DECL_FILE_SCOPE_P (newdecl) + && !DECL_EXTERNAL (newdecl) + && !DECL_EXTERNAL (olddecl)) + warned |= warning_at (DECL_SOURCE_LOCATION (newdecl), + OPT_Wc___compat, + ("duplicate declaration of %qD is " + "invalid in C++"), + newdecl); + } + + /* warnings */ + /* All decls must agree on a visibility. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (newdecl), TS_DECL_WITH_VIS) + && DECL_VISIBILITY_SPECIFIED (newdecl) && DECL_VISIBILITY_SPECIFIED (olddecl) + && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) + { + warned |= warning (0, "redeclaration of %q+D with different visibility " + "(old visibility preserved)", newdecl); + } + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + warned |= diagnose_mismatched_attributes (olddecl, newdecl); + else /* PARM_DECL, VAR_DECL */ + { + /* Redeclaration of a parameter is a constraint violation (this is + not explicitly stated, but follows from C99 6.7p3 [no more than + one declaration of the same identifier with no linkage in the + same scope, except type tags] and 6.2.2p6 [parameters have no + linkage]). We must check for a forward parameter declaration, + indicated by TREE_ASM_WRITTEN on the old declaration - this is + an extension, the mandatory diagnostic for which is handled by + mark_forward_parm_decls. */ + + if (TREE_CODE (newdecl) == PARM_DECL + && (!TREE_ASM_WRITTEN (olddecl) || TREE_ASM_WRITTEN (newdecl))) + { + auto_diagnostic_group d; + error ("redefinition of parameter %q+D", newdecl); + locate_old_decl (olddecl); + return false; + } + } + + /* Optional warning for completely redundant decls. */ + if (!warned && !pedwarned + && warn_redundant_decls + /* Don't warn about a function declaration followed by a + definition. */ + && !(TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl)) + /* Don't warn about redundant redeclarations of builtins. */ + && !(TREE_CODE (newdecl) == FUNCTION_DECL + && !fndecl_built_in_p (newdecl) + && fndecl_built_in_p (olddecl) + && !C_DECL_DECLARED_BUILTIN (olddecl)) + /* Don't warn about an extern followed by a definition. */ + && !(DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl)) + /* Don't warn about forward parameter decls. */ + && !(TREE_CODE (newdecl) == PARM_DECL + && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)) + /* Don't warn about a variable definition following a declaration. */ + && !(VAR_P (newdecl) + && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl))) + { + warned = warning (OPT_Wredundant_decls, "redundant redeclaration of %q+D", + newdecl); + } + + /* Report location of previous decl/defn. */ + if (warned || pedwarned) + locate_old_decl (olddecl); + +#undef DECL_EXTERN_INLINE + + return retval; +} + +/* Subroutine of duplicate_decls. NEWDECL has been found to be + consistent with OLDDECL, but carries new information. Merge the + new information into OLDDECL. This function issues no + diagnostics. */ + +static void +merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) +{ + bool new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) != NULL_TREE); + bool new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL + && prototype_p (TREE_TYPE (newdecl))); + bool old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL + && prototype_p (TREE_TYPE (olddecl))); + + /* For real parm decl following a forward decl, rechain the old decl + in its new location and clear TREE_ASM_WRITTEN (it's not a + forward decl anymore). */ + if (TREE_CODE (newdecl) == PARM_DECL + && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)) + { + struct c_binding *b, **here; + + for (here = ¤t_scope->bindings; *here; here = &(*here)->prev) + if ((*here)->decl == olddecl) + goto found; + gcc_unreachable (); + + found: + b = *here; + *here = b->prev; + b->prev = current_scope->bindings; + current_scope->bindings = b; + + TREE_ASM_WRITTEN (olddecl) = 0; + } + + DECL_ATTRIBUTES (newdecl) + = targetm.merge_decl_attributes (olddecl, newdecl); + + /* For typedefs use the old type, as the new type's DECL_NAME points + at newdecl, which will be ggc_freed. */ + if (TREE_CODE (newdecl) == TYPE_DECL) + { + /* But NEWTYPE might have an attribute, honor that. */ + tree tem = newtype; + newtype = oldtype; + + if (TYPE_USER_ALIGN (tem)) + { + if (TYPE_ALIGN (tem) > TYPE_ALIGN (newtype)) + SET_TYPE_ALIGN (newtype, TYPE_ALIGN (tem)); + TYPE_USER_ALIGN (newtype) = true; + } + + /* And remove the new type from the variants list. */ + if (TYPE_NAME (TREE_TYPE (newdecl)) == newdecl) + { + tree remove = TREE_TYPE (newdecl); + if (TYPE_MAIN_VARIANT (remove) == remove) + { + gcc_assert (TYPE_NEXT_VARIANT (remove) == NULL_TREE); + /* If remove is the main variant, no need to remove that + from the list. One of the DECL_ORIGINAL_TYPE + variants, e.g. created for aligned attribute, might still + refer to the newdecl TYPE_DECL though, so remove that one + in that case. */ + if (DECL_ORIGINAL_TYPE (newdecl) + && DECL_ORIGINAL_TYPE (newdecl) != remove) + for (tree t = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (newdecl)); + t; t = TYPE_MAIN_VARIANT (t)) + if (TYPE_NAME (TYPE_NEXT_VARIANT (t)) == newdecl) + { + TYPE_NEXT_VARIANT (t) + = TYPE_NEXT_VARIANT (TYPE_NEXT_VARIANT (t)); + break; + } + } + else + for (tree t = TYPE_MAIN_VARIANT (remove); ; + t = TYPE_NEXT_VARIANT (t)) + if (TYPE_NEXT_VARIANT (t) == remove) + { + TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (remove); + break; + } + } + } + + /* Merge the data types specified in the two decls. */ + TREE_TYPE (newdecl) + = TREE_TYPE (olddecl) + = composite_type (newtype, oldtype); + + /* Lay the type out, unless already done. */ + if (!comptypes (oldtype, TREE_TYPE (newdecl))) + { + if (TREE_TYPE (newdecl) != error_mark_node) + layout_type (TREE_TYPE (newdecl)); + if (TREE_CODE (newdecl) != FUNCTION_DECL + && TREE_CODE (newdecl) != TYPE_DECL + && TREE_CODE (newdecl) != CONST_DECL) + layout_decl (newdecl, 0); + } + else + { + /* Since the type is OLDDECL's, make OLDDECL's size go with. */ + DECL_SIZE (newdecl) = DECL_SIZE (olddecl); + DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl); + SET_DECL_MODE (newdecl, DECL_MODE (olddecl)); + if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) + { + SET_DECL_ALIGN (newdecl, DECL_ALIGN (olddecl)); + DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl); + } + else if (DECL_ALIGN (olddecl) == DECL_ALIGN (newdecl) + && DECL_USER_ALIGN (olddecl) != DECL_USER_ALIGN (newdecl)) + DECL_USER_ALIGN (newdecl) = 1; + if (DECL_WARN_IF_NOT_ALIGN (olddecl) + > DECL_WARN_IF_NOT_ALIGN (newdecl)) + SET_DECL_WARN_IF_NOT_ALIGN (newdecl, + DECL_WARN_IF_NOT_ALIGN (olddecl)); + } + + /* Keep the old rtl since we can safely use it. */ + if (HAS_RTL_P (olddecl)) + COPY_DECL_RTL (olddecl, newdecl); + + /* Merge the type qualifiers. */ + if (TREE_READONLY (newdecl)) + TREE_READONLY (olddecl) = 1; + + if (TREE_THIS_VOLATILE (newdecl)) + TREE_THIS_VOLATILE (olddecl) = 1; + + /* Merge deprecatedness. */ + if (TREE_DEPRECATED (newdecl)) + TREE_DEPRECATED (olddecl) = 1; + + /* Merge unavailability. */ + if (TREE_UNAVAILABLE (newdecl)) + TREE_UNAVAILABLE (olddecl) = 1; + + /* If a decl is in a system header and the other isn't, keep the one on the + system header. Otherwise, keep source location of definition rather than + declaration and of prototype rather than non-prototype unless that + prototype is built-in. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS) + && DECL_IN_SYSTEM_HEADER (olddecl) + && !DECL_IN_SYSTEM_HEADER (newdecl) ) + DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); + else if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS) + && DECL_IN_SYSTEM_HEADER (newdecl) + && !DECL_IN_SYSTEM_HEADER (olddecl)) + DECL_SOURCE_LOCATION (olddecl) = DECL_SOURCE_LOCATION (newdecl); + else if ((DECL_INITIAL (newdecl) == NULL_TREE + && DECL_INITIAL (olddecl) != NULL_TREE) + || (old_is_prototype && !new_is_prototype + && !C_DECL_BUILTIN_PROTOTYPE (olddecl))) + DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); + + /* Merge the initialization information. */ + if (DECL_INITIAL (newdecl) == NULL_TREE) + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + + /* Merge the threadprivate attribute. */ + if (VAR_P (olddecl) && C_DECL_THREADPRIVATE_P (olddecl)) + C_DECL_THREADPRIVATE_P (newdecl) = 1; + + if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS)) + { + /* Copy the assembler name. + Currently, it can only be defined in the prototype. */ + COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); + + /* Use visibility of whichever declaration had it specified */ + if (DECL_VISIBILITY_SPECIFIED (olddecl)) + { + DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); + DECL_VISIBILITY_SPECIFIED (newdecl) = 1; + } + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); + DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); + DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl); + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) + |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); + TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); + DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl); + if (DECL_IS_OPERATOR_NEW_P (olddecl)) + DECL_SET_IS_OPERATOR_NEW (newdecl, true); + if (DECL_IS_OPERATOR_DELETE_P (olddecl)) + DECL_SET_IS_OPERATOR_DELETE (newdecl, true); + TREE_READONLY (newdecl) |= TREE_READONLY (olddecl); + DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl); + DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl); + } + + /* Merge the storage class information. */ + merge_weak (newdecl, olddecl); + + /* For functions, static overrides non-static. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl); + /* This is since we don't automatically + copy the attributes of NEWDECL into OLDDECL. */ + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + /* If this clears `static', clear it in the identifier too. */ + if (!TREE_PUBLIC (olddecl)) + TREE_PUBLIC (DECL_NAME (olddecl)) = 0; + } + } + + /* In c99, 'extern' declaration before (or after) 'inline' means this + function is not DECL_EXTERNAL, unless 'gnu_inline' attribute + is present. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL + && !flag_gnu89_inline + && (DECL_DECLARED_INLINE_P (newdecl) + || DECL_DECLARED_INLINE_P (olddecl)) + && (!DECL_DECLARED_INLINE_P (newdecl) + || !DECL_DECLARED_INLINE_P (olddecl) + || !DECL_EXTERNAL (olddecl)) + && DECL_EXTERNAL (newdecl) + && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (newdecl)) + && !current_function_decl) + DECL_EXTERNAL (newdecl) = 0; + + /* An inline definition following a static declaration is not + DECL_EXTERNAL. */ + if (new_is_definition + && (DECL_DECLARED_INLINE_P (newdecl) + || DECL_DECLARED_INLINE_P (olddecl)) + && !TREE_PUBLIC (olddecl)) + DECL_EXTERNAL (newdecl) = 0; + + if (DECL_EXTERNAL (newdecl)) + { + TREE_STATIC (newdecl) = TREE_STATIC (olddecl); + DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl); + + /* An extern decl does not override previous storage class. */ + TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); + if (!DECL_EXTERNAL (newdecl)) + { + DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl); + DECL_COMMON (newdecl) = DECL_COMMON (olddecl); + } + } + else + { + TREE_STATIC (olddecl) = TREE_STATIC (newdecl); + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + } + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* If we're redefining a function previously defined as extern + inline, make sure we emit debug info for the inline before we + throw it away, in case it was inlined into a function that + hasn't been written out yet. */ + if (new_is_definition && DECL_INITIAL (olddecl)) + /* The new defn must not be inline. */ + DECL_UNINLINABLE (newdecl) = 1; + else + { + /* If either decl says `inline', this fn is inline, unless + its definition was passed already. */ + if (DECL_DECLARED_INLINE_P (newdecl) + || DECL_DECLARED_INLINE_P (olddecl)) + DECL_DECLARED_INLINE_P (newdecl) = 1; + + DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl) + = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)); + + DECL_DISREGARD_INLINE_LIMITS (newdecl) + = DECL_DISREGARD_INLINE_LIMITS (olddecl) + = (DECL_DISREGARD_INLINE_LIMITS (newdecl) + || DECL_DISREGARD_INLINE_LIMITS (olddecl)); + } + + if (fndecl_built_in_p (olddecl)) + { + /* If redeclaring a builtin function, it stays built in. + But it gets tagged as having been declared. */ + copy_decl_built_in_function (newdecl, olddecl); + C_DECL_DECLARED_BUILTIN (newdecl) = 1; + if (new_is_prototype) + { + C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0; + if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL) + { + enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl); + switch (fncode) + { + /* If a compatible prototype of these builtin functions + is seen, assume the runtime implements it with the + expected semantics. */ + case BUILT_IN_STPCPY: + if (builtin_decl_explicit_p (fncode)) + set_builtin_decl_implicit_p (fncode, true); + break; + default: + if (builtin_decl_explicit_p (fncode)) + set_builtin_decl_declared_p (fncode, true); + break; + } + + copy_attributes_to_builtin (newdecl); + } + } + else + C_DECL_BUILTIN_PROTOTYPE (newdecl) + = C_DECL_BUILTIN_PROTOTYPE (olddecl); + } + + /* Preserve function specific target and optimization options */ + if (DECL_FUNCTION_SPECIFIC_TARGET (olddecl) + && !DECL_FUNCTION_SPECIFIC_TARGET (newdecl)) + DECL_FUNCTION_SPECIFIC_TARGET (newdecl) + = DECL_FUNCTION_SPECIFIC_TARGET (olddecl); + + if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl) + && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl)) + DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl) + = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl); + + /* Also preserve various other info from the definition. */ + if (!new_is_definition) + { + tree t; + DECL_RESULT (newdecl) = DECL_RESULT (olddecl); + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl); + DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl); + DECL_ARGUMENTS (newdecl) = copy_list (DECL_ARGUMENTS (olddecl)); + for (t = DECL_ARGUMENTS (newdecl); t ; t = DECL_CHAIN (t)) + DECL_CONTEXT (t) = newdecl; + + /* See if we've got a function to instantiate from. */ + if (DECL_SAVED_TREE (olddecl)) + DECL_ABSTRACT_ORIGIN (newdecl) + = DECL_ABSTRACT_ORIGIN (olddecl); + } + } + + /* Merge the USED information. */ + if (TREE_USED (olddecl)) + TREE_USED (newdecl) = 1; + else if (TREE_USED (newdecl)) + TREE_USED (olddecl) = 1; + if (VAR_P (olddecl) || TREE_CODE (olddecl) == PARM_DECL) + DECL_READ_P (newdecl) |= DECL_READ_P (olddecl); + if (DECL_PRESERVE_P (olddecl)) + DECL_PRESERVE_P (newdecl) = 1; + else if (DECL_PRESERVE_P (newdecl)) + DECL_PRESERVE_P (olddecl) = 1; + + /* Merge DECL_COMMON */ + if (VAR_P (olddecl) && VAR_P (newdecl) + && !lookup_attribute ("common", DECL_ATTRIBUTES (newdecl)) + && !lookup_attribute ("nocommon", DECL_ATTRIBUTES (newdecl))) + DECL_COMMON (newdecl) = DECL_COMMON (newdecl) && DECL_COMMON (olddecl); + + /* Copy most of the decl-specific fields of NEWDECL into OLDDECL. + But preserve OLDDECL's DECL_UID, DECL_CONTEXT and + DECL_ARGUMENTS (if appropriate). */ + { + unsigned olddecl_uid = DECL_UID (olddecl); + tree olddecl_context = DECL_CONTEXT (olddecl); + tree olddecl_arguments = NULL; + if (TREE_CODE (olddecl) == FUNCTION_DECL) + olddecl_arguments = DECL_ARGUMENTS (olddecl); + + memcpy ((char *) olddecl + sizeof (struct tree_common), + (char *) newdecl + sizeof (struct tree_common), + sizeof (struct tree_decl_common) - sizeof (struct tree_common)); + DECL_USER_ALIGN (olddecl) = DECL_USER_ALIGN (newdecl); + switch (TREE_CODE (olddecl)) + { + case FUNCTION_DECL: + case VAR_DECL: + { + struct symtab_node *snode = olddecl->decl_with_vis.symtab_node; + + memcpy ((char *) olddecl + sizeof (struct tree_decl_common), + (char *) newdecl + sizeof (struct tree_decl_common), + tree_code_size (TREE_CODE (olddecl)) - sizeof (struct tree_decl_common)); + olddecl->decl_with_vis.symtab_node = snode; + + if ((DECL_EXTERNAL (olddecl) + || TREE_PUBLIC (olddecl) + || TREE_STATIC (olddecl)) + && DECL_SECTION_NAME (newdecl) != NULL) + set_decl_section_name (olddecl, newdecl); + + /* This isn't quite correct for something like + int __thread x attribute ((tls_model ("local-exec"))); + extern int __thread x; + as we'll lose the "local-exec" model. */ + if (VAR_P (olddecl) && DECL_THREAD_LOCAL_P (newdecl)) + set_decl_tls_model (olddecl, DECL_TLS_MODEL (newdecl)); + break; + } + + case FIELD_DECL: + case PARM_DECL: + case LABEL_DECL: + case RESULT_DECL: + case CONST_DECL: + case TYPE_DECL: + memcpy ((char *) olddecl + sizeof (struct tree_decl_common), + (char *) newdecl + sizeof (struct tree_decl_common), + tree_code_size (TREE_CODE (olddecl)) - sizeof (struct tree_decl_common)); + break; + + default: + + memcpy ((char *) olddecl + sizeof (struct tree_decl_common), + (char *) newdecl + sizeof (struct tree_decl_common), + sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common)); + } + DECL_UID (olddecl) = olddecl_uid; + DECL_CONTEXT (olddecl) = olddecl_context; + if (TREE_CODE (olddecl) == FUNCTION_DECL) + DECL_ARGUMENTS (olddecl) = olddecl_arguments; + } + + /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl + so that encode_section_info has a chance to look at the new decl + flags and attributes. */ + if (DECL_RTL_SET_P (olddecl) + && (TREE_CODE (olddecl) == FUNCTION_DECL + || (VAR_P (olddecl) && TREE_STATIC (olddecl)))) + make_decl_rtl (olddecl); +} + +/* Handle when a new declaration NEWDECL has the same name as an old + one OLDDECL in the same binding contour. Prints an error message + if appropriate. + + If safely possible, alter OLDDECL to look like NEWDECL, and return + true. Otherwise, return false. */ + +static bool +duplicate_decls (tree newdecl, tree olddecl) +{ + tree newtype = NULL, oldtype = NULL; + + if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype)) + { + /* Avoid `unused variable' and other warnings for OLDDECL. */ + suppress_warning (olddecl, OPT_Wunused); + /* If the types are completely different, poison them both with + error_mark_node. */ + if (TREE_CODE (TREE_TYPE (newdecl)) != TREE_CODE (TREE_TYPE (olddecl)) + && olddecl != error_mark_node + && seen_error ()) + { + if (TREE_CODE (olddecl) != FUNCTION_DECL) + TREE_TYPE (olddecl) = error_mark_node; + if (TREE_CODE (newdecl) != FUNCTION_DECL) + TREE_TYPE (newdecl) = error_mark_node; + } + return false; + } + + merge_decls (newdecl, olddecl, newtype, oldtype); + + /* The NEWDECL will no longer be needed. + + Before releasing the node, be sure to remove function from symbol + table that might have been inserted there to record comdat group. + Be sure to however do not free DECL_STRUCT_FUNCTION because this + structure is shared in between NEWDECL and OLDECL. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL) + DECL_STRUCT_FUNCTION (newdecl) = NULL; + if (VAR_OR_FUNCTION_DECL_P (newdecl)) + { + struct symtab_node *snode = symtab_node::get (newdecl); + if (snode) + snode->remove (); + } + ggc_free (newdecl); + return true; +} + + +/* Check whether decl-node NEW_DECL shadows an existing declaration. */ +static void +warn_if_shadowing (tree new_decl) +{ + struct c_binding *b; + + /* Shadow warnings wanted? */ + if (!(warn_shadow + || warn_shadow_local + || warn_shadow_compatible_local) + /* No shadow warnings for internally generated vars. */ + || DECL_IS_UNDECLARED_BUILTIN (new_decl)) + return; + + /* Is anything being shadowed? Invisible decls do not count. */ + for (b = I_SYMBOL_BINDING (DECL_NAME (new_decl)); b; b = b->shadowed) + if (b->decl && b->decl != new_decl && !b->invisible + && (b->decl == error_mark_node + || diagnostic_report_warnings_p (global_dc, + DECL_SOURCE_LOCATION (b->decl)))) + { + tree old_decl = b->decl; + + if (old_decl == error_mark_node) + { + warning (OPT_Wshadow, "declaration of %q+D shadows previous " + "non-variable", new_decl); + break; + } + + bool warned = false; + auto_diagnostic_group d; + if (TREE_CODE (old_decl) == PARM_DECL) + { + enum opt_code warning_code; + + /* If '-Wshadow=compatible-local' is specified without other + -Wshadow= flags, we will warn only when the types of the + shadowing variable (i.e. new_decl) and the shadowed variable + (old_decl) are compatible. */ + if (warn_shadow) + warning_code = OPT_Wshadow; + else if (comptypes (TREE_TYPE (old_decl), TREE_TYPE (new_decl))) + warning_code = OPT_Wshadow_compatible_local; + else + warning_code = OPT_Wshadow_local; + warned = warning_at (DECL_SOURCE_LOCATION (new_decl), warning_code, + "declaration of %qD shadows a parameter", + new_decl); + } + else if (DECL_FILE_SCOPE_P (old_decl)) + { + /* Do not warn if a variable shadows a function, unless + the variable is a function or a pointer-to-function. */ + if (TREE_CODE (old_decl) == FUNCTION_DECL + && TREE_CODE (new_decl) != FUNCTION_DECL + && !FUNCTION_POINTER_TYPE_P (TREE_TYPE (new_decl))) + continue; + + warned = warning_at (DECL_SOURCE_LOCATION (new_decl), OPT_Wshadow, + "declaration of %qD shadows a global " + "declaration", + new_decl); + } + else if (TREE_CODE (old_decl) == FUNCTION_DECL + && fndecl_built_in_p (old_decl)) + { + warning (OPT_Wshadow, "declaration of %q+D shadows " + "a built-in function", new_decl); + break; + } + else + { + enum opt_code warning_code; + + /* If '-Wshadow=compatible-local' is specified without other + -Wshadow= flags, we will warn only when the types of the + shadowing variable (i.e. new_decl) and the shadowed variable + (old_decl) are compatible. */ + if (warn_shadow) + warning_code = OPT_Wshadow; + else if (comptypes (TREE_TYPE (old_decl), TREE_TYPE (new_decl))) + warning_code = OPT_Wshadow_compatible_local; + else + warning_code = OPT_Wshadow_local; + warned = warning_at (DECL_SOURCE_LOCATION (new_decl), warning_code, + "declaration of %qD shadows a previous local", + new_decl); + } + + if (warned) + inform (DECL_SOURCE_LOCATION (old_decl), + "shadowed declaration is here"); + + break; + } +} + +/* Record a decl-node X as belonging to the current lexical scope. + Check for errors (such as an incompatible declaration for the same + name already seen in the same scope). + + Returns either X or an old decl for the same name. + If an old decl is returned, it may have been smashed + to agree with what X says. */ + +tree +pushdecl (tree x) +{ + tree name = DECL_NAME (x); + struct c_scope *scope = current_scope; + struct c_binding *b; + bool nested = false; + location_t locus = DECL_SOURCE_LOCATION (x); + + /* Must set DECL_CONTEXT for everything not at file scope or + DECL_FILE_SCOPE_P won't work. Local externs don't count + unless they have initializers (which generate code). */ + if (current_function_decl + && (!VAR_OR_FUNCTION_DECL_P (x) + || DECL_INITIAL (x) || !TREE_PUBLIC (x))) + DECL_CONTEXT (x) = current_function_decl; + + /* Anonymous decls are just inserted in the scope. */ + if (!name) + { + bind (name, x, scope, /*invisible=*/false, /*nested=*/false, + locus); + return x; + } + + /* First, see if there is another declaration with the same name in + the current scope. If there is, duplicate_decls may do all the + work for us. If duplicate_decls returns false, that indicates + two incompatible decls in the same scope; we are to silently + replace the old one (duplicate_decls has issued all appropriate + diagnostics). In particular, we should not consider possible + duplicates in the external scope, or shadowing. */ + b = I_SYMBOL_BINDING (name); + if (b && B_IN_SCOPE (b, scope)) + { + struct c_binding *b_ext, *b_use; + tree type = TREE_TYPE (x); + tree visdecl = b->decl; + tree vistype = TREE_TYPE (visdecl); + if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE + && COMPLETE_TYPE_P (TREE_TYPE (x))) + b->inner_comp = false; + b_use = b; + b_ext = b; + /* If this is an external linkage declaration, we should check + for compatibility with the type in the external scope before + setting the type at this scope based on the visible + information only. */ + if (TREE_PUBLIC (x) && TREE_PUBLIC (visdecl)) + { + while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext)) + b_ext = b_ext->shadowed; + if (b_ext) + { + b_use = b_ext; + if (b_use->u.type) + TREE_TYPE (b_use->decl) = b_use->u.type; + } + } + if (duplicate_decls (x, b_use->decl)) + { + if (b_use != b) + { + /* Save the updated type in the external scope and + restore the proper type for this scope. */ + tree thistype; + if (comptypes (vistype, type)) + thistype = composite_type (vistype, type); + else + thistype = TREE_TYPE (b_use->decl); + b_use->u.type = TREE_TYPE (b_use->decl); + if (TREE_CODE (b_use->decl) == FUNCTION_DECL + && fndecl_built_in_p (b_use->decl)) + thistype + = build_type_attribute_variant (thistype, + TYPE_ATTRIBUTES + (b_use->u.type)); + TREE_TYPE (b_use->decl) = thistype; + } + return b_use->decl; + } + else + goto skip_external_and_shadow_checks; + } + + /* All declarations with external linkage, and all external + references, go in the external scope, no matter what scope is + current. However, the binding in that scope is ignored for + purposes of normal name lookup. A separate binding structure is + created in the requested scope; this governs the normal + visibility of the symbol. + + The binding in the externals scope is used exclusively for + detecting duplicate declarations of the same object, no matter + what scope they are in; this is what we do here. (C99 6.2.7p2: + All declarations that refer to the same object or function shall + have compatible type; otherwise, the behavior is undefined.) + However, in Objective-C, we also want to detect declarations + conflicting with those of the basic types. */ + if ((DECL_EXTERNAL (x) || scope == file_scope) + && (VAR_OR_FUNCTION_DECL_P (x) || c_dialect_objc ())) + { + tree type = TREE_TYPE (x); + tree vistype = NULL_TREE; + tree visdecl = NULL_TREE; + bool type_saved = false; + if (b && !B_IN_EXTERNAL_SCOPE (b) + && VAR_OR_FUNCTION_DECL_P (b->decl) + && DECL_FILE_SCOPE_P (b->decl)) + { + visdecl = b->decl; + vistype = TREE_TYPE (visdecl); + } + if (scope != file_scope + && !DECL_IN_SYSTEM_HEADER (x)) + warning_at (locus, OPT_Wnested_externs, + "nested extern declaration of %qD", x); + + while (b && !B_IN_EXTERNAL_SCOPE (b)) + { + /* If this decl might be modified, save its type. This is + done here rather than when the decl is first bound + because the type may change after first binding, through + being completed or through attributes being added. If we + encounter multiple such decls, only the first should have + its type saved; the others will already have had their + proper types saved and the types will not have changed as + their scopes will not have been re-entered. */ + if (DECL_P (b->decl) && DECL_FILE_SCOPE_P (b->decl) && !type_saved) + { + b->u.type = TREE_TYPE (b->decl); + type_saved = true; + } + if (B_IN_FILE_SCOPE (b) + && VAR_P (b->decl) + && TREE_STATIC (b->decl) + && TREE_CODE (TREE_TYPE (b->decl)) == ARRAY_TYPE + && !TYPE_DOMAIN (TREE_TYPE (b->decl)) + && TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) + && !integer_zerop (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))) + { + /* Array type completed in inner scope, which should be + diagnosed if the completion does not have size 1 and + it does not get completed in the file scope. */ + b->inner_comp = true; + } + b = b->shadowed; + } + + /* If a matching external declaration has been found, set its + type to the composite of all the types of that declaration. + After the consistency checks, it will be reset to the + composite of the visible types only. */ + if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl)) + && b->u.type) + TREE_TYPE (b->decl) = b->u.type; + + /* The point of the same_translation_unit_p check here is, + we want to detect a duplicate decl for a construct like + foo() { extern bar(); } ... static bar(); but not if + they are in different translation units. In any case, + the static does not go in the externals scope. */ + if (b + && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl)) + && duplicate_decls (x, b->decl)) + { + tree thistype; + if (vistype) + { + if (comptypes (vistype, type)) + thistype = composite_type (vistype, type); + else + thistype = TREE_TYPE (b->decl); + } + else + thistype = type; + b->u.type = TREE_TYPE (b->decl); + /* Propagate the type attributes to the decl. */ + thistype + = build_type_attribute_variant (thistype, + TYPE_ATTRIBUTES (b->u.type)); + TREE_TYPE (b->decl) = thistype; + bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true, + locus); + return b->decl; + } + else if (TREE_PUBLIC (x)) + { + if (visdecl && !b && duplicate_decls (x, visdecl)) + { + /* An external declaration at block scope referring to a + visible entity with internal linkage. The composite + type will already be correct for this scope, so we + just need to fall through to make the declaration in + this scope. */ + nested = true; + x = visdecl; + } + else + { + bind (name, x, external_scope, /*invisible=*/true, + /*nested=*/false, locus); + nested = true; + } + } + } + + if (TREE_CODE (x) != PARM_DECL) + warn_if_shadowing (x); + + skip_external_and_shadow_checks: + if (TREE_CODE (x) == TYPE_DECL) + { + /* So this is a typedef, set its underlying type. */ + set_underlying_type (x); + + /* If X is a typedef defined in the current function, record it + for the purpose of implementing the -Wunused-local-typedefs + warning. */ + record_locally_defined_typedef (x); + } + + bind (name, x, scope, /*invisible=*/false, nested, locus); + + /* If x's type is incomplete because it's based on a + structure or union which has not yet been fully declared, + attach it to that structure or union type, so we can go + back and complete the variable declaration later, if the + structure or union gets fully declared. + + If the input is erroneous, we can have error_mark in the type + slot (e.g. "f(void a, ...)") - that doesn't count as an + incomplete type. */ + if (TREE_TYPE (x) != error_mark_node + && !COMPLETE_TYPE_P (TREE_TYPE (x))) + { + tree element = TREE_TYPE (x); + + while (TREE_CODE (element) == ARRAY_TYPE) + element = TREE_TYPE (element); + element = TYPE_MAIN_VARIANT (element); + + if ((RECORD_OR_UNION_TYPE_P (element) + || TREE_CODE (element) == ENUMERAL_TYPE) + && (TREE_CODE (x) != TYPE_DECL + || TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE) + && !COMPLETE_TYPE_P (element)) + C_TYPE_INCOMPLETE_VARS (element) + = tree_cons (NULL_TREE, x, C_TYPE_INCOMPLETE_VARS (element)); + } + return x; +} + + +/* Issue a warning about implicit function declaration. ID is the function + identifier, OLDDECL is a declaration of the function in a different scope, + or NULL_TREE. */ + +static void +implicit_decl_warning (location_t loc, tree id, tree olddecl) +{ + if (!warn_implicit_function_declaration) + return; + + bool warned; + auto_diagnostic_group d; + name_hint hint; + if (!olddecl) + hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_FUNCTION_NAME, loc); + + if (flag_isoc99) + { + if (const char *suggestion = hint.suggestion ()) + { + gcc_rich_location richloc (loc); + richloc.add_fixit_replace (suggestion); + warned = pedwarn (&richloc, OPT_Wimplicit_function_declaration, + "implicit declaration of function %qE;" + " did you mean %qs?", + id, suggestion); + } + else + warned = pedwarn (loc, OPT_Wimplicit_function_declaration, + "implicit declaration of function %qE", id); + } + else if (const char *suggestion = hint.suggestion ()) + { + gcc_rich_location richloc (loc); + richloc.add_fixit_replace (suggestion); + warned = warning_at + (&richloc, OPT_Wimplicit_function_declaration, + G_("implicit declaration of function %qE; did you mean %qs?"), + id, suggestion); + } + else + warned = warning_at (loc, OPT_Wimplicit_function_declaration, + G_("implicit declaration of function %qE"), id); + + if (warned) + { + /* Whether the olddecl is an undeclared builtin function. + locate_old_decl will not generate a diagnostic for those, + so in that case we want to look elsewhere. */ + bool undeclared_builtin = (olddecl + && TREE_CODE (olddecl) == FUNCTION_DECL + && fndecl_built_in_p (olddecl) + && !C_DECL_DECLARED_BUILTIN (olddecl)); + if (undeclared_builtin) + { + const char *header = header_for_builtin_fn (olddecl); + if (header) + { + rich_location richloc (line_table, loc); + maybe_add_include_fixit (&richloc, header, true); + inform (&richloc, + "include %qs or provide a declaration of %qE", + header, id); + } + } + else if (olddecl) + locate_old_decl (olddecl); + } + + if (!warned) + hint.suppress (); +} + +/* Return the name of the header file that declares built-in function + FNDECL, or null if either we don't know or don't expect to see an + explicit declaration. */ + +static const char * +header_for_builtin_fn (tree fndecl) +{ + if (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL) + return NULL; + + switch (DECL_FUNCTION_CODE (fndecl)) + { + CASE_FLT_FN (BUILT_IN_ACOS): + CASE_FLT_FN (BUILT_IN_ACOSH): + CASE_FLT_FN (BUILT_IN_ASIN): + CASE_FLT_FN (BUILT_IN_ASINH): + CASE_FLT_FN (BUILT_IN_ATAN): + CASE_FLT_FN (BUILT_IN_ATANH): + CASE_FLT_FN (BUILT_IN_ATAN2): + CASE_FLT_FN (BUILT_IN_CBRT): + CASE_FLT_FN (BUILT_IN_CEIL): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_CEIL): + CASE_FLT_FN (BUILT_IN_COPYSIGN): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_COPYSIGN): + CASE_FLT_FN (BUILT_IN_COS): + CASE_FLT_FN (BUILT_IN_COSH): + CASE_FLT_FN (BUILT_IN_ERF): + CASE_FLT_FN (BUILT_IN_ERFC): + CASE_FLT_FN (BUILT_IN_EXP): + CASE_FLT_FN (BUILT_IN_EXP2): + CASE_FLT_FN (BUILT_IN_EXPM1): + CASE_FLT_FN (BUILT_IN_FABS): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS): + CASE_FLT_FN (BUILT_IN_FDIM): + CASE_FLT_FN (BUILT_IN_FLOOR): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_FLOOR): + CASE_FLT_FN (BUILT_IN_FMA): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMA): + CASE_FLT_FN (BUILT_IN_FMAX): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMAX): + CASE_FLT_FN (BUILT_IN_FMIN): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMIN): + CASE_FLT_FN (BUILT_IN_FMOD): + CASE_FLT_FN (BUILT_IN_FREXP): + CASE_FLT_FN (BUILT_IN_HYPOT): + CASE_FLT_FN (BUILT_IN_ILOGB): + CASE_FLT_FN (BUILT_IN_LDEXP): + CASE_FLT_FN (BUILT_IN_LGAMMA): + CASE_FLT_FN (BUILT_IN_LLRINT): + CASE_FLT_FN (BUILT_IN_LLROUND): + CASE_FLT_FN (BUILT_IN_LOG): + CASE_FLT_FN (BUILT_IN_LOG10): + CASE_FLT_FN (BUILT_IN_LOG1P): + CASE_FLT_FN (BUILT_IN_LOG2): + CASE_FLT_FN (BUILT_IN_LOGB): + CASE_FLT_FN (BUILT_IN_LRINT): + CASE_FLT_FN (BUILT_IN_LROUND): + CASE_FLT_FN (BUILT_IN_MODF): + CASE_FLT_FN (BUILT_IN_NAN): + CASE_FLT_FN (BUILT_IN_NEARBYINT): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_NEARBYINT): + CASE_FLT_FN (BUILT_IN_NEXTAFTER): + CASE_FLT_FN (BUILT_IN_NEXTTOWARD): + CASE_FLT_FN (BUILT_IN_POW): + CASE_FLT_FN (BUILT_IN_REMAINDER): + CASE_FLT_FN (BUILT_IN_REMQUO): + CASE_FLT_FN (BUILT_IN_RINT): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_RINT): + CASE_FLT_FN (BUILT_IN_ROUND): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_ROUND): + CASE_FLT_FN (BUILT_IN_SCALBLN): + CASE_FLT_FN (BUILT_IN_SCALBN): + CASE_FLT_FN (BUILT_IN_SIN): + CASE_FLT_FN (BUILT_IN_SINH): + CASE_FLT_FN (BUILT_IN_SINCOS): + CASE_FLT_FN (BUILT_IN_SQRT): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_SQRT): + CASE_FLT_FN (BUILT_IN_TAN): + CASE_FLT_FN (BUILT_IN_TANH): + CASE_FLT_FN (BUILT_IN_TGAMMA): + CASE_FLT_FN (BUILT_IN_TRUNC): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_TRUNC): + case BUILT_IN_ISINF: + case BUILT_IN_ISNAN: + return ""; + CASE_FLT_FN (BUILT_IN_CABS): + CASE_FLT_FN (BUILT_IN_CACOS): + CASE_FLT_FN (BUILT_IN_CACOSH): + CASE_FLT_FN (BUILT_IN_CARG): + CASE_FLT_FN (BUILT_IN_CASIN): + CASE_FLT_FN (BUILT_IN_CASINH): + CASE_FLT_FN (BUILT_IN_CATAN): + CASE_FLT_FN (BUILT_IN_CATANH): + CASE_FLT_FN (BUILT_IN_CCOS): + CASE_FLT_FN (BUILT_IN_CCOSH): + CASE_FLT_FN (BUILT_IN_CEXP): + CASE_FLT_FN (BUILT_IN_CIMAG): + CASE_FLT_FN (BUILT_IN_CLOG): + CASE_FLT_FN (BUILT_IN_CONJ): + CASE_FLT_FN (BUILT_IN_CPOW): + CASE_FLT_FN (BUILT_IN_CPROJ): + CASE_FLT_FN (BUILT_IN_CREAL): + CASE_FLT_FN (BUILT_IN_CSIN): + CASE_FLT_FN (BUILT_IN_CSINH): + CASE_FLT_FN (BUILT_IN_CSQRT): + CASE_FLT_FN (BUILT_IN_CTAN): + CASE_FLT_FN (BUILT_IN_CTANH): + return ""; + case BUILT_IN_MEMCHR: + case BUILT_IN_MEMCMP: + case BUILT_IN_MEMCPY: + case BUILT_IN_MEMMOVE: + case BUILT_IN_MEMSET: + case BUILT_IN_STRCAT: + case BUILT_IN_STRCHR: + case BUILT_IN_STRCMP: + case BUILT_IN_STRCPY: + case BUILT_IN_STRCSPN: + case BUILT_IN_STRLEN: + case BUILT_IN_STRNCAT: + case BUILT_IN_STRNCMP: + case BUILT_IN_STRNCPY: + case BUILT_IN_STRPBRK: + case BUILT_IN_STRRCHR: + case BUILT_IN_STRSPN: + case BUILT_IN_STRSTR: + return ""; + case BUILT_IN_FPRINTF: + case BUILT_IN_PUTC: + case BUILT_IN_FPUTC: + case BUILT_IN_FPUTS: + case BUILT_IN_FSCANF: + case BUILT_IN_FWRITE: + case BUILT_IN_PRINTF: + case BUILT_IN_PUTCHAR: + case BUILT_IN_PUTS: + case BUILT_IN_SCANF: + case BUILT_IN_SNPRINTF: + case BUILT_IN_SPRINTF: + case BUILT_IN_SSCANF: + case BUILT_IN_VFPRINTF: + case BUILT_IN_VFSCANF: + case BUILT_IN_VPRINTF: + case BUILT_IN_VSCANF: + case BUILT_IN_VSNPRINTF: + case BUILT_IN_VSPRINTF: + case BUILT_IN_VSSCANF: + return ""; + case BUILT_IN_ISALNUM: + case BUILT_IN_ISALPHA: + case BUILT_IN_ISBLANK: + case BUILT_IN_ISCNTRL: + case BUILT_IN_ISDIGIT: + case BUILT_IN_ISGRAPH: + case BUILT_IN_ISLOWER: + case BUILT_IN_ISPRINT: + case BUILT_IN_ISPUNCT: + case BUILT_IN_ISSPACE: + case BUILT_IN_ISUPPER: + case BUILT_IN_ISXDIGIT: + case BUILT_IN_TOLOWER: + case BUILT_IN_TOUPPER: + return ""; + case BUILT_IN_ISWALNUM: + case BUILT_IN_ISWALPHA: + case BUILT_IN_ISWBLANK: + case BUILT_IN_ISWCNTRL: + case BUILT_IN_ISWDIGIT: + case BUILT_IN_ISWGRAPH: + case BUILT_IN_ISWLOWER: + case BUILT_IN_ISWPRINT: + case BUILT_IN_ISWPUNCT: + case BUILT_IN_ISWSPACE: + case BUILT_IN_ISWUPPER: + case BUILT_IN_ISWXDIGIT: + case BUILT_IN_TOWLOWER: + case BUILT_IN_TOWUPPER: + return ""; + case BUILT_IN_ABORT: + case BUILT_IN_ABS: + case BUILT_IN_CALLOC: + case BUILT_IN_EXIT: + case BUILT_IN_FREE: + case BUILT_IN_LABS: + case BUILT_IN_LLABS: + case BUILT_IN_MALLOC: + case BUILT_IN_REALLOC: + case BUILT_IN__EXIT2: + case BUILT_IN_ALIGNED_ALLOC: + return ""; + case BUILT_IN_IMAXABS: + return ""; + case BUILT_IN_STRFTIME: + return ""; + default: + return NULL; + } +} + +/* Generate an implicit declaration for identifier FUNCTIONID at LOC as a + function of type int (). */ + +tree +implicitly_declare (location_t loc, tree functionid) +{ + struct c_binding *b; + tree decl = NULL_TREE; + tree asmspec_tree; + + for (b = I_SYMBOL_BINDING (functionid); b; b = b->shadowed) + { + if (B_IN_SCOPE (b, external_scope)) + { + decl = b->decl; + break; + } + } + + if (decl) + { + if (TREE_CODE (decl) != FUNCTION_DECL) + return decl; + + /* FIXME: Objective-C has weird not-really-builtin functions + which are supposed to be visible automatically. They wind up + in the external scope because they're pushed before the file + scope gets created. Catch this here and rebind them into the + file scope. */ + if (!fndecl_built_in_p (decl) && DECL_IS_UNDECLARED_BUILTIN (decl)) + { + bind (functionid, decl, file_scope, + /*invisible=*/false, /*nested=*/true, + DECL_SOURCE_LOCATION (decl)); + return decl; + } + else + { + tree newtype = default_function_type; + if (b->u.type) + TREE_TYPE (decl) = b->u.type; + /* Implicit declaration of a function already declared + (somehow) in a different scope, or as a built-in. + If this is the first time this has happened, warn; + then recycle the old declaration but with the new type. */ + if (!C_DECL_IMPLICIT (decl)) + { + implicit_decl_warning (loc, functionid, decl); + C_DECL_IMPLICIT (decl) = 1; + } + if (fndecl_built_in_p (decl)) + { + newtype = build_type_attribute_variant (newtype, + TYPE_ATTRIBUTES + (TREE_TYPE (decl))); + if (!comptypes (newtype, TREE_TYPE (decl))) + { + bool warned = warning_at (loc, + OPT_Wbuiltin_declaration_mismatch, + "incompatible implicit " + "declaration of built-in " + "function %qD", decl); + /* See if we can hint which header to include. */ + const char *header = header_for_builtin_fn (decl); + if (header != NULL && warned) + { + rich_location richloc (line_table, loc); + maybe_add_include_fixit (&richloc, header, true); + inform (&richloc, + "include %qs or provide a declaration of %qD", + header, decl); + } + newtype = TREE_TYPE (decl); + } + } + else + { + if (!comptypes (newtype, TREE_TYPE (decl))) + { + auto_diagnostic_group d; + error_at (loc, "incompatible implicit declaration of " + "function %qD", decl); + locate_old_decl (decl); + } + } + b->u.type = TREE_TYPE (decl); + TREE_TYPE (decl) = newtype; + bind (functionid, decl, current_scope, + /*invisible=*/false, /*nested=*/true, + DECL_SOURCE_LOCATION (decl)); + return decl; + } + } + + /* Not seen before. */ + decl = build_decl (loc, FUNCTION_DECL, functionid, default_function_type); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + C_DECL_IMPLICIT (decl) = 1; + implicit_decl_warning (loc, functionid, 0); + asmspec_tree = maybe_apply_renaming_pragma (decl, /*asmname=*/NULL); + if (asmspec_tree) + set_user_assembler_name (decl, TREE_STRING_POINTER (asmspec_tree)); + + /* C89 says implicit declarations are in the innermost block. + So we record the decl in the standard fashion. */ + decl = pushdecl (decl); + + /* No need to call objc_check_decl here - it's a function type. */ + rest_of_decl_compilation (decl, 0, 0); + + /* Write a record describing this implicit function declaration + to the prototypes file (if requested). */ + gen_aux_info_record (decl, 0, 1, 0); + + /* Possibly apply some default attributes to this implicit declaration. */ + decl_attributes (&decl, NULL_TREE, 0); + + return decl; +} + +/* Issue an error message for a reference to an undeclared variable + ID, including a reference to a builtin outside of function-call + context. Establish a binding of the identifier to error_mark_node + in an appropriate scope, which will suppress further errors for the + same identifier. The error message should be given location LOC. */ +void +undeclared_variable (location_t loc, tree id) +{ + static bool already = false; + struct c_scope *scope; + + auto_diagnostic_group d; + if (current_function_decl == NULL_TREE) + { + name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc); + if (const char *suggestion = guessed_id.suggestion ()) + { + gcc_rich_location richloc (loc); + richloc.add_fixit_replace (suggestion); + error_at (&richloc, + "%qE undeclared here (not in a function);" + " did you mean %qs?", + id, suggestion); + } + else + error_at (loc, "%qE undeclared here (not in a function)", id); + scope = current_scope; + } + else + { + if (!objc_diagnose_private_ivar (id)) + { + name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc); + if (const char *suggestion = guessed_id.suggestion ()) + { + gcc_rich_location richloc (loc); + richloc.add_fixit_replace (suggestion); + error_at (&richloc, + "%qE undeclared (first use in this function);" + " did you mean %qs?", + id, suggestion); + } + else + error_at (loc, "%qE undeclared (first use in this function)", id); + } + if (!already) + { + inform (loc, "each undeclared identifier is reported only" + " once for each function it appears in"); + already = true; + } + + /* If we are parsing old-style parameter decls, current_function_decl + will be nonnull but current_function_scope will be null. */ + scope = current_function_scope ? current_function_scope : current_scope; + } + bind (id, error_mark_node, scope, /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); +} + +/* Subroutine of lookup_label, declare_label, define_label: construct a + LABEL_DECL with all the proper frills. Also create a struct + c_label_vars initialized for the current scope. */ + +static tree +make_label (location_t location, tree name, bool defining, + struct c_label_vars **p_label_vars) +{ + tree label = build_decl (location, LABEL_DECL, name, void_type_node); + DECL_CONTEXT (label) = current_function_decl; + SET_DECL_MODE (label, VOIDmode); + + c_label_vars *label_vars = ggc_alloc (); + label_vars->shadowed = NULL; + set_spot_bindings (&label_vars->label_bindings, defining); + label_vars->decls_in_scope = make_tree_vector (); + label_vars->gotos = NULL; + *p_label_vars = label_vars; + + return label; +} + +/* Get the LABEL_DECL corresponding to identifier NAME as a label. + Create one if none exists so far for the current function. + This is called when a label is used in a goto expression or + has its address taken. */ + +tree +lookup_label (tree name) +{ + tree label; + struct c_label_vars *label_vars; + + if (current_function_scope == 0) + { + error ("label %qE referenced outside of any function", name); + return NULL_TREE; + } + + /* Use a label already defined or ref'd with this name, but not if + it is inherited from a containing function and wasn't declared + using __label__. */ + label = I_LABEL_DECL (name); + if (label && (DECL_CONTEXT (label) == current_function_decl + || C_DECLARED_LABEL_FLAG (label))) + { + /* If the label has only been declared, update its apparent + location to point here, for better diagnostics if it + turns out not to have been defined. */ + if (DECL_INITIAL (label) == NULL_TREE) + DECL_SOURCE_LOCATION (label) = input_location; + return label; + } + + /* No label binding for that identifier; make one. */ + label = make_label (input_location, name, false, &label_vars); + + /* Ordinary labels go in the current function scope. */ + bind_label (name, label, current_function_scope, label_vars); + + return label; +} + +/* Issue a warning about DECL for a goto statement at GOTO_LOC going + to LABEL. */ + +static void +warn_about_goto (location_t goto_loc, tree label, tree decl) +{ + if (variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + error_at (goto_loc, + "jump into scope of identifier with variably modified type"); + else + warning_at (goto_loc, OPT_Wjump_misses_init, + "jump skips variable initialization"); + inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label); + inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl); +} + +/* Look up a label because of a goto statement. This is like + lookup_label, but also issues any appropriate warnings. */ + +tree +lookup_label_for_goto (location_t loc, tree name) +{ + tree label; + struct c_label_vars *label_vars; + unsigned int ix; + tree decl; + + label = lookup_label (name); + if (label == NULL_TREE) + return NULL_TREE; + + /* If we are jumping to a different function, we can't issue any + useful warnings. */ + if (DECL_CONTEXT (label) != current_function_decl) + { + gcc_assert (C_DECLARED_LABEL_FLAG (label)); + return label; + } + + label_vars = I_LABEL_BINDING (name)->u.label; + + /* If the label has not yet been defined, then push this goto on a + list for possible later warnings. */ + if (label_vars->label_bindings.scope == NULL) + { + c_goto_bindings *g = ggc_alloc (); + + g->loc = loc; + set_spot_bindings (&g->goto_bindings, true); + vec_safe_push (label_vars->gotos, g); + return label; + } + + /* If there are any decls in label_vars->decls_in_scope, then this + goto has missed the declaration of the decl. This happens for a + case like + int i = 1; + lab: + ... + goto lab; + Issue a warning or error. */ + FOR_EACH_VEC_SAFE_ELT (label_vars->decls_in_scope, ix, decl) + warn_about_goto (loc, label, decl); + + if (label_vars->label_bindings.left_stmt_expr) + { + error_at (loc, "jump into statement expression"); + inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label); + } + + return label; +} + +/* Make a label named NAME in the current function, shadowing silently + any that may be inherited from containing functions or containing + scopes. This is called for __label__ declarations. */ + +tree +declare_label (tree name) +{ + struct c_binding *b = I_LABEL_BINDING (name); + tree label; + struct c_label_vars *label_vars; + + /* Check to make sure that the label hasn't already been declared + at this scope */ + if (b && B_IN_CURRENT_SCOPE (b)) + { + auto_diagnostic_group d; + error ("duplicate label declaration %qE", name); + locate_old_decl (b->decl); + + /* Just use the previous declaration. */ + return b->decl; + } + + label = make_label (input_location, name, false, &label_vars); + C_DECLARED_LABEL_FLAG (label) = 1; + + /* Declared labels go in the current scope. */ + bind_label (name, label, current_scope, label_vars); + + return label; +} + +/* When we define a label, issue any appropriate warnings if there are + any gotos earlier in the function which jump to this label. */ + +static void +check_earlier_gotos (tree label, struct c_label_vars* label_vars) +{ + unsigned int ix; + struct c_goto_bindings *g; + + FOR_EACH_VEC_SAFE_ELT (label_vars->gotos, ix, g) + { + struct c_binding *b; + struct c_scope *scope; + + /* We have a goto to this label. The goto is going forward. In + g->scope, the goto is going to skip any binding which was + defined after g->bindings_in_scope. */ + if (g->goto_bindings.scope->has_jump_unsafe_decl) + { + for (b = g->goto_bindings.scope->bindings; + b != g->goto_bindings.bindings_in_scope; + b = b->prev) + { + if (decl_jump_unsafe (b->decl)) + warn_about_goto (g->loc, label, b->decl); + } + } + + /* We also need to warn about decls defined in any scopes + between the scope of the label and the scope of the goto. */ + for (scope = label_vars->label_bindings.scope; + scope != g->goto_bindings.scope; + scope = scope->outer) + { + gcc_assert (scope != NULL); + if (scope->has_jump_unsafe_decl) + { + if (scope == label_vars->label_bindings.scope) + b = label_vars->label_bindings.bindings_in_scope; + else + b = scope->bindings; + for (; b != NULL; b = b->prev) + { + if (decl_jump_unsafe (b->decl)) + warn_about_goto (g->loc, label, b->decl); + } + } + } + + if (g->goto_bindings.stmt_exprs > 0) + { + error_at (g->loc, "jump into statement expression"); + inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", + label); + } + } + + /* Now that the label is defined, we will issue warnings about + subsequent gotos to this label when we see them. */ + vec_safe_truncate (label_vars->gotos, 0); + label_vars->gotos = NULL; +} + +/* Define a label, specifying the location in the source file. + Return the LABEL_DECL node for the label, if the definition is valid. + Otherwise return NULL_TREE. */ + +tree +define_label (location_t location, tree name) +{ + /* Find any preexisting label with this name. It is an error + if that label has already been defined in this function, or + if there is a containing function with a declared label with + the same name. */ + tree label = I_LABEL_DECL (name); + + if (label + && ((DECL_CONTEXT (label) == current_function_decl + && DECL_INITIAL (label) != NULL_TREE) + || (DECL_CONTEXT (label) != current_function_decl + && C_DECLARED_LABEL_FLAG (label)))) + { + auto_diagnostic_group d; + error_at (location, "duplicate label %qD", label); + locate_old_decl (label); + return NULL_TREE; + } + else if (label && DECL_CONTEXT (label) == current_function_decl) + { + struct c_label_vars *label_vars = I_LABEL_BINDING (name)->u.label; + + /* The label has been used or declared already in this function, + but not defined. Update its location to point to this + definition. */ + DECL_SOURCE_LOCATION (label) = location; + set_spot_bindings (&label_vars->label_bindings, true); + + /* Issue warnings as required about any goto statements from + earlier in the function. */ + check_earlier_gotos (label, label_vars); + } + else + { + struct c_label_vars *label_vars; + + /* No label binding for that identifier; make one. */ + label = make_label (location, name, true, &label_vars); + + /* Ordinary labels go in the current function scope. */ + bind_label (name, label, current_function_scope, label_vars); + } + + if (!in_system_header_at (input_location) && lookup_name (name)) + warning_at (location, OPT_Wtraditional, + "traditional C lacks a separate namespace " + "for labels, identifier %qE conflicts", name); + + /* Mark label as having been defined. */ + DECL_INITIAL (label) = error_mark_node; + return label; +} + +/* Get the bindings for a new switch statement. This is used to issue + warnings as appropriate for jumps from the switch to case or + default labels. */ + +struct c_spot_bindings * +c_get_switch_bindings (void) +{ + struct c_spot_bindings *switch_bindings; + + switch_bindings = XNEW (struct c_spot_bindings); + set_spot_bindings (switch_bindings, true); + return switch_bindings; +} + +void +c_release_switch_bindings (struct c_spot_bindings *bindings) +{ + gcc_assert (bindings->stmt_exprs == 0 && !bindings->left_stmt_expr); + XDELETE (bindings); +} + +/* This is called at the point of a case or default label to issue + warnings about decls as needed. It returns true if it found an + error, not just a warning. */ + +bool +c_check_switch_jump_warnings (struct c_spot_bindings *switch_bindings, + location_t switch_loc, location_t case_loc) +{ + bool saw_error; + struct c_scope *scope; + + saw_error = false; + for (scope = current_scope; + scope != switch_bindings->scope; + scope = scope->outer) + { + struct c_binding *b; + + gcc_assert (scope != NULL); + + if (!scope->has_jump_unsafe_decl) + continue; + + for (b = scope->bindings; b != NULL; b = b->prev) + { + if (decl_jump_unsafe (b->decl)) + { + if (variably_modified_type_p (TREE_TYPE (b->decl), NULL_TREE)) + { + saw_error = true; + error_at (case_loc, + ("switch jumps into scope of identifier with " + "variably modified type")); + } + else + warning_at (case_loc, OPT_Wjump_misses_init, + "switch jumps over variable initialization"); + inform (switch_loc, "switch starts here"); + inform (DECL_SOURCE_LOCATION (b->decl), "%qD declared here", + b->decl); + } + } + } + + if (switch_bindings->stmt_exprs > 0) + { + saw_error = true; + error_at (case_loc, "switch jumps into statement expression"); + inform (switch_loc, "switch starts here"); + } + + return saw_error; +} + +/* Given NAME, an IDENTIFIER_NODE, + return the structure (or union or enum) definition for that name. + If THISLEVEL_ONLY is nonzero, searches only the current_scope. + CODE says which kind of type the caller wants; + it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE. + If PLOC is not NULL and this returns non-null, it sets *PLOC to the + location where the tag was defined. + If the wrong kind of type is found, an error is reported. */ + +static tree +lookup_tag (enum tree_code code, tree name, bool thislevel_only, + location_t *ploc) +{ + struct c_binding *b = I_TAG_BINDING (name); + bool thislevel = false; + + if (!b || !b->decl) + return NULL_TREE; + + /* We only care about whether it's in this level if + thislevel_only was set or it might be a type clash. */ + if (thislevel_only || TREE_CODE (b->decl) != code) + { + /* For our purposes, a tag in the external scope is the same as + a tag in the file scope. (Primarily relevant to Objective-C + and its builtin structure tags, which get pushed before the + file scope is created.) */ + if (B_IN_CURRENT_SCOPE (b) + || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) + thislevel = true; + } + + if (thislevel_only && !thislevel) + return NULL_TREE; + + if (TREE_CODE (b->decl) != code) + { + /* Definition isn't the kind we were looking for. */ + pending_invalid_xref = name; + pending_invalid_xref_location = input_location; + + /* If in the same binding level as a declaration as a tag + of a different type, this must not be allowed to + shadow that tag, so give the error immediately. + (For example, "struct foo; union foo;" is invalid.) */ + if (thislevel) + pending_xref_error (); + } + + if (ploc != NULL) + *ploc = b->locus; + + return b->decl; +} + +/* Return true if a definition exists for NAME with code CODE. */ + +bool +tag_exists_p (enum tree_code code, tree name) +{ + struct c_binding *b = I_TAG_BINDING (name); + + if (b == NULL || b->decl == NULL_TREE) + return false; + return TREE_CODE (b->decl) == code; +} + +/* Print an error message now + for a recent invalid struct, union or enum cross reference. + We don't print them immediately because they are not invalid + when used in the `struct foo;' construct for shadowing. */ + +void +pending_xref_error (void) +{ + if (pending_invalid_xref != NULL_TREE) + error_at (pending_invalid_xref_location, "%qE defined as wrong kind of tag", + pending_invalid_xref); + pending_invalid_xref = NULL_TREE; +} + + +/* Look up NAME in the current scope and its superiors + in the namespace of variables, functions and typedefs. + Return a ..._DECL node of some kind representing its definition, + or return NULL_TREE if it is undefined. */ + +tree +lookup_name (tree name) +{ + struct c_binding *b = I_SYMBOL_BINDING (name); + if (b && !b->invisible) + { + maybe_record_typedef_use (b->decl); + return b->decl; + } + return NULL_TREE; +} + +/* Similar to `lookup_name' but look only at the indicated scope. */ + +static tree +lookup_name_in_scope (tree name, struct c_scope *scope) +{ + struct c_binding *b; + + for (b = I_SYMBOL_BINDING (name); b; b = b->shadowed) + if (B_IN_SCOPE (b, scope)) + return b->decl; + return NULL_TREE; +} + +/* Look for the closest match for NAME within the currently valid + scopes. + + This finds the identifier with the lowest Levenshtein distance to + NAME. If there are multiple candidates with equal minimal distance, + the first one found is returned. Scopes are searched from innermost + outwards, and within a scope in reverse order of declaration, thus + benefiting candidates "near" to the current scope. + + The function also looks for similar macro names to NAME, since a + misspelled macro name will not be expanded, and hence looks like an + identifier to the C frontend. + + It also looks for start_typename keywords, to detect "singed" vs "signed" + typos. + + Use LOC for any deferred diagnostics. */ + +name_hint +lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) +{ + gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); + + /* First, try some well-known names in the C standard library, in case + the user forgot a #include. */ + const char *header_hint + = get_c_stdlib_header_for_name (IDENTIFIER_POINTER (name)); + + if (header_hint) + return name_hint (NULL, + new suggest_missing_header (loc, + IDENTIFIER_POINTER (name), + header_hint)); + + /* Only suggest names reserved for the implementation if NAME begins + with an underscore. */ + bool consider_implementation_names = (IDENTIFIER_POINTER (name)[0] == '_'); + + best_match bm (name); + + /* Look within currently valid scopes. */ + for (c_scope *scope = current_scope; scope; scope = scope->outer) + for (c_binding *binding = scope->bindings; binding; binding = binding->prev) + { + if (!binding->id || binding->invisible) + continue; + if (binding->decl == error_mark_node) + continue; + /* Don't use bindings from implicitly declared functions, + as they were likely misspellings themselves. */ + if (TREE_CODE (binding->decl) == FUNCTION_DECL) + if (C_DECL_IMPLICIT (binding->decl)) + continue; + /* Don't suggest names that are reserved for use by the + implementation, unless NAME began with an underscore. */ + if (!consider_implementation_names) + { + const char *suggestion_str = IDENTIFIER_POINTER (binding->id); + if (name_reserved_for_implementation_p (suggestion_str)) + continue; + } + switch (kind) + { + case FUZZY_LOOKUP_TYPENAME: + if (TREE_CODE (binding->decl) != TYPE_DECL) + continue; + break; + + case FUZZY_LOOKUP_FUNCTION_NAME: + if (TREE_CODE (binding->decl) != FUNCTION_DECL) + { + /* Allow function pointers. */ + if ((VAR_P (binding->decl) + || TREE_CODE (binding->decl) == PARM_DECL) + && TREE_CODE (TREE_TYPE (binding->decl)) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (TREE_TYPE (binding->decl))) + == FUNCTION_TYPE)) + break; + continue; + } + break; + + default: + break; + } + bm.consider (binding->id); + } + + /* Consider macros: if the user misspelled a macro name e.g. "SOME_MACRO" + as: + x = SOME_OTHER_MACRO (y); + then "SOME_OTHER_MACRO" will survive to the frontend and show up + as a misspelled identifier. + + Use the best distance so far so that a candidate is only set if + a macro is better than anything so far. This allows early rejection + (without calculating the edit distance) of macro names that must have + distance >= bm.get_best_distance (), and means that we only get a + non-NULL result for best_macro_match if it's better than any of + the identifiers already checked, which avoids needless creation + of identifiers for macro hashnodes. */ + best_macro_match bmm (name, bm.get_best_distance (), parse_in); + cpp_hashnode *best_macro = bmm.get_best_meaningful_candidate (); + /* If a macro is the closest so far to NAME, use it, creating an + identifier tree node for it. */ + if (best_macro) + { + const char *id = (const char *)best_macro->ident.str; + tree macro_as_identifier + = get_identifier_with_length (id, best_macro->ident.len); + bm.set_best_so_far (macro_as_identifier, + bmm.get_best_distance (), + bmm.get_best_candidate_length ()); + } + + /* Try the "start_typename" keywords to detect + "singed" vs "signed" typos. */ + if (kind == FUZZY_LOOKUP_TYPENAME) + { + for (unsigned i = 0; i < num_c_common_reswords; i++) + { + const c_common_resword *resword = &c_common_reswords[i]; + if (!c_keyword_starts_typename (resword->rid)) + continue; + tree resword_identifier = ridpointers [resword->rid]; + if (!resword_identifier) + continue; + gcc_assert (TREE_CODE (resword_identifier) == IDENTIFIER_NODE); + bm.consider (resword_identifier); + } + } + + tree best = bm.get_best_meaningful_candidate (); + if (best) + return name_hint (IDENTIFIER_POINTER (best), NULL); + else + return name_hint (NULL, NULL); +} + + +/* Handle the standard [[nodiscard]] attribute. */ + +static tree +handle_nodiscard_attribute (tree *node, tree name, tree /*args*/, + int /*flags*/, bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))) + warning_at (DECL_SOURCE_LOCATION (*node), + OPT_Wattributes, "%qE attribute applied to %qD with void " + "return type", name, *node); + } + else if (RECORD_OR_UNION_TYPE_P (*node) + || TREE_CODE (*node) == ENUMERAL_TYPE) + /* OK */; + else + { + pedwarn (input_location, + OPT_Wattributes, "%qE attribute can only be applied to " + "functions or to structure, union or enumeration types", name); + *no_add_attrs = true; + } + return NULL_TREE; +} +/* Table of supported standard (C2x) attributes. */ +const struct attribute_spec std_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, + affects_type_identity, handler, exclude } */ + { "deprecated", 0, 1, false, false, false, false, + handle_deprecated_attribute, NULL }, + { "fallthrough", 0, 0, false, false, false, false, + handle_fallthrough_attribute, NULL }, + { "maybe_unused", 0, 0, false, false, false, false, + handle_unused_attribute, NULL }, + { "nodiscard", 0, 1, false, false, false, false, + handle_nodiscard_attribute, NULL }, + { NULL, 0, 0, false, false, false, false, NULL, NULL } +}; + +/* Create the predefined scalar types of C, + and some nodes representing standard constants (0, 1, (void *) 0). + Initialize the global scope. + Make definitions for built-in primitive functions. */ + +void +c_init_decl_processing (void) +{ + location_t save_loc = input_location; + + /* Initialize reserved words for parser. */ + c_parse_init (); + + register_scoped_attributes (std_attribute_table, NULL); + + current_function_decl = NULL_TREE; + + gcc_obstack_init (&parser_obstack); + + /* Make the externals scope. */ + push_scope (); + external_scope = current_scope; + + /* Declarations from c_common_nodes_and_builtins must not be associated + with this input file, lest we get differences between using and not + using preprocessed headers. */ + input_location = BUILTINS_LOCATION; + + c_common_nodes_and_builtins (); + + /* In C, comparisons and TRUTH_* expressions have type int. */ + truthvalue_type_node = integer_type_node; + truthvalue_true_node = integer_one_node; + truthvalue_false_node = integer_zero_node; + + /* Even in C99, which has a real boolean type. */ + pushdecl (build_decl (UNKNOWN_LOCATION, TYPE_DECL, get_identifier ("_Bool"), + boolean_type_node)); + + input_location = save_loc; + + make_fname_decl = c_make_fname_decl; + start_fname_decls (); +} + +/* Create the VAR_DECL at LOC for __FUNCTION__ etc. ID is the name to + give the decl, NAME is the initialization string and TYPE_DEP + indicates whether NAME depended on the type of the function. As we + don't yet implement delayed emission of static data, we mark the + decl as emitted so it is not placed in the output. Anything using + it must therefore pull out the STRING_CST initializer directly. + FIXME. */ + +static tree +c_make_fname_decl (location_t loc, tree id, int type_dep) +{ + const char *name = fname_as_string (type_dep); + tree decl, type, init; + size_t length = strlen (name); + + type = build_array_type (char_type_node, + build_index_type (size_int (length))); + type = c_build_qualified_type (type, TYPE_QUAL_CONST); + + decl = build_decl (loc, VAR_DECL, id, type); + + TREE_STATIC (decl) = 1; + TREE_READONLY (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + + init = build_string (length + 1, name); + free (CONST_CAST (char *, name)); + TREE_TYPE (init) = type; + DECL_INITIAL (decl) = init; + + TREE_USED (decl) = 1; + + if (current_function_decl + /* For invalid programs like this: + + void foo() + const char* p = __FUNCTION__; + + the __FUNCTION__ is believed to appear in K&R style function + parameter declarator. In that case we still don't have + function_scope. */ + && current_function_scope) + { + DECL_CONTEXT (decl) = current_function_decl; + bind (id, decl, current_function_scope, + /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION); + } + + finish_decl (decl, loc, init, NULL_TREE, NULL_TREE); + + return decl; +} + +tree +c_builtin_function (tree decl) +{ + tree type = TREE_TYPE (decl); + tree id = DECL_NAME (decl); + + const char *name = IDENTIFIER_POINTER (id); + C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type); + + /* Should never be called on a symbol with a preexisting meaning. */ + gcc_assert (!I_SYMBOL_BINDING (id)); + + bind (id, decl, external_scope, /*invisible=*/true, /*nested=*/false, + UNKNOWN_LOCATION); + + /* Builtins in the implementation namespace are made visible without + needing to be explicitly declared. See push_file_scope. */ + if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1]))) + { + DECL_CHAIN (decl) = visible_builtins; + visible_builtins = decl; + } + + return decl; +} + +tree +c_builtin_function_ext_scope (tree decl) +{ + tree type = TREE_TYPE (decl); + tree id = DECL_NAME (decl); + + const char *name = IDENTIFIER_POINTER (id); + C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type); + + if (external_scope) + bind (id, decl, external_scope, /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); + + /* Builtins in the implementation namespace are made visible without + needing to be explicitly declared. See push_file_scope. */ + if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1]))) + { + DECL_CHAIN (decl) = visible_builtins; + visible_builtins = decl; + } + + return decl; +} + +/* Implement LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL. */ + +tree +c_simulate_builtin_function_decl (tree decl) +{ + tree type = TREE_TYPE (decl); + C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type); + return pushdecl (decl); +} + +/* Warn about attributes in a context where they are unused + (attribute-declarations, except for the "fallthrough" case, and + attributes on statements). */ + +void +c_warn_unused_attributes (tree attrs) +{ + for (tree t = attrs; t != NULL_TREE; t = TREE_CHAIN (t)) + if (get_attribute_namespace (t) == NULL_TREE) + /* The specifications of standard attributes mean this is a + constraint violation. */ + pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", + get_attribute_name (t)); + else if (!attribute_ignored_p (t)) + warning (OPT_Wattributes, "%qE attribute ignored", + get_attribute_name (t)); +} + +/* Warn for standard attributes being applied to a type that is not + being defined, where that is a constraint violation, and return a + list of attributes with them removed. */ + +tree +c_warn_type_attributes (tree attrs) +{ + tree *attr_ptr = &attrs; + while (*attr_ptr) + if (get_attribute_namespace (*attr_ptr) == NULL_TREE) + { + pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", + get_attribute_name (*attr_ptr)); + *attr_ptr = TREE_CHAIN (*attr_ptr); + } + else + attr_ptr = &TREE_CHAIN (*attr_ptr); + return attrs; +} + +/* Called when a declaration is seen that contains no names to declare. + If its type is a reference to a structure, union or enum inherited + from a containing scope, shadow that tag name for the current scope + with a forward reference. + If its type defines a new named structure or union + or defines an enum, it is valid but we need not do anything here. + Otherwise, it is an error. */ + +void +shadow_tag (const struct c_declspecs *declspecs) +{ + shadow_tag_warned (declspecs, 0); +} + +/* WARNED is 1 if we have done a pedwarn, 2 if we have done a warning, + but no pedwarn. */ +void +shadow_tag_warned (const struct c_declspecs *declspecs, int warned) +{ + bool found_tag = false; + + if (declspecs->type && !declspecs->default_int_p && !declspecs->typedef_p) + { + tree value = declspecs->type; + enum tree_code code = TREE_CODE (value); + + if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) + /* Used to test also that TYPE_SIZE (value) != 0. + That caused warning for `struct foo;' at top level in the file. */ + { + tree name = TYPE_NAME (value); + tree t; + + found_tag = true; + + if (declspecs->restrict_p) + { + error ("invalid use of %"); + warned = 1; + } + + if (name == NULL_TREE) + { + if (warned != 1 && code != ENUMERAL_TYPE) + /* Empty unnamed enum OK */ + { + pedwarn (input_location, 0, + "unnamed struct/union that defines no instances"); + warned = 1; + } + } + else if (declspecs->typespec_kind != ctsk_tagdef + && declspecs->typespec_kind != ctsk_tagfirstref + && declspecs->typespec_kind != ctsk_tagfirstref_attrs + && declspecs->storage_class != csc_none) + { + if (warned != 1) + pedwarn (input_location, 0, + "empty declaration with storage class specifier " + "does not redeclare tag"); + warned = 1; + pending_xref_error (); + } + else if (declspecs->typespec_kind != ctsk_tagdef + && declspecs->typespec_kind != ctsk_tagfirstref + && declspecs->typespec_kind != ctsk_tagfirstref_attrs + && (declspecs->const_p + || declspecs->volatile_p + || declspecs->atomic_p + || declspecs->restrict_p + || declspecs->address_space)) + { + if (warned != 1) + pedwarn (input_location, 0, + "empty declaration with type qualifier " + "does not redeclare tag"); + warned = 1; + pending_xref_error (); + } + else if (declspecs->typespec_kind != ctsk_tagdef + && declspecs->typespec_kind != ctsk_tagfirstref + && declspecs->typespec_kind != ctsk_tagfirstref_attrs + && declspecs->alignas_p) + { + if (warned != 1) + pedwarn (input_location, 0, + "empty declaration with %<_Alignas%> " + "does not redeclare tag"); + warned = 1; + pending_xref_error (); + } + else + { + pending_invalid_xref = NULL_TREE; + t = lookup_tag (code, name, true, NULL); + + if (t == NULL_TREE) + { + t = make_node (code); + pushtag (input_location, name, t); + } + } + } + else + { + if (warned != 1 && !in_system_header_at (input_location)) + { + pedwarn (input_location, 0, + "useless type name in empty declaration"); + warned = 1; + } + } + } + else if (warned != 1 && !in_system_header_at (input_location) + && declspecs->typedef_p) + { + pedwarn (input_location, 0, "useless type name in empty declaration"); + warned = 1; + } + + pending_invalid_xref = NULL_TREE; + + if (declspecs->inline_p) + { + error ("% in empty declaration"); + warned = 1; + } + + if (declspecs->noreturn_p) + { + error ("%<_Noreturn%> in empty declaration"); + warned = 1; + } + + if (current_scope == file_scope && declspecs->storage_class == csc_auto) + { + error ("% in file-scope empty declaration"); + warned = 1; + } + + if (current_scope == file_scope && declspecs->storage_class == csc_register) + { + error ("% in file-scope empty declaration"); + warned = 1; + } + + if (!warned && !in_system_header_at (input_location) + && declspecs->storage_class != csc_none) + { + warning (0, "useless storage class specifier in empty declaration"); + warned = 2; + } + + if (!warned && !in_system_header_at (input_location) && declspecs->thread_p) + { + warning (0, "useless %qs in empty declaration", + declspecs->thread_gnu_p ? "__thread" : "_Thread_local"); + warned = 2; + } + + if (!warned + && !in_system_header_at (input_location) + && (declspecs->const_p + || declspecs->volatile_p + || declspecs->atomic_p + || declspecs->restrict_p + || declspecs->address_space)) + { + warning (0, "useless type qualifier in empty declaration"); + warned = 2; + } + + if (!warned && !in_system_header_at (input_location) + && declspecs->alignas_p) + { + warning (0, "useless %<_Alignas%> in empty declaration"); + warned = 2; + } + + if (found_tag + && warned == 2 + && (declspecs->typespec_kind == ctsk_tagref_attrs + || declspecs->typespec_kind == ctsk_tagfirstref_attrs)) + { + /* Standard attributes after the "struct" or "union" keyword are + only permitted when the contents of the type are defined, or + in the form "struct-or-union attribute-specifier-sequence + identifier;". If the ';' was not present, attributes were + diagnosed in the parser. Here, ensure that any other useless + elements of the declaration result in a pedwarn, not just a + warning. Forward declarations of enum types are not part of + standard C, but handle them the same. */ + pedwarn (input_location, 0, + "invalid use of attributes in empty declaration"); + warned = 1; + } + + if (warned != 1) + { + if (declspecs->declspecs_seen_p + && !declspecs->non_std_attrs_seen_p) + /* An attribute declaration (but not a fallthrough attribute + declaration, which was handled separately); warn if there + are any attributes being ignored (but not if the attributes + were empty). */ + c_warn_unused_attributes (declspecs->attrs); + else if (!found_tag) + pedwarn (input_location, 0, "empty declaration"); + } +} + + +/* Return the qualifiers from SPECS as a bitwise OR of TYPE_QUAL_* + bits. SPECS represents declaration specifiers that the grammar + only permits to contain type qualifiers and attributes. */ + +int +quals_from_declspecs (const struct c_declspecs *specs) +{ + int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0) + | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0) + | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0) + | (specs->atomic_p ? TYPE_QUAL_ATOMIC : 0) + | (ENCODE_QUAL_ADDR_SPACE (specs->address_space))); + gcc_assert (!specs->type + && !specs->decl_attr + && specs->typespec_word == cts_none + && specs->storage_class == csc_none + && !specs->typedef_p + && !specs->explicit_signed_p + && !specs->deprecated_p + && !specs->unavailable_p + && !specs->long_p + && !specs->long_long_p + && !specs->short_p + && !specs->signed_p + && !specs->unsigned_p + && !specs->complex_p + && !specs->inline_p + && !specs->noreturn_p + && !specs->thread_p); + return quals; +} + +/* Construct an array declarator. LOC is the location of the + beginning of the array (usually the opening brace). EXPR is the + expression inside [], or NULL_TREE. QUALS are the type qualifiers + inside the [] (to be applied to the pointer to which a parameter + array is converted). STATIC_P is true if "static" is inside the + [], false otherwise. VLA_UNSPEC_P is true if the array is [*], a + VLA of unspecified length which is nevertheless a complete type, + false otherwise. The field for the contained declarator is left to + be filled in by set_array_declarator_inner. */ + +struct c_declarator * +build_array_declarator (location_t loc, + tree expr, struct c_declspecs *quals, bool static_p, + bool vla_unspec_p) +{ + struct c_declarator *declarator = XOBNEW (&parser_obstack, + struct c_declarator); + declarator->id_loc = loc; + declarator->kind = cdk_array; + declarator->declarator = 0; + declarator->u.array.dimen = expr; + if (quals) + { + declarator->u.array.attrs = quals->attrs; + declarator->u.array.quals = quals_from_declspecs (quals); + } + else + { + declarator->u.array.attrs = NULL_TREE; + declarator->u.array.quals = 0; + } + declarator->u.array.static_p = static_p; + declarator->u.array.vla_unspec_p = vla_unspec_p; + if (static_p || quals != NULL) + pedwarn_c90 (loc, OPT_Wpedantic, + "ISO C90 does not support % or type " + "qualifiers in parameter array declarators"); + if (vla_unspec_p) + pedwarn_c90 (loc, OPT_Wpedantic, + "ISO C90 does not support %<[*]%> array declarators"); + if (vla_unspec_p) + { + if (!current_scope->parm_flag) + { + /* C99 6.7.5.2p4 */ + error_at (loc, "%<[*]%> not allowed in other than " + "function prototype scope"); + declarator->u.array.vla_unspec_p = false; + return NULL; + } + current_scope->had_vla_unspec = true; + } + return declarator; +} + +/* Set the contained declarator of an array declarator. DECL is the + declarator, as constructed by build_array_declarator; INNER is what + appears on the left of the []. */ + +struct c_declarator * +set_array_declarator_inner (struct c_declarator *decl, + struct c_declarator *inner) +{ + decl->declarator = inner; + return decl; +} + +/* INIT is a constructor that forms DECL's initializer. If the final + element initializes a flexible array field, add the size of that + initializer to DECL's size. */ + +static void +add_flexible_array_elts_to_size (tree decl, tree init) +{ + tree elt, type; + + if (vec_safe_is_empty (CONSTRUCTOR_ELTS (init))) + return; + + elt = CONSTRUCTOR_ELTS (init)->last ().value; + type = TREE_TYPE (elt); + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_SIZE (type) == NULL_TREE + && TYPE_DOMAIN (type) != NULL_TREE + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE) + { + complete_array_type (&type, elt, false); + DECL_SIZE (decl) + = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type)); + DECL_SIZE_UNIT (decl) + = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type)); + } +} + +/* Decode a "typename", such as "int **", returning a ..._TYPE node. + Set *EXPR, if EXPR not NULL, to any expression to be evaluated + before the type name, and set *EXPR_CONST_OPERANDS, if + EXPR_CONST_OPERANDS not NULL, to indicate whether the type name may + appear in a constant expression. */ + +tree +groktypename (struct c_type_name *type_name, tree *expr, + bool *expr_const_operands) +{ + tree type; + tree attrs = type_name->specs->attrs; + + type_name->specs->attrs = NULL_TREE; + + type = grokdeclarator (type_name->declarator, type_name->specs, TYPENAME, + false, NULL, &attrs, expr, expr_const_operands, + DEPRECATED_NORMAL); + + /* Apply attributes. */ + attrs = c_warn_type_attributes (attrs); + decl_attributes (&type, attrs, 0); + + return type; +} + +/* Looks up the most recent pushed declaration corresponding to DECL. */ + +static tree +lookup_last_decl (tree decl) +{ + tree last_decl = lookup_name (DECL_NAME (decl)); + if (!last_decl) + last_decl = lookup_name_in_scope (DECL_NAME (decl), external_scope); + return last_decl; +} + +/* Wrapper for decl_attributes that adds some implicit attributes + to VAR_DECLs or FUNCTION_DECLs. */ + +static tree +c_decl_attributes (tree *node, tree attributes, int flags) +{ + /* Add implicit "omp declare target" attribute if requested. */ + if (current_omp_declare_target_attribute + && ((VAR_P (*node) && is_global_var (*node)) + || TREE_CODE (*node) == FUNCTION_DECL)) + { + if (VAR_P (*node) + && !lang_hooks.types.omp_mappable_type (TREE_TYPE (*node))) + attributes = tree_cons (get_identifier ("omp declare target implicit"), + NULL_TREE, attributes); + else + { + attributes = tree_cons (get_identifier ("omp declare target"), + NULL_TREE, attributes); + attributes = tree_cons (get_identifier ("omp declare target block"), + NULL_TREE, attributes); + } + } + + /* Look up the current declaration with all the attributes merged + so far so that attributes on the current declaration that's + about to be pushed that conflict with the former can be detected, + diagnosed, and rejected as appropriate. */ + tree last_decl = lookup_last_decl (*node); + return decl_attributes (node, attributes, flags, last_decl); +} + + +/* Decode a declarator in an ordinary declaration or data definition. + This is called as soon as the type information and variable name + have been parsed, before parsing the initializer if any. + Here we create the ..._DECL node, fill in its type, + and put it on the list of decls for the current context. + When nonnull, set *LASTLOC to the location of the prior declaration + of the same entity if one exists. + The ..._DECL node is returned as the value. + + Exception: for arrays where the length is not specified, + the type is left null, to be filled in by `finish_decl'. + + Function definitions do not come here; they go to start_function + instead. However, external and forward declarations of functions + do go through here. Structure field declarations are done by + grokfield and not through here. */ + +tree +start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, + bool initialized, tree attributes, location_t *lastloc /* = NULL */) +{ + tree decl; + tree tem; + tree expr = NULL_TREE; + enum deprecated_states deprecated_state = DEPRECATED_NORMAL; + + /* An object declared as __attribute__((unavailable)) suppresses + warnings and errors from __attribute__((deprecated/unavailable)) + components. + An object declared as __attribute__((deprecated)) suppresses + warnings of uses of other deprecated items. */ + if (lookup_attribute ("unavailable", attributes)) + deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS; + else if (lookup_attribute ("deprecated", attributes)) + deprecated_state = DEPRECATED_SUPPRESS; + + decl = grokdeclarator (declarator, declspecs, + NORMAL, initialized, NULL, &attributes, &expr, NULL, + deprecated_state); + if (!decl || decl == error_mark_node) + return NULL_TREE; + + if (tree lastdecl = lastloc ? lookup_last_decl (decl) : NULL_TREE) + if (lastdecl != error_mark_node) + *lastloc = DECL_SOURCE_LOCATION (lastdecl); + + if (expr) + add_stmt (fold_convert (void_type_node, expr)); + + if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl)) + && TREE_PUBLIC (decl)) + warning (OPT_Wmain, "%q+D is usually a function", decl); + + if (initialized) + /* Is it valid for this decl to have an initializer at all? + If not, set INITIALIZED to zero, which will indirectly + tell 'finish_decl' to ignore the initializer once it is parsed. */ + switch (TREE_CODE (decl)) + { + case TYPE_DECL: + error ("typedef %qD is initialized (use %<__typeof__%> instead)", decl); + initialized = false; + break; + + case FUNCTION_DECL: + error ("function %qD is initialized like a variable", decl); + initialized = false; + break; + + case PARM_DECL: + /* DECL_INITIAL in a PARM_DECL is really DECL_ARG_TYPE. */ + error ("parameter %qD is initialized", decl); + initialized = false; + break; + + default: + /* Don't allow initializations for incomplete types except for + arrays which might be completed by the initialization. */ + + /* This can happen if the array size is an undefined macro. + We already gave a warning, so we don't need another one. */ + if (TREE_TYPE (decl) == error_mark_node) + initialized = false; + else if (COMPLETE_TYPE_P (TREE_TYPE (decl))) + { + /* A complete type is ok if size is fixed. */ + + if (!poly_int_tree_p (TYPE_SIZE (TREE_TYPE (decl))) + || C_DECL_VARIABLE_SIZE (decl)) + { + error ("variable-sized object may not be initialized"); + initialized = false; + } + } + else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) + { + error ("variable %qD has initializer but incomplete type", decl); + initialized = false; + } + else if (C_DECL_VARIABLE_SIZE (decl)) + { + /* Although C99 is unclear about whether incomplete arrays + of VLAs themselves count as VLAs, it does not make + sense to permit them to be initialized given that + ordinary VLAs may not be initialized. */ + error ("variable-sized object may not be initialized"); + initialized = false; + } + } + + if (initialized) + { + if (current_scope == file_scope) + TREE_STATIC (decl) = 1; + + /* Tell 'pushdecl' this is an initialized decl + even though we don't yet have the initializer expression. + Also tell 'finish_decl' it may store the real initializer. */ + DECL_INITIAL (decl) = error_mark_node; + } + + /* If this is a function declaration, write a record describing it to the + prototypes file (if requested). */ + + if (TREE_CODE (decl) == FUNCTION_DECL) + gen_aux_info_record (decl, 0, 0, prototype_p (TREE_TYPE (decl))); + + /* ANSI specifies that a tentative definition which is not merged with + a non-tentative definition behaves exactly like a definition with an + initializer equal to zero. (Section 3.7.2) + + -fno-common gives strict ANSI behavior, though this tends to break + a large body of code that grew up without this rule. + + Thread-local variables are never common, since there's no entrenched + body of code to break, and it allows more efficient variable references + in the presence of dynamic linking. */ + + if (VAR_P (decl) + && !initialized + && TREE_PUBLIC (decl) + && !DECL_THREAD_LOCAL_P (decl) + && !flag_no_common) + DECL_COMMON (decl) = 1; + + /* Set attributes here so if duplicate decl, will have proper attributes. */ + c_decl_attributes (&decl, attributes, 0); + + /* Handle gnu_inline attribute. */ + if (declspecs->inline_p + && !flag_gnu89_inline + && TREE_CODE (decl) == FUNCTION_DECL + && (lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl)) + || current_function_decl)) + { + if (declspecs->storage_class == csc_auto && current_scope != file_scope) + ; + else if (declspecs->storage_class != csc_static) + DECL_EXTERNAL (decl) = !DECL_EXTERNAL (decl); + } + + if (TREE_CODE (decl) == FUNCTION_DECL + && targetm.calls.promote_prototypes (TREE_TYPE (decl))) + { + struct c_declarator *ce = declarator; + + if (ce->kind == cdk_pointer) + ce = declarator->declarator; + if (ce->kind == cdk_function) + { + tree args = ce->u.arg_info->parms; + for (; args; args = DECL_CHAIN (args)) + { + tree type = TREE_TYPE (args); + if (type && INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (args) = c_type_promotes_to (type); + } + } + } + + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (decl) + && DECL_UNINLINABLE (decl) + && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl))) + warning (OPT_Wattributes, "inline function %q+D given attribute %qs", + decl, "noinline"); + + /* C99 6.7.4p3: An inline definition of a function with external + linkage shall not contain a definition of a modifiable object + with static storage duration... */ + if (VAR_P (decl) + && current_scope != file_scope + && TREE_STATIC (decl) + && !TREE_READONLY (decl) + && DECL_DECLARED_INLINE_P (current_function_decl) + && DECL_EXTERNAL (current_function_decl)) + record_inline_static (input_location, current_function_decl, + decl, csi_modifiable); + + if (c_dialect_objc () + && VAR_OR_FUNCTION_DECL_P (decl)) + objc_check_global_decl (decl); + + /* Add this decl to the current scope. + TEM may equal DECL or it may be a previous decl of the same name. */ + tem = pushdecl (decl); + + if (initialized && DECL_EXTERNAL (tem)) + { + DECL_EXTERNAL (tem) = 0; + TREE_STATIC (tem) = 1; + } + + return tem; +} + +/* Subroutine of finish_decl. TYPE is the type of an uninitialized object + DECL or the non-array element type if DECL is an uninitialized array. + If that type has a const member, diagnose this. */ + +static void +diagnose_uninitialized_cst_member (tree decl, tree type) +{ + tree field; + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + tree field_type; + if (TREE_CODE (field) != FIELD_DECL) + continue; + field_type = strip_array_types (TREE_TYPE (field)); + + if (TYPE_QUALS (field_type) & TYPE_QUAL_CONST) + { + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, + "uninitialized const member in %qT is invalid in C++", + strip_array_types (TREE_TYPE (decl))); + inform (DECL_SOURCE_LOCATION (field), "%qD should be initialized", field); + } + + if (RECORD_OR_UNION_TYPE_P (field_type)) + diagnose_uninitialized_cst_member (decl, field_type); + } +} + +/* Finish processing of a declaration; + install its initial value. + If ORIGTYPE is not NULL_TREE, it is the original type of INIT. + If the length of an array type is not known before, + it must be determined now, from the initial value, or it is an error. + + INIT_LOC is the location of the initial value. */ + +void +finish_decl (tree decl, location_t init_loc, tree init, + tree origtype, tree asmspec_tree) +{ + tree type; + bool was_incomplete = (DECL_SIZE (decl) == NULL_TREE); + const char *asmspec = 0; + + /* If a name was specified, get the string. */ + if (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_FILE_SCOPE_P (decl)) + asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree); + if (asmspec_tree) + asmspec = TREE_STRING_POINTER (asmspec_tree); + + if (VAR_P (decl) + && TREE_STATIC (decl) + && global_bindings_p ()) + /* So decl is a global variable. Record the types it uses + so that we can decide later to emit debug info for them. */ + record_types_used_by_current_var_decl (decl); + + /* If `start_decl' didn't like having an initialization, ignore it now. */ + if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE) + init = NULL_TREE; + + /* Don't crash if parm is initialized. */ + if (TREE_CODE (decl) == PARM_DECL) + init = NULL_TREE; + + if (init) + store_init_value (init_loc, decl, init, origtype); + + if (c_dialect_objc () && (VAR_OR_FUNCTION_DECL_P (decl) + || TREE_CODE (decl) == FIELD_DECL)) + objc_check_decl (decl); + + type = TREE_TYPE (decl); + + /* Deduce size of array from initialization, if not already known. + This is only needed for an initialization in the current scope; + it must not be done for a file-scope initialization of a + declaration with external linkage, redeclared in an inner scope + with the outer declaration shadowed in an intermediate scope. */ + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) == NULL_TREE + && TREE_CODE (decl) != TYPE_DECL + && !(TREE_PUBLIC (decl) && current_scope != file_scope)) + { + bool do_default + = (TREE_STATIC (decl) + /* Even if pedantic, an external linkage array + may have incomplete type at first. */ + ? pedantic && !TREE_PUBLIC (decl) + : !DECL_EXTERNAL (decl)); + int failure + = complete_array_type (&TREE_TYPE (decl), DECL_INITIAL (decl), + do_default); + + /* Get the completed type made by complete_array_type. */ + type = TREE_TYPE (decl); + + switch (failure) + { + case 1: + error ("initializer fails to determine size of %q+D", decl); + break; + + case 2: + if (do_default) + error ("array size missing in %q+D", decl); + break; + + case 3: + error ("zero or negative size array %q+D", decl); + break; + + case 0: + /* For global variables, update the copy of the type that + exists in the binding. */ + if (TREE_PUBLIC (decl)) + { + struct c_binding *b_ext = I_SYMBOL_BINDING (DECL_NAME (decl)); + while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext)) + b_ext = b_ext->shadowed; + if (b_ext && TREE_CODE (decl) == TREE_CODE (b_ext->decl)) + { + if (b_ext->u.type && comptypes (b_ext->u.type, type)) + b_ext->u.type = composite_type (b_ext->u.type, type); + else + b_ext->u.type = type; + } + } + break; + + default: + gcc_unreachable (); + } + + if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node) + TREE_TYPE (DECL_INITIAL (decl)) = type; + + relayout_decl (decl); + } + + /* Look for braced array initializers for character arrays and + recursively convert them into STRING_CSTs. */ + if (tree init = DECL_INITIAL (decl)) + DECL_INITIAL (decl) = braced_lists_to_strings (type, init); + + if (VAR_P (decl)) + { + if (init && TREE_CODE (init) == CONSTRUCTOR) + add_flexible_array_elts_to_size (decl, init); + + complete_flexible_array_elts (DECL_INITIAL (decl)); + + if (is_global_var (decl)) + { + type_context_kind context = (DECL_THREAD_LOCAL_P (decl) + ? TCTX_THREAD_STORAGE + : TCTX_STATIC_STORAGE); + if (!verify_type_context (input_location, context, TREE_TYPE (decl))) + TREE_TYPE (decl) = error_mark_node; + } + + if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node + && COMPLETE_TYPE_P (TREE_TYPE (decl))) + layout_decl (decl, 0); + + if (DECL_SIZE (decl) == NULL_TREE + /* Don't give an error if we already gave one earlier. */ + && TREE_TYPE (decl) != error_mark_node + && (TREE_STATIC (decl) + /* A static variable with an incomplete type + is an error if it is initialized. + Also if it is not file scope. + Otherwise, let it through, but if it is not `extern' + then it may cause an error message later. */ + ? (DECL_INITIAL (decl) != NULL_TREE + || !DECL_FILE_SCOPE_P (decl)) + /* An automatic variable with an incomplete type + is an error. */ + : !DECL_EXTERNAL (decl))) + { + error ("storage size of %q+D isn%'t known", decl); + TREE_TYPE (decl) = error_mark_node; + } + + if ((RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)) + || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) + && DECL_SIZE (decl) == NULL_TREE + && TREE_STATIC (decl)) + incomplete_record_decls.safe_push (decl); + + if (is_global_var (decl) + && DECL_SIZE (decl) != NULL_TREE + && TREE_TYPE (decl) != error_mark_node) + { + if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) + constant_expression_warning (DECL_SIZE (decl)); + else + { + error ("storage size of %q+D isn%'t constant", decl); + TREE_TYPE (decl) = error_mark_node; + } + } + + if (TREE_USED (type)) + { + TREE_USED (decl) = 1; + DECL_READ_P (decl) = 1; + } + } + + /* If this is a function and an assembler name is specified, reset DECL_RTL + so we can give it its new name. Also, update builtin_decl if it + was a normal built-in. */ + if (TREE_CODE (decl) == FUNCTION_DECL && asmspec) + { + if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL) + set_builtin_user_assembler_name (decl, asmspec); + set_user_assembler_name (decl, asmspec); + } + + /* If #pragma weak was used, mark the decl weak now. */ + maybe_apply_pragma_weak (decl); + + /* Output the assembler code and/or RTL code for variables and functions, + unless the type is an undefined structure or union. + If not, it will get done when the type is completed. */ + + if (VAR_OR_FUNCTION_DECL_P (decl)) + { + /* Determine the ELF visibility. */ + if (TREE_PUBLIC (decl)) + c_determine_visibility (decl); + + /* This is a no-op in c-lang.c or something real in objc-act.c. */ + if (c_dialect_objc ()) + objc_check_decl (decl); + + if (asmspec) + { + /* If this is not a static variable, issue a warning. + It doesn't make any sense to give an ASMSPEC for an + ordinary, non-register local variable. Historically, + GCC has accepted -- but ignored -- the ASMSPEC in + this case. */ + if (!DECL_FILE_SCOPE_P (decl) + && VAR_P (decl) + && !C_DECL_REGISTER (decl) + && !TREE_STATIC (decl)) + warning (0, "ignoring % specifier for non-static local " + "variable %q+D", decl); + else + set_user_assembler_name (decl, asmspec); + } + + if (DECL_FILE_SCOPE_P (decl)) + { + if (DECL_INITIAL (decl) == NULL_TREE + || DECL_INITIAL (decl) == error_mark_node) + /* Don't output anything + when a tentative file-scope definition is seen. + But at end of compilation, do output code for them. */ + DECL_DEFER_OUTPUT (decl) = 1; + if (asmspec && VAR_P (decl) && C_DECL_REGISTER (decl)) + DECL_HARD_REGISTER (decl) = 1; + rest_of_decl_compilation (decl, true, 0); + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + tree parms = DECL_ARGUMENTS (decl); + const bool builtin = fndecl_built_in_p (decl); + if (tree access = build_attr_access_from_parms (parms, !builtin)) + decl_attributes (&decl, access, 0); + } + } + else + { + /* In conjunction with an ASMSPEC, the `register' + keyword indicates that we should place the variable + in a particular register. */ + if (asmspec && C_DECL_REGISTER (decl)) + { + DECL_HARD_REGISTER (decl) = 1; + /* This cannot be done for a structure with volatile + fields, on which DECL_REGISTER will have been + reset. */ + if (!DECL_REGISTER (decl)) + error ("cannot put object with volatile field into register"); + } + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + /* If we're building a variable sized type, and we might be + reachable other than via the top of the current binding + level, then create a new BIND_EXPR so that we deallocate + the object at the right time. */ + /* Note that DECL_SIZE can be null due to errors. */ + if (DECL_SIZE (decl) + && !TREE_CONSTANT (DECL_SIZE (decl)) + && STATEMENT_LIST_HAS_LABEL (cur_stmt_list)) + { + tree bind; + bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); + TREE_SIDE_EFFECTS (bind) = 1; + add_stmt (bind); + BIND_EXPR_BODY (bind) = push_stmt_list (); + } + add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), + DECL_EXPR, decl)); + } + } + + + if (!DECL_FILE_SCOPE_P (decl)) + { + /* Recompute the RTL of a local array now + if it used to be an incomplete type. */ + if (was_incomplete && !is_global_var (decl)) + { + /* If we used it already as memory, it must stay in memory. */ + TREE_ADDRESSABLE (decl) = TREE_USED (decl); + /* If it's still incomplete now, no init will save it. */ + if (DECL_SIZE (decl) == NULL_TREE) + DECL_INITIAL (decl) = NULL_TREE; + } + } + } + + if (TREE_CODE (decl) == TYPE_DECL) + { + if (!DECL_FILE_SCOPE_P (decl) + && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); + + rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0); + } + + /* Install a cleanup (aka destructor) if one was given. */ + if (VAR_P (decl) && !TREE_STATIC (decl)) + { + tree attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl)); + if (attr) + { + tree cleanup_id = TREE_VALUE (TREE_VALUE (attr)); + tree cleanup_decl = lookup_name (cleanup_id); + tree cleanup; + vec *v; + + /* Build "cleanup(&decl)" for the destructor. */ + cleanup = build_unary_op (input_location, ADDR_EXPR, decl, false); + vec_alloc (v, 1); + v->quick_push (cleanup); + cleanup = c_build_function_call_vec (DECL_SOURCE_LOCATION (decl), + vNULL, cleanup_decl, v, NULL); + vec_free (v); + + /* Don't warn about decl unused; the cleanup uses it. */ + TREE_USED (decl) = 1; + TREE_USED (cleanup_decl) = 1; + DECL_READ_P (decl) = 1; + + push_cleanup (decl, cleanup, false); + } + } + + if (warn_cxx_compat + && VAR_P (decl) + && !DECL_EXTERNAL (decl) + && DECL_INITIAL (decl) == NULL_TREE) + { + type = strip_array_types (type); + if (TREE_READONLY (decl)) + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, + "uninitialized % is invalid in C++", decl); + else if (RECORD_OR_UNION_TYPE_P (type) + && C_TYPE_FIELDS_READONLY (type)) + diagnose_uninitialized_cst_member (decl, type); + } + + if (flag_openmp + && VAR_P (decl) + && lookup_attribute ("omp declare target implicit", + DECL_ATTRIBUTES (decl))) + { + DECL_ATTRIBUTES (decl) + = remove_attribute ("omp declare target implicit", + DECL_ATTRIBUTES (decl)); + if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (decl))) + error ("%q+D in declare target directive does not have mappable type", + decl); + else if (!lookup_attribute ("omp declare target", + DECL_ATTRIBUTES (decl)) + && !lookup_attribute ("omp declare target link", + DECL_ATTRIBUTES (decl))) + { + DECL_ATTRIBUTES (decl) + = tree_cons (get_identifier ("omp declare target"), + NULL_TREE, DECL_ATTRIBUTES (decl)); + symtab_node *node = symtab_node::get (decl); + if (node != NULL) + { + node->offloadable = 1; + if (ENABLE_OFFLOADING) + { + g->have_offload = true; + if (is_a (node)) + vec_safe_push (offload_vars, decl); + } + } + } + } + + /* This is the last point we can lower alignment so give the target the + chance to do so. */ + if (VAR_P (decl) + && !is_global_var (decl) + && !DECL_HARD_REGISTER (decl)) + targetm.lower_local_decl_alignment (decl); + + invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); +} + +/* Given a parsed parameter declaration, decode it into a PARM_DECL. + EXPR is NULL or a pointer to an expression that needs to be + evaluated for the side effects of array size expressions in the + parameters. */ + +tree +grokparm (const struct c_parm *parm, tree *expr) +{ + tree attrs = parm->attrs; + tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, + NULL, &attrs, expr, NULL, DEPRECATED_NORMAL); + + decl_attributes (&decl, attrs, 0); + + return decl; +} + +/* Return attribute "arg spec" corresponding to an array/VLA parameter + described by PARM, concatenated onto attributes ATTRS. + The spec consists of one dollar symbol for each specified variable + bound, one asterisk for each unspecified variable bound, followed + by at most one specification of the most significant bound of + an ordinary array parameter. For ordinary arrays the specification + is either the constant bound itself, or the space character for + an array with an unspecified bound (the [] form). Finally, a chain + of specified variable bounds is appended to the spec, starting with + the most significant bound. For example, the PARM T a[2][m][3][n] + will produce __attribute__((arg spec ("[$$2]", m, n)). + For T a typedef for an array with variable bounds, the bounds are + included in the specification in the expected order. + No "arg spec" is created for parameters of pointer types, making + a distinction between T(*)[N] (or, equivalently, T[][N]) and + the T[M][N] form, all of which have the same type and are represented + the same, but only the last of which gets an "arg spec" describing + the most significant bound M. */ + +static tree +get_parm_array_spec (const struct c_parm *parm, tree attrs) +{ + /* The attribute specification string, minor bound first. */ + std::string spec; + + /* A list of VLA variable bounds, major first, or null if unspecified + or not a VLA. */ + tree vbchain = NULL_TREE; + /* True for a pointer parameter. */ + bool pointer = false; + /* True for an ordinary array with an unpecified bound. */ + bool nobound = false; + + /* Create a string representation for the bounds of the array/VLA. */ + for (c_declarator *pd = parm->declarator, *next; pd; pd = next) + { + next = pd->declarator; + while (next && next->kind == cdk_attrs) + next = next->declarator; + + /* Remember if a pointer has been seen to avoid storing the constant + bound. */ + if (pd->kind == cdk_pointer) + pointer = true; + + if ((pd->kind == cdk_pointer || pd->kind == cdk_function) + && (!next || next->kind == cdk_id)) + { + /* Do nothing for the common case of a pointer. The fact that + the parameter is one can be deduced from the absence of + an arg spec for it. */ + return attrs; + } + + if (pd->kind == cdk_id) + { + if (pointer + || !parm->specs->type + || TREE_CODE (parm->specs->type) != ARRAY_TYPE + || !TYPE_DOMAIN (parm->specs->type) + || !TYPE_MAX_VALUE (TYPE_DOMAIN (parm->specs->type))) + continue; + + tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (parm->specs->type)); + if (!vbchain + && TREE_CODE (max) == INTEGER_CST) + { + /* Extract the upper bound from a parameter of an array type + unless the parameter is an ordinary array of unspecified + bound in which case a next iteration of the loop will + exit. */ + if (spec.empty () || spec.end ()[-1] != ' ') + { + if (!tree_fits_shwi_p (max)) + continue; + + /* The upper bound is the value of the largest valid + index. */ + HOST_WIDE_INT n = tree_to_shwi (max) + 1; + char buf[40]; + sprintf (buf, "%lu", (unsigned long)n); + spec += buf; + } + continue; + } + + /* For a VLA typedef, create a list of its variable bounds and + append it in the expected order to VBCHAIN. */ + tree tpbnds = NULL_TREE; + for (tree type = parm->specs->type; TREE_CODE (type) == ARRAY_TYPE; + type = TREE_TYPE (type)) + { + tree nelts = array_type_nelts (type); + if (error_operand_p (nelts)) + return attrs; + if (TREE_CODE (nelts) != INTEGER_CST) + { + /* Each variable VLA bound is represented by the dollar + sign. */ + spec += "$"; + tpbnds = tree_cons (NULL_TREE, nelts, tpbnds); + } + } + tpbnds = nreverse (tpbnds); + vbchain = chainon (vbchain, tpbnds); + continue; + } + + if (pd->kind != cdk_array) + continue; + + if (pd->u.array.vla_unspec_p) + { + /* Each unspecified bound is represented by a star. There + can be any number of these in a declaration (but none in + a definition). */ + spec += '*'; + continue; + } + + tree nelts = pd->u.array.dimen; + if (!nelts) + { + /* Ordinary array of unspecified size. There can be at most + one for the most significant bound. Exit on the next + iteration which determines whether or not PARM is declared + as a pointer or an array. */ + nobound = true; + continue; + } + + if (pd->u.array.static_p) + spec += 's'; + + if (!INTEGRAL_TYPE_P (TREE_TYPE (nelts))) + /* Avoid invalid NELTS. */ + return attrs; + + STRIP_NOPS (nelts); + nelts = c_fully_fold (nelts, false, nullptr); + if (TREE_CODE (nelts) == INTEGER_CST) + { + /* Skip all constant bounds except the most significant one. + The interior ones are included in the array type. */ + if (next && (next->kind == cdk_array || next->kind == cdk_pointer)) + continue; + + if (!tree_fits_uhwi_p (nelts)) + /* Bail completely on invalid bounds. */ + return attrs; + + char buf[40]; + unsigned HOST_WIDE_INT n = tree_to_uhwi (nelts); + sprintf (buf, "%llu", (unsigned long long)n); + spec += buf; + break; + } + + /* Each variable VLA bound is represented by a dollar sign. */ + spec += "$"; + vbchain = tree_cons (NULL_TREE, nelts, vbchain); + } + + if (spec.empty () && !nobound) + return attrs; + + spec.insert (0, "["); + if (nobound) + /* Ordinary array of unspecified bound is represented by a space. + It must be last in the spec. */ + spec += ' '; + spec += ']'; + + tree acsstr = build_string (spec.length () + 1, spec.c_str ()); + tree args = tree_cons (NULL_TREE, acsstr, vbchain); + tree name = get_identifier ("arg spec"); + return tree_cons (name, args, attrs); +} + +/* Given a parsed parameter declaration, decode it into a PARM_DECL + and push that on the current scope. EXPR is a pointer to an + expression that needs to be evaluated for the side effects of array + size expressions in the parameters. */ + +void +push_parm_decl (const struct c_parm *parm, tree *expr) +{ + tree attrs = parm->attrs; + tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL, + &attrs, expr, NULL, DEPRECATED_NORMAL); + if (decl && DECL_P (decl)) + DECL_SOURCE_LOCATION (decl) = parm->loc; + + attrs = get_parm_array_spec (parm, attrs); + decl_attributes (&decl, attrs, 0); + + decl = pushdecl (decl); + + finish_decl (decl, input_location, NULL_TREE, NULL_TREE, NULL_TREE); +} + +/* Mark all the parameter declarations to date as forward decls. + Also diagnose use of this extension. */ + +void +mark_forward_parm_decls (void) +{ + struct c_binding *b; + + if (pedantic && !current_scope->warned_forward_parm_decls) + { + pedwarn (input_location, OPT_Wpedantic, + "ISO C forbids forward parameter declarations"); + current_scope->warned_forward_parm_decls = true; + } + + for (b = current_scope->bindings; b; b = b->prev) + if (TREE_CODE (b->decl) == PARM_DECL) + TREE_ASM_WRITTEN (b->decl) = 1; +} + +/* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound + literal, which may be an incomplete array type completed by the + initializer; INIT is a CONSTRUCTOR at LOC that initializes the compound + literal. NON_CONST is true if the initializers contain something + that cannot occur in a constant expression. If ALIGNAS_ALIGN is nonzero, + it is the (valid) alignment for this compound literal, as specified + with _Alignas. */ + +tree +build_compound_literal (location_t loc, tree type, tree init, bool non_const, + unsigned int alignas_align) +{ + /* We do not use start_decl here because we have a type, not a declarator; + and do not use finish_decl because the decl should be stored inside + the COMPOUND_LITERAL_EXPR rather than added elsewhere as a DECL_EXPR. */ + tree decl; + tree complit; + tree stmt; + + if (type == error_mark_node + || init == error_mark_node) + return error_mark_node; + + decl = build_decl (loc, VAR_DECL, NULL_TREE, type); + DECL_EXTERNAL (decl) = 0; + TREE_PUBLIC (decl) = 0; + TREE_STATIC (decl) = (current_scope == file_scope); + DECL_CONTEXT (decl) = current_function_decl; + TREE_USED (decl) = 1; + DECL_READ_P (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + C_DECL_COMPOUND_LITERAL_P (decl) = 1; + TREE_TYPE (decl) = type; + c_apply_type_quals_to_decl (TYPE_QUALS (strip_array_types (type)), decl); + if (alignas_align) + { + SET_DECL_ALIGN (decl, alignas_align * BITS_PER_UNIT); + DECL_USER_ALIGN (decl) = 1; + } + store_init_value (loc, decl, init, NULL_TREE); + + if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type)) + { + int failure = complete_array_type (&TREE_TYPE (decl), + DECL_INITIAL (decl), true); + /* If complete_array_type returns 3, it means that the + initial value of the compound literal is empty. Allow it. */ + gcc_assert (failure == 0 || failure == 3); + + type = TREE_TYPE (decl); + TREE_TYPE (DECL_INITIAL (decl)) = type; + } + + if (type == error_mark_node || !COMPLETE_TYPE_P (type)) + { + c_incomplete_type_error (loc, NULL_TREE, type); + return error_mark_node; + } + + if (TREE_STATIC (decl) + && !verify_type_context (loc, TCTX_STATIC_STORAGE, type)) + return error_mark_node; + + stmt = build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl); + complit = build1 (COMPOUND_LITERAL_EXPR, type, stmt); + TREE_SIDE_EFFECTS (complit) = 1; + + layout_decl (decl, 0); + + if (TREE_STATIC (decl)) + { + /* This decl needs a name for the assembler output. */ + set_compound_literal_name (decl); + DECL_DEFER_OUTPUT (decl) = 1; + DECL_COMDAT (decl) = 1; + pushdecl (decl); + rest_of_decl_compilation (decl, 1, 0); + } + else if (current_function_decl && !current_scope->parm_flag) + pushdecl (decl); + + if (non_const) + { + complit = build2 (C_MAYBE_CONST_EXPR, type, NULL, complit); + C_MAYBE_CONST_EXPR_NON_CONST (complit) = 1; + } + + return complit; +} + +/* Check the type of a compound literal. Here we just check that it + is valid for C++. */ + +void +check_compound_literal_type (location_t loc, struct c_type_name *type_name) +{ + if (warn_cxx_compat + && (type_name->specs->typespec_kind == ctsk_tagdef + || type_name->specs->typespec_kind == ctsk_tagfirstref + || type_name->specs->typespec_kind == ctsk_tagfirstref_attrs)) + warning_at (loc, OPT_Wc___compat, + "defining a type in a compound literal is invalid in C++"); +} + +/* Performs sanity checks on the TYPE and WIDTH of the bit-field NAME, + replacing with appropriate values if they are invalid. */ + +static void +check_bitfield_type_and_width (location_t loc, tree *type, tree *width, + tree orig_name) +{ + tree type_mv; + unsigned int max_width; + unsigned HOST_WIDE_INT w; + const char *name = (orig_name + ? identifier_to_locale (IDENTIFIER_POINTER (orig_name)) + : _("")); + + /* Detect and ignore out of range field width and process valid + field widths. */ + if (!INTEGRAL_TYPE_P (TREE_TYPE (*width))) + { + error_at (loc, "bit-field %qs width not an integer constant", name); + *width = integer_one_node; + } + else + { + if (TREE_CODE (*width) != INTEGER_CST) + { + *width = c_fully_fold (*width, false, NULL); + if (TREE_CODE (*width) == INTEGER_CST) + pedwarn (loc, OPT_Wpedantic, + "bit-field %qs width not an integer constant expression", + name); + } + if (TREE_CODE (*width) != INTEGER_CST) + { + error_at (loc, "bit-field %qs width not an integer constant", name); + *width = integer_one_node; + } + constant_expression_warning (*width); + if (tree_int_cst_sgn (*width) < 0) + { + error_at (loc, "negative width in bit-field %qs", name); + *width = integer_one_node; + } + else if (integer_zerop (*width) && orig_name) + { + error_at (loc, "zero width for bit-field %qs", name); + *width = integer_one_node; + } + } + + /* Detect invalid bit-field type. */ + if (TREE_CODE (*type) != INTEGER_TYPE + && TREE_CODE (*type) != BOOLEAN_TYPE + && TREE_CODE (*type) != ENUMERAL_TYPE) + { + error_at (loc, "bit-field %qs has invalid type", name); + *type = unsigned_type_node; + } + + if (TYPE_WARN_IF_NOT_ALIGN (*type)) + { + error_at (loc, "cannot declare bit-field %qs with % type", + name); + *type = unsigned_type_node; + } + + type_mv = TYPE_MAIN_VARIANT (*type); + if (!in_system_header_at (input_location) + && type_mv != integer_type_node + && type_mv != unsigned_type_node + && type_mv != boolean_type_node) + pedwarn_c90 (loc, OPT_Wpedantic, + "type of bit-field %qs is a GCC extension", name); + + max_width = TYPE_PRECISION (*type); + + if (compare_tree_int (*width, max_width) > 0) + { + error_at (loc, "width of %qs exceeds its type", name); + w = max_width; + *width = build_int_cst (integer_type_node, w); + } + else + w = tree_to_uhwi (*width); + + if (TREE_CODE (*type) == ENUMERAL_TYPE) + { + struct lang_type *lt = TYPE_LANG_SPECIFIC (*type); + if (!lt + || w < tree_int_cst_min_precision (lt->enum_min, TYPE_SIGN (*type)) + || w < tree_int_cst_min_precision (lt->enum_max, TYPE_SIGN (*type))) + warning_at (loc, 0, "%qs is narrower than values of its type", name); + } +} + + + +/* Print warning about variable length array if necessary. */ + +static void +warn_variable_length_array (tree name, tree size) +{ + if (TREE_CONSTANT (size)) + { + if (name) + pedwarn_c90 (input_location, OPT_Wvla, + "ISO C90 forbids array %qE whose size " + "cannot be evaluated", name); + else + pedwarn_c90 (input_location, OPT_Wvla, "ISO C90 forbids array " + "whose size cannot be evaluated"); + } + else + { + if (name) + pedwarn_c90 (input_location, OPT_Wvla, + "ISO C90 forbids variable length array %qE", name); + else + pedwarn_c90 (input_location, OPT_Wvla, "ISO C90 forbids variable " + "length array"); + } +} + +/* Print warning about defaulting to int if necessary. */ + +static void +warn_defaults_to (location_t location, int opt, const char *gmsgid, ...) +{ + diagnostic_info diagnostic; + va_list ap; + rich_location richloc (line_table, location); + + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + flag_isoc99 ? DK_PEDWARN : DK_WARNING); + diagnostic.option_index = opt; + diagnostic_report_diagnostic (global_dc, &diagnostic); + va_end (ap); +} + +/* Returns the smallest location != UNKNOWN_LOCATION in LOCATIONS, + considering only those c_declspec_words found in LIST, which + must be terminated by cdw_number_of_elements. */ + +static location_t +smallest_type_quals_location (const location_t *locations, + const c_declspec_word *list) +{ + location_t loc = UNKNOWN_LOCATION; + while (*list != cdw_number_of_elements) + { + location_t newloc = locations[*list]; + if (loc == UNKNOWN_LOCATION + || (newloc != UNKNOWN_LOCATION && newloc < loc)) + loc = newloc; + list++; + } + + return loc; +} + +/* Given declspecs and a declarator, + determine the name and type of the object declared + and construct a ..._DECL node for it. + (In one case we can return a ..._TYPE node instead. + For invalid input we sometimes return NULL_TREE.) + + DECLSPECS is a c_declspecs structure for the declaration specifiers. + + DECL_CONTEXT says which syntactic context this declaration is in: + NORMAL for most contexts. Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL. + FUNCDEF for a function definition. Like NORMAL but a few different + error messages in each case. Return value may be zero meaning + this definition is too screwy to try to parse. + PARM for a parameter declaration (either within a function prototype + or before a function body). Make a PARM_DECL, or return void_type_node. + TYPENAME if for a typename (in a cast or sizeof). + Don't make a DECL node; just return the ..._TYPE node. + FIELD for a struct or union field; make a FIELD_DECL. + INITIALIZED is true if the decl has an initializer. + WIDTH is non-NULL for bit-fields, and is a pointer to an INTEGER_CST node + representing the width of the bit-field. + DECL_ATTRS points to the list of attributes that should be added to this + decl. Any nested attributes that belong on the decl itself will be + added to this list. + If EXPR is not NULL, any expressions that need to be evaluated as + part of evaluating variably modified types will be stored in *EXPR. + If EXPR_CONST_OPERANDS is not NULL, *EXPR_CONST_OPERANDS will be + set to indicate whether operands in *EXPR can be used in constant + expressions. + DEPRECATED_STATE is a deprecated_states value indicating whether + deprecation/unavailability warnings should be suppressed. + + In the TYPENAME case, DECLARATOR is really an absolute declarator. + It may also be so in the PARM case, for a prototype where the + argument type is specified but not the name. + + This function is where the complicated C meanings of `static' + and `extern' are interpreted. */ + +static tree +grokdeclarator (const struct c_declarator *declarator, + struct c_declspecs *declspecs, + enum decl_context decl_context, bool initialized, tree *width, + tree *decl_attrs, tree *expr, bool *expr_const_operands, + enum deprecated_states deprecated_state) +{ + tree type = declspecs->type; + bool threadp = declspecs->thread_p; + enum c_storage_class storage_class = declspecs->storage_class; + int constp; + int restrictp; + int volatilep; + int atomicp; + int type_quals = TYPE_UNQUALIFIED; + tree name = NULL_TREE; + bool funcdef_flag = false; + bool funcdef_syntax = false; + bool size_varies = false; + tree decl_attr = declspecs->decl_attr; + int array_ptr_quals = TYPE_UNQUALIFIED; + tree array_ptr_attrs = NULL_TREE; + bool array_parm_static = false; + bool array_parm_vla_unspec_p = false; + tree returned_attrs = NULL_TREE; + tree decl_id_attrs = NULL_TREE; + bool bitfield = width != NULL; + tree element_type; + tree orig_qual_type = NULL; + size_t orig_qual_indirect = 0; + struct c_arg_info *arg_info = 0; + addr_space_t as1, as2, address_space; + location_t loc = UNKNOWN_LOCATION; + tree expr_dummy; + bool expr_const_operands_dummy; + enum c_declarator_kind first_non_attr_kind; + unsigned int alignas_align = 0; + + if (TREE_CODE (type) == ERROR_MARK) + return error_mark_node; + if (expr == NULL) + { + expr = &expr_dummy; + expr_dummy = NULL_TREE; + } + if (expr_const_operands == NULL) + expr_const_operands = &expr_const_operands_dummy; + + if (declspecs->expr) + { + if (*expr) + *expr = build2 (COMPOUND_EXPR, TREE_TYPE (declspecs->expr), *expr, + declspecs->expr); + else + *expr = declspecs->expr; + } + *expr_const_operands = declspecs->expr_const_operands; + + if (decl_context == FUNCDEF) + funcdef_flag = true, decl_context = NORMAL; + + /* Look inside a declarator for the name being declared + and get it as an IDENTIFIER_NODE, for an error message. */ + { + const struct c_declarator *decl = declarator; + + first_non_attr_kind = cdk_attrs; + while (decl) + switch (decl->kind) + { + case cdk_array: + loc = decl->id_loc; + /* FALL THRU. */ + + case cdk_function: + case cdk_pointer: + funcdef_syntax = (decl->kind == cdk_function); + if (first_non_attr_kind == cdk_attrs) + first_non_attr_kind = decl->kind; + decl = decl->declarator; + break; + + case cdk_attrs: + decl = decl->declarator; + break; + + case cdk_id: + loc = decl->id_loc; + if (decl->u.id.id) + name = decl->u.id.id; + decl_id_attrs = decl->u.id.attrs; + if (first_non_attr_kind == cdk_attrs) + first_non_attr_kind = decl->kind; + decl = 0; + break; + + default: + gcc_unreachable (); + } + if (name == NULL_TREE) + { + gcc_assert (decl_context == PARM + || decl_context == TYPENAME + || (decl_context == FIELD + && declarator->kind == cdk_id)); + gcc_assert (!initialized); + } + } + + /* A function definition's declarator must have the form of + a function declarator. */ + + if (funcdef_flag && !funcdef_syntax) + return NULL_TREE; + + /* If this looks like a function definition, make it one, + even if it occurs where parms are expected. + Then store_parm_decls will reject it and not use it as a parm. */ + if (decl_context == NORMAL && !funcdef_flag && current_scope->parm_flag) + decl_context = PARM; + + if (deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) + { + if (declspecs->unavailable_p) + error_unavailable_use (declspecs->type, declspecs->decl_attr); + else if (declspecs->deprecated_p + && deprecated_state != DEPRECATED_SUPPRESS) + warn_deprecated_use (declspecs->type, declspecs->decl_attr); + } + + if ((decl_context == NORMAL || decl_context == FIELD) + && current_scope == file_scope + && variably_modified_type_p (type, NULL_TREE)) + { + if (name) + error_at (loc, "variably modified %qE at file scope", name); + else + error_at (loc, "variably modified field at file scope"); + type = integer_type_node; + } + + size_varies = C_TYPE_VARIABLE_SIZE (type) != 0; + + /* Diagnose defaulting to "int". */ + + if (declspecs->default_int_p && !in_system_header_at (input_location)) + { + /* Issue a warning if this is an ISO C 99 program or if + -Wreturn-type and this is a function, or if -Wimplicit; + prefer the former warning since it is more explicit. */ + if ((warn_implicit_int || warn_return_type > 0 || flag_isoc99) + && funcdef_flag) + warn_about_return_type = 1; + else + { + if (name) + warn_defaults_to (loc, OPT_Wimplicit_int, + "type defaults to % in declaration " + "of %qE", name); + else + warn_defaults_to (loc, OPT_Wimplicit_int, + "type defaults to % in type name"); + } + } + + /* Adjust the type if a bit-field is being declared, + -funsigned-bitfields applied and the type is not explicitly + "signed". */ + if (bitfield && !flag_signed_bitfields && !declspecs->explicit_signed_p + && TREE_CODE (type) == INTEGER_TYPE) + type = unsigned_type_for (type); + + /* Figure out the type qualifiers for the declaration. There are + two ways a declaration can become qualified. One is something + like `const int i' where the `const' is explicit. Another is + something like `typedef const int CI; CI i' where the type of the + declaration contains the `const'. A third possibility is that + there is a type qualifier on the element type of a typedefed + array type, in which case we should extract that qualifier so + that c_apply_type_quals_to_decl receives the full list of + qualifiers to work with (C90 is not entirely clear about whether + duplicate qualifiers should be diagnosed in this case, but it + seems most appropriate to do so). */ + element_type = strip_array_types (type); + constp = declspecs->const_p + TYPE_READONLY (element_type); + restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type); + volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type); + atomicp = declspecs->atomic_p + TYPE_ATOMIC (element_type); + as1 = declspecs->address_space; + as2 = TYPE_ADDR_SPACE (element_type); + address_space = ADDR_SPACE_GENERIC_P (as1)? as2 : as1; + + if (constp > 1) + pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %"); + if (restrictp > 1) + pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %"); + if (volatilep > 1) + pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %"); + if (atomicp > 1) + pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %<_Atomic%>"); + + if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2) + error_at (loc, "conflicting named address spaces (%s vs %s)", + c_addr_space_name (as1), c_addr_space_name (as2)); + + if ((TREE_CODE (type) == ARRAY_TYPE + || first_non_attr_kind == cdk_array) + && TYPE_QUALS (element_type)) + { + orig_qual_type = type; + type = TYPE_MAIN_VARIANT (type); + } + type_quals = ((constp ? TYPE_QUAL_CONST : 0) + | (restrictp ? TYPE_QUAL_RESTRICT : 0) + | (volatilep ? TYPE_QUAL_VOLATILE : 0) + | (atomicp ? TYPE_QUAL_ATOMIC : 0) + | ENCODE_QUAL_ADDR_SPACE (address_space)); + if (type_quals != TYPE_QUALS (element_type)) + orig_qual_type = NULL_TREE; + + /* Applying the _Atomic qualifier to an array type (through the use + of typedefs or typeof) must be detected here. If the qualifier + is introduced later, any appearance of applying it to an array is + actually applying it to an element of that array. */ + if (declspecs->atomic_p && TREE_CODE (type) == ARRAY_TYPE) + error_at (loc, "%<_Atomic%>-qualified array type"); + + /* Warn about storage classes that are invalid for certain + kinds of declarations (parameters, typenames, etc.). */ + + if (funcdef_flag + && (threadp + || storage_class == csc_auto + || storage_class == csc_register + || storage_class == csc_typedef)) + { + if (storage_class == csc_auto) + pedwarn (loc, + (current_scope == file_scope) ? 0 : OPT_Wpedantic, + "function definition declared %"); + if (storage_class == csc_register) + error_at (loc, "function definition declared %"); + if (storage_class == csc_typedef) + error_at (loc, "function definition declared %"); + if (threadp) + error_at (loc, "function definition declared %qs", + declspecs->thread_gnu_p ? "__thread" : "_Thread_local"); + threadp = false; + if (storage_class == csc_auto + || storage_class == csc_register + || storage_class == csc_typedef) + storage_class = csc_none; + } + else if (decl_context != NORMAL && (storage_class != csc_none || threadp)) + { + if (decl_context == PARM && storage_class == csc_register) + ; + else + { + switch (decl_context) + { + case FIELD: + if (name) + error_at (loc, "storage class specified for structure " + "field %qE", name); + else + error_at (loc, "storage class specified for structure field"); + break; + case PARM: + if (name) + error_at (loc, "storage class specified for parameter %qE", + name); + else + error_at (loc, "storage class specified for unnamed parameter"); + break; + default: + error_at (loc, "storage class specified for typename"); + break; + } + storage_class = csc_none; + threadp = false; + } + } + else if (storage_class == csc_extern + && initialized + && !funcdef_flag) + { + /* 'extern' with initialization is invalid if not at file scope. */ + if (current_scope == file_scope) + { + /* It is fine to have 'extern const' when compiling at C + and C++ intersection. */ + if (!(warn_cxx_compat && constp)) + warning_at (loc, 0, "%qE initialized and declared %", + name); + } + else + error_at (loc, "%qE has both % and initializer", name); + } + else if (current_scope == file_scope) + { + if (storage_class == csc_auto) + error_at (loc, "file-scope declaration of %qE specifies %", + name); + if (pedantic && storage_class == csc_register) + pedwarn (input_location, OPT_Wpedantic, + "file-scope declaration of %qE specifies %", name); + } + else + { + if (storage_class == csc_extern && funcdef_flag) + error_at (loc, "nested function %qE declared %", name); + else if (threadp && storage_class == csc_none) + { + error_at (loc, "function-scope %qE implicitly auto and declared " + "%qs", name, + declspecs->thread_gnu_p ? "__thread" : "_Thread_local"); + threadp = false; + } + } + + /* Now figure out the structure of the declarator proper. + Descend through it, creating more complex types, until we reach + the declared identifier (or NULL_TREE, in an absolute declarator). + At each stage we maintain an unqualified version of the type + together with any qualifiers that should be applied to it with + c_build_qualified_type; this way, array types including + multidimensional array types are first built up in unqualified + form and then the qualified form is created with + TYPE_MAIN_VARIANT pointing to the unqualified form. */ + + while (declarator && declarator->kind != cdk_id) + { + if (type == error_mark_node) + { + declarator = declarator->declarator; + continue; + } + + /* Each level of DECLARATOR is either a cdk_array (for ...[..]), + a cdk_pointer (for *...), + a cdk_function (for ...(...)), + a cdk_attrs (for nested attributes), + or a cdk_id (for the name being declared + or the place in an absolute declarator + where the name was omitted). + For the last case, we have just exited the loop. + + At this point, TYPE is the type of elements of an array, + or for a function to return, or for a pointer to point to. + After this sequence of ifs, TYPE is the type of the + array or function or pointer, and DECLARATOR has had its + outermost layer removed. */ + + if (array_ptr_quals != TYPE_UNQUALIFIED + || array_ptr_attrs != NULL_TREE + || array_parm_static) + { + /* Only the innermost declarator (making a parameter be of + array type which is converted to pointer type) + may have static or type qualifiers. */ + error_at (loc, "static or type qualifiers in non-parameter array declarator"); + array_ptr_quals = TYPE_UNQUALIFIED; + array_ptr_attrs = NULL_TREE; + array_parm_static = false; + } + + switch (declarator->kind) + { + case cdk_attrs: + { + /* A declarator with embedded attributes. */ + tree attrs = declarator->u.attrs; + const struct c_declarator *inner_decl; + int attr_flags = 0; + declarator = declarator->declarator; + /* Standard attribute syntax precisely defines what entity + an attribute in each position appertains to, so only + apply laxity about positioning to GNU attribute syntax. + Standard attributes applied to a function or array + declarator apply exactly to that type; standard + attributes applied to the identifier apply to the + declaration rather than to the type, and are specified + using a cdk_id declarator rather than using + cdk_attrs. */ + inner_decl = declarator; + while (inner_decl->kind == cdk_attrs) + inner_decl = inner_decl->declarator; + if (!cxx11_attribute_p (attrs)) + { + if (inner_decl->kind == cdk_id) + attr_flags |= (int) ATTR_FLAG_DECL_NEXT; + else if (inner_decl->kind == cdk_function) + attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; + else if (inner_decl->kind == cdk_array) + attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; + } + attrs = c_warn_type_attributes (attrs); + returned_attrs = decl_attributes (&type, + chainon (returned_attrs, attrs), + attr_flags); + break; + } + case cdk_array: + { + tree itype = NULL_TREE; + tree size = declarator->u.array.dimen; + /* The index is a signed object `sizetype' bits wide. */ + tree index_type = c_common_signed_type (sizetype); + + array_ptr_quals = declarator->u.array.quals; + array_ptr_attrs = declarator->u.array.attrs; + array_parm_static = declarator->u.array.static_p; + array_parm_vla_unspec_p = declarator->u.array.vla_unspec_p; + + declarator = declarator->declarator; + + /* Check for some types that there cannot be arrays of. */ + + if (VOID_TYPE_P (type)) + { + if (name) + error_at (loc, "declaration of %qE as array of voids", name); + else + error_at (loc, "declaration of type name as array of voids"); + type = error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (name) + error_at (loc, "declaration of %qE as array of functions", + name); + else + error_at (loc, "declaration of type name as array of " + "functions"); + type = error_mark_node; + } + + if (pedantic && !in_system_header_at (input_location) + && flexible_array_type_p (type)) + pedwarn (loc, OPT_Wpedantic, + "invalid use of structure with flexible array member"); + + if (size == error_mark_node) + type = error_mark_node; + + if (type == error_mark_node) + continue; + + if (!verify_type_context (loc, TCTX_ARRAY_ELEMENT, type)) + { + type = error_mark_node; + continue; + } + + /* If size was specified, set ITYPE to a range-type for + that size. Otherwise, ITYPE remains null. finish_decl + may figure it out from an initial value. */ + + if (size) + { + bool size_maybe_const = true; + bool size_int_const = (TREE_CODE (size) == INTEGER_CST + && !TREE_OVERFLOW (size)); + bool this_size_varies = false; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an + lvalue. */ + STRIP_TYPE_NOPS (size); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (size))) + { + if (name) + error_at (loc, "size of array %qE has non-integer type", + name); + else + error_at (loc, + "size of unnamed array has non-integer type"); + size = integer_one_node; + size_int_const = true; + } + /* This can happen with enum forward declaration. */ + else if (!COMPLETE_TYPE_P (TREE_TYPE (size))) + { + if (name) + error_at (loc, "size of array %qE has incomplete type", + name); + else + error_at (loc, "size of unnamed array has incomplete " + "type"); + size = integer_one_node; + size_int_const = true; + } + + size = c_fully_fold (size, false, &size_maybe_const); + + if (pedantic && size_maybe_const && integer_zerop (size)) + { + if (name) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids zero-size array %qE", name); + else + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids zero-size array"); + } + + if (TREE_CODE (size) == INTEGER_CST && size_maybe_const) + { + constant_expression_warning (size); + if (tree_int_cst_sgn (size) < 0) + { + if (name) + error_at (loc, "size of array %qE is negative", name); + else + error_at (loc, "size of unnamed array is negative"); + size = integer_one_node; + size_int_const = true; + } + /* Handle a size folded to an integer constant but + not an integer constant expression. */ + if (!size_int_const) + { + /* If this is a file scope declaration of an + ordinary identifier, this is invalid code; + diagnosing it here and not subsequently + treating the type as variable-length avoids + more confusing diagnostics later. */ + if ((decl_context == NORMAL || decl_context == FIELD) + && current_scope == file_scope) + pedwarn (input_location, 0, + "variably modified %qE at file scope", + name); + else + this_size_varies = size_varies = true; + warn_variable_length_array (name, size); + } + } + else if ((decl_context == NORMAL || decl_context == FIELD) + && current_scope == file_scope) + { + error_at (loc, "variably modified %qE at file scope", name); + size = integer_one_node; + } + else + { + /* Make sure the array size remains visibly + nonconstant even if it is (eg) a const variable + with known value. */ + this_size_varies = size_varies = true; + warn_variable_length_array (name, size); + if (sanitize_flags_p (SANITIZE_VLA) + && current_function_decl != NULL_TREE + && decl_context == NORMAL) + { + /* Evaluate the array size only once. */ + size = save_expr (size); + size = c_fully_fold (size, false, NULL); + size = fold_build2 (COMPOUND_EXPR, TREE_TYPE (size), + ubsan_instrument_vla (loc, size), + size); + } + } + + if (integer_zerop (size) && !this_size_varies) + { + /* A zero-length array cannot be represented with + an unsigned index type, which is what we'll + get with build_index_type. Create an + open-ended range instead. */ + itype = build_range_type (sizetype, size, NULL_TREE); + } + else + { + /* Arrange for the SAVE_EXPR on the inside of the + MINUS_EXPR, which allows the -1 to get folded + with the +1 that happens when building TYPE_SIZE. */ + if (size_varies) + size = save_expr (size); + if (this_size_varies && TREE_CODE (size) == INTEGER_CST) + size = build2 (COMPOUND_EXPR, TREE_TYPE (size), + integer_zero_node, size); + + /* Compute the maximum valid index, that is, size + - 1. Do the calculation in index_type, so that + if it is a variable the computations will be + done in the proper mode. */ + itype = fold_build2_loc (loc, MINUS_EXPR, index_type, + convert (index_type, size), + convert (index_type, + size_one_node)); + + /* The above overflows when size does not fit + in index_type. + ??? While a size of INT_MAX+1 technically shouldn't + cause an overflow (because we subtract 1), handling + this case seems like an unnecessary complication. */ + if (TREE_CODE (size) == INTEGER_CST + && !int_fits_type_p (size, index_type)) + { + if (name) + error_at (loc, "size of array %qE is too large", + name); + else + error_at (loc, "size of unnamed array is too large"); + type = error_mark_node; + continue; + } + + itype = build_index_type (itype); + } + if (this_size_varies) + { + if (TREE_SIDE_EFFECTS (size)) + { + if (*expr) + *expr = build2 (COMPOUND_EXPR, TREE_TYPE (size), + *expr, size); + else + *expr = size; + } + *expr_const_operands &= size_maybe_const; + } + } + else if (decl_context == FIELD) + { + bool flexible_array_member = false; + if (array_parm_vla_unspec_p) + /* Field names can in fact have function prototype + scope so [*] is disallowed here through making + the field variably modified, not through being + something other than a declaration with function + prototype scope. */ + size_varies = true; + else + { + const struct c_declarator *t = declarator; + while (t->kind == cdk_attrs) + t = t->declarator; + flexible_array_member = (t->kind == cdk_id); + } + if (flexible_array_member + && !in_system_header_at (input_location)) + pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not " + "support flexible array members"); + + /* ISO C99 Flexible array members are effectively + identical to GCC's zero-length array extension. */ + if (flexible_array_member || array_parm_vla_unspec_p) + itype = build_range_type (sizetype, size_zero_node, + NULL_TREE); + } + else if (decl_context == PARM) + { + if (array_parm_vla_unspec_p) + { + itype = build_range_type (sizetype, size_zero_node, NULL_TREE); + size_varies = true; + } + } + else if (decl_context == TYPENAME) + { + if (array_parm_vla_unspec_p) + { + /* C99 6.7.5.2p4 */ + warning (0, "%<[*]%> not in a declaration"); + /* We use this to avoid messing up with incomplete + array types of the same type, that would + otherwise be modified below. */ + itype = build_range_type (sizetype, size_zero_node, + NULL_TREE); + size_varies = true; + } + } + + /* Complain about arrays of incomplete types. */ + if (!COMPLETE_TYPE_P (type)) + { + error_at (loc, "array type has incomplete element type %qT", + type); + /* See if we can be more helpful. */ + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (name) + inform (loc, "declaration of %qE as multidimensional " + "array must have bounds for all dimensions " + "except the first", name); + else + inform (loc, "declaration of multidimensional array " + "must have bounds for all dimensions except " + "the first"); + } + type = error_mark_node; + } + else + /* When itype is NULL, a shared incomplete array type is + returned for all array of a given type. Elsewhere we + make sure we don't complete that type before copying + it, but here we want to make sure we don't ever + modify the shared type, so we gcc_assert (itype) + below. */ + { + addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals); + if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type)) + type = build_qualified_type (type, + ENCODE_QUAL_ADDR_SPACE (as)); + + type = build_array_type (type, itype); + } + + if (type != error_mark_node) + { + if (size_varies) + { + /* It is ok to modify type here even if itype is + NULL: if size_varies, we're in a + multi-dimensional array and the inner type has + variable size, so the enclosing shared array type + must too. */ + if (size && TREE_CODE (size) == INTEGER_CST) + type + = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + C_TYPE_VARIABLE_SIZE (type) = 1; + } + + /* The GCC extension for zero-length arrays differs from + ISO flexible array members in that sizeof yields + zero. */ + if (size && integer_zerop (size)) + { + gcc_assert (itype); + type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + TYPE_SIZE (type) = bitsize_zero_node; + TYPE_SIZE_UNIT (type) = size_zero_node; + SET_TYPE_STRUCTURAL_EQUALITY (type); + } + if (array_parm_vla_unspec_p) + { + gcc_assert (itype); + /* The type is complete. C99 6.7.5.2p4 */ + type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + TYPE_SIZE (type) = bitsize_zero_node; + TYPE_SIZE_UNIT (type) = size_zero_node; + SET_TYPE_STRUCTURAL_EQUALITY (type); + } + + if (!valid_array_size_p (loc, type, name)) + type = error_mark_node; + } + + if (decl_context != PARM + && (array_ptr_quals != TYPE_UNQUALIFIED + || array_ptr_attrs != NULL_TREE + || array_parm_static)) + { + error_at (loc, "static or type qualifiers in non-parameter " + "array declarator"); + array_ptr_quals = TYPE_UNQUALIFIED; + array_ptr_attrs = NULL_TREE; + array_parm_static = false; + } + orig_qual_indirect++; + break; + } + case cdk_function: + { + /* Say it's a definition only for the declarator closest + to the identifier, apart possibly from some + attributes. */ + bool really_funcdef = false; + tree arg_types; + orig_qual_type = NULL_TREE; + if (funcdef_flag) + { + const struct c_declarator *t = declarator->declarator; + while (t->kind == cdk_attrs) + t = t->declarator; + really_funcdef = (t->kind == cdk_id); + } + + /* Declaring a function type. Make sure we have a valid + type for the function to return. */ + if (type == error_mark_node) + continue; + + size_varies = false; + + /* Warn about some types functions can't return. */ + if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (name) + error_at (loc, "%qE declared as function returning a " + "function", name); + else + error_at (loc, "type name declared as function " + "returning a function"); + type = integer_type_node; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (name) + error_at (loc, "%qE declared as function returning an array", + name); + else + error_at (loc, "type name declared as function returning " + "an array"); + type = integer_type_node; + } + + /* Construct the function type and go to the next + inner layer of declarator. */ + arg_info = declarator->u.arg_info; + arg_types = grokparms (arg_info, really_funcdef); + + /* Type qualifiers before the return type of the function + qualify the return type, not the function type. */ + if (type_quals) + { + const enum c_declspec_word ignored_quals_list[] = + { + cdw_const, cdw_volatile, cdw_restrict, cdw_address_space, + cdw_atomic, cdw_number_of_elements + }; + location_t specs_loc + = smallest_type_quals_location (declspecs->locations, + ignored_quals_list); + if (specs_loc == UNKNOWN_LOCATION) + specs_loc = declspecs->locations[cdw_typedef]; + if (specs_loc == UNKNOWN_LOCATION) + specs_loc = loc; + + /* Type qualifiers on a function return type are + normally permitted by the standard but have no + effect, so give a warning at -Wreturn-type. + Qualifiers on a void return type are banned on + function definitions in ISO C; GCC used to used + them for noreturn functions. The resolution of C11 + DR#423 means qualifiers (other than _Atomic) are + actually removed from the return type when + determining the function type. */ + int quals_used = type_quals; + if (flag_isoc11) + quals_used &= TYPE_QUAL_ATOMIC; + if (quals_used && VOID_TYPE_P (type) && really_funcdef) + pedwarn (specs_loc, 0, + "function definition has qualified void " + "return type"); + else + warning_at (specs_loc, OPT_Wignored_qualifiers, + "type qualifiers ignored on function " + "return type"); + + /* Ensure an error for restrict on invalid types; the + DR#423 resolution is not entirely clear about + this. */ + if (flag_isoc11 + && (type_quals & TYPE_QUAL_RESTRICT) + && (!POINTER_TYPE_P (type) + || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))) + error_at (loc, "invalid use of %"); + type = c_build_qualified_type (type, quals_used); + } + type_quals = TYPE_UNQUALIFIED; + + type = build_function_type (type, arg_types); + declarator = declarator->declarator; + + /* Set the TYPE_CONTEXTs for each tagged type which is local to + the formal parameter list of this FUNCTION_TYPE to point to + the FUNCTION_TYPE node itself. */ + { + c_arg_tag *tag; + unsigned ix; + + FOR_EACH_VEC_SAFE_ELT_REVERSE (arg_info->tags, ix, tag) + TYPE_CONTEXT (tag->type) = type; + } + break; + } + case cdk_pointer: + { + /* Merge any constancy or volatility into the target type + for the pointer. */ + if ((type_quals & TYPE_QUAL_ATOMIC) + && TREE_CODE (type) == FUNCTION_TYPE) + { + error_at (loc, + "%<_Atomic%>-qualified function type"); + type_quals &= ~TYPE_QUAL_ATOMIC; + } + else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals, orig_qual_type, + orig_qual_indirect); + orig_qual_type = NULL_TREE; + size_varies = false; + + /* When the pointed-to type involves components of variable size, + care must be taken to ensure that the size evaluation code is + emitted early enough to dominate all the possible later uses + and late enough for the variables on which it depends to have + been assigned. + + This is expected to happen automatically when the pointed-to + type has a name/declaration of it's own, but special attention + is required if the type is anonymous. + + We attach an artificial TYPE_DECL to such pointed-to type + and arrange for it to be included in a DECL_EXPR. This + forces the sizes evaluation at a safe point and ensures it + is not deferred until e.g. within a deeper conditional context. + + PARM contexts have no enclosing statement list that + can hold the DECL_EXPR, so we need to use a BIND_EXPR + instead, and add it to the list of expressions that + need to be evaluated. + + TYPENAME contexts do have an enclosing statement list, + but it would be incorrect to use it, as the size should + only be evaluated if the containing expression is + evaluated. We might also be in the middle of an + expression with side effects on the pointed-to type size + "arguments" prior to the pointer declaration point and + the fake TYPE_DECL in the enclosing context would force + the size evaluation prior to the side effects. We therefore + use BIND_EXPRs in TYPENAME contexts too. */ + if (!TYPE_NAME (type) + && variably_modified_type_p (type, NULL_TREE)) + { + tree bind = NULL_TREE; + if (decl_context == TYPENAME || decl_context == PARM) + { + bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, + NULL_TREE, NULL_TREE); + TREE_SIDE_EFFECTS (bind) = 1; + BIND_EXPR_BODY (bind) = push_stmt_list (); + push_scope (); + } + tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type); + DECL_ARTIFICIAL (decl) = 1; + pushdecl (decl); + finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE); + TYPE_NAME (type) = decl; + if (bind) + { + pop_scope (); + BIND_EXPR_BODY (bind) + = pop_stmt_list (BIND_EXPR_BODY (bind)); + if (*expr) + *expr = build2 (COMPOUND_EXPR, void_type_node, *expr, + bind); + else + *expr = bind; + } + } + + type = c_build_pointer_type (type); + + /* Process type qualifiers (such as const or volatile) + that were given inside the `*'. */ + type_quals = declarator->u.pointer_quals; + + declarator = declarator->declarator; + break; + } + default: + gcc_unreachable (); + } + } + *decl_attrs = chainon (returned_attrs, *decl_attrs); + *decl_attrs = chainon (decl_id_attrs, *decl_attrs); + + /* Now TYPE has the actual type, apart from any qualifiers in + TYPE_QUALS. */ + + /* Warn about address space used for things other than static memory or + pointers. */ + address_space = DECODE_QUAL_ADDR_SPACE (type_quals); + if (!ADDR_SPACE_GENERIC_P (address_space)) + { + if (decl_context == NORMAL) + { + switch (storage_class) + { + case csc_auto: + error ("%qs combined with % qualifier for %qE", + c_addr_space_name (address_space), name); + break; + case csc_register: + error ("%qs combined with % qualifier for %qE", + c_addr_space_name (address_space), name); + break; + case csc_none: + if (current_function_scope) + { + error ("%qs specified for auto variable %qE", + c_addr_space_name (address_space), name); + break; + } + break; + case csc_static: + case csc_extern: + case csc_typedef: + break; + default: + gcc_unreachable (); + } + } + else if (decl_context == PARM && TREE_CODE (type) != ARRAY_TYPE) + { + if (name) + error ("%qs specified for parameter %qE", + c_addr_space_name (address_space), name); + else + error ("%qs specified for unnamed parameter", + c_addr_space_name (address_space)); + } + else if (decl_context == FIELD) + { + if (name) + error ("%qs specified for structure field %qE", + c_addr_space_name (address_space), name); + else + error ("%qs specified for structure field", + c_addr_space_name (address_space)); + } + } + + /* Check the type and width of a bit-field. */ + if (bitfield) + { + check_bitfield_type_and_width (loc, &type, width, name); + /* C11 makes it implementation-defined (6.7.2.1#5) whether + atomic types are permitted for bit-fields; we have no code to + make bit-field accesses atomic, so disallow them. */ + if (type_quals & TYPE_QUAL_ATOMIC) + { + if (name) + error_at (loc, "bit-field %qE has atomic type", name); + else + error_at (loc, "bit-field has atomic type"); + type_quals &= ~TYPE_QUAL_ATOMIC; + } + } + + /* Reject invalid uses of _Alignas. */ + if (declspecs->alignas_p) + { + if (storage_class == csc_typedef) + error_at (loc, "alignment specified for typedef %qE", name); + else if (storage_class == csc_register) + error_at (loc, "alignment specified for % object %qE", + name); + else if (decl_context == PARM) + { + if (name) + error_at (loc, "alignment specified for parameter %qE", name); + else + error_at (loc, "alignment specified for unnamed parameter"); + } + else if (bitfield) + { + if (name) + error_at (loc, "alignment specified for bit-field %qE", name); + else + error_at (loc, "alignment specified for unnamed bit-field"); + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + error_at (loc, "alignment specified for function %qE", name); + else if (declspecs->align_log != -1 && TYPE_P (type)) + { + alignas_align = 1U << declspecs->align_log; + if (alignas_align < min_align_of_type (type)) + { + if (name) + error_at (loc, "%<_Alignas%> specifiers cannot reduce " + "alignment of %qE", name); + else + error_at (loc, "%<_Alignas%> specifiers cannot reduce " + "alignment of unnamed field"); + alignas_align = 0; + } + } + } + + /* If this is declaring a typedef name, return a TYPE_DECL. */ + + if (storage_class == csc_typedef) + { + tree decl; + if ((type_quals & TYPE_QUAL_ATOMIC) + && TREE_CODE (type) == FUNCTION_TYPE) + { + error_at (loc, + "%<_Atomic%>-qualified function type"); + type_quals &= ~TYPE_QUAL_ATOMIC; + } + else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals, orig_qual_type, + orig_qual_indirect); + decl = build_decl (declarator->id_loc, + TYPE_DECL, declarator->u.id.id, type); + if (declspecs->explicit_signed_p) + C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; + if (declspecs->inline_p) + pedwarn (loc, 0,"typedef %q+D declared %", decl); + if (declspecs->noreturn_p) + pedwarn (loc, 0,"typedef %q+D declared %<_Noreturn%>", decl); + + if (warn_cxx_compat && declarator->u.id.id != NULL_TREE) + { + struct c_binding *b = I_TAG_BINDING (declarator->u.id.id); + + if (b != NULL + && b->decl != NULL_TREE + && (B_IN_CURRENT_SCOPE (b) + || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) + && TYPE_MAIN_VARIANT (b->decl) != TYPE_MAIN_VARIANT (type)) + { + auto_diagnostic_group d; + if (warning_at (declarator->id_loc, OPT_Wc___compat, + ("using %qD as both a typedef and a tag is " + "invalid in C++"), decl) + && b->locus != UNKNOWN_LOCATION) + inform (b->locus, "originally defined here"); + } + } + + return decl; + } + + /* If this is a type name (such as, in a cast or sizeof), + compute the type and return it now. */ + + if (decl_context == TYPENAME) + { + /* Note that the grammar rejects storage classes in typenames + and fields. */ + gcc_assert (storage_class == csc_none && !threadp + && !declspecs->inline_p && !declspecs->noreturn_p); + if ((type_quals & TYPE_QUAL_ATOMIC) + && TREE_CODE (type) == FUNCTION_TYPE) + { + error_at (loc, + "%<_Atomic%>-qualified function type"); + type_quals &= ~TYPE_QUAL_ATOMIC; + } + else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids const or volatile function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals, orig_qual_type, + orig_qual_indirect); + return type; + } + + if (pedantic && decl_context == FIELD + && variably_modified_type_p (type, NULL_TREE)) + { + /* C99 6.7.2.1p8 */ + pedwarn (loc, OPT_Wpedantic, "a member of a structure or union cannot " + "have a variably modified type"); + } + + /* Aside from typedefs and type names (handle above), + `void' at top level (not within pointer) + is allowed only in public variables. + We don't complain about parms either, but that is because + a better error message can be made later. */ + + if (VOID_TYPE_P (type) && decl_context != PARM + && !((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE) + && (storage_class == csc_extern + || (current_scope == file_scope + && !(storage_class == csc_static + || storage_class == csc_register))))) + { + error_at (loc, "variable or field %qE declared void", name); + type = integer_type_node; + } + + /* Now create the decl, which may be a VAR_DECL, a PARM_DECL + or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */ + + { + tree decl; + + if (decl_context == PARM) + { + tree promoted_type; + bool array_parameter_p = false; + + /* A parameter declared as an array of T is really a pointer to T. + One declared as a function is really a pointer to a function. */ + + if (TREE_CODE (type) == ARRAY_TYPE) + { + /* Transfer const-ness of array into that of type pointed to. */ + type = TREE_TYPE (type); + if (orig_qual_type != NULL_TREE) + { + if (orig_qual_indirect == 0) + orig_qual_type = TREE_TYPE (orig_qual_type); + else + orig_qual_indirect--; + } + if (type_quals) + type = c_build_qualified_type (type, type_quals, orig_qual_type, + orig_qual_indirect); + type = c_build_pointer_type (type); + type_quals = array_ptr_quals; + if (type_quals) + type = c_build_qualified_type (type, type_quals); + + /* We don't yet implement attributes in this context. */ + if (array_ptr_attrs != NULL_TREE) + warning_at (loc, OPT_Wattributes, + "attributes in parameter array declarator ignored"); + + size_varies = false; + array_parameter_p = true; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (type_quals & TYPE_QUAL_ATOMIC) + { + error_at (loc, + "%<_Atomic%>-qualified function type"); + type_quals &= ~TYPE_QUAL_ATOMIC; + } + else if (type_quals) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + type = c_build_pointer_type (type); + type_quals = TYPE_UNQUALIFIED; + } + else if (type_quals) + type = c_build_qualified_type (type, type_quals); + + decl = build_decl (declarator->id_loc, + PARM_DECL, declarator->u.id.id, type); + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + C_ARRAY_PARAMETER (decl) = array_parameter_p; + + /* Compute the type actually passed in the parmlist, + for the case where there is no prototype. + (For example, shorts and chars are passed as ints.) + When there is a prototype, this is overridden later. */ + + if (type == error_mark_node) + promoted_type = type; + else + promoted_type = c_type_promotes_to (type); + + DECL_ARG_TYPE (decl) = promoted_type; + if (declspecs->inline_p) + pedwarn (loc, 0, "parameter %q+D declared %", decl); + if (declspecs->noreturn_p) + pedwarn (loc, 0, "parameter %q+D declared %<_Noreturn%>", decl); + } + else if (decl_context == FIELD) + { + /* Note that the grammar rejects storage classes in typenames + and fields. */ + gcc_assert (storage_class == csc_none && !threadp + && !declspecs->inline_p && !declspecs->noreturn_p); + + /* Structure field. It may not be a function. */ + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error_at (loc, "field %qE declared as a function", name); + type = build_pointer_type (type); + } + else if (TREE_CODE (type) != ERROR_MARK + && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type)) + { + if (name) + error_at (loc, "field %qE has incomplete type", name); + else + error_at (loc, "unnamed field has incomplete type"); + type = error_mark_node; + } + else if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) == NULL_TREE) + { + /* We have a flexible array member through a typedef. + Set suitable range. Whether this is a correct position + for a flexible array member will be determined elsewhere. */ + if (!in_system_header_at (input_location)) + pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not " + "support flexible array members"); + type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + TYPE_DOMAIN (type) = build_range_type (sizetype, size_zero_node, + NULL_TREE); + if (orig_qual_indirect == 0) + orig_qual_type = NULL_TREE; + } + if (type != error_mark_node + && !verify_type_context (loc, TCTX_FIELD, type)) + type = error_mark_node; + + type = c_build_qualified_type (type, type_quals, orig_qual_type, + orig_qual_indirect); + decl = build_decl (declarator->id_loc, + FIELD_DECL, declarator->u.id.id, type); + DECL_NONADDRESSABLE_P (decl) = bitfield; + if (bitfield && !declarator->u.id.id) + DECL_PADDING_P (decl) = 1; + + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (storage_class == csc_register || threadp) + { + error_at (loc, "invalid storage class for function %qE", name); + } + else if (current_scope != file_scope) + { + /* Function declaration not at file scope. Storage + classes other than `extern' are not allowed, C99 + 6.7.1p5, and `extern' makes no difference. However, + GCC allows 'auto', perhaps with 'inline', to support + nested functions. */ + if (storage_class == csc_auto) + pedwarn (loc, OPT_Wpedantic, + "invalid storage class for function %qE", name); + else if (storage_class == csc_static) + { + error_at (loc, "invalid storage class for function %qE", name); + if (funcdef_flag) + storage_class = declspecs->storage_class = csc_none; + else + return NULL_TREE; + } + } + + decl = build_decl (declarator->id_loc, + FUNCTION_DECL, declarator->u.id.id, type); + decl = build_decl_attribute_variant (decl, decl_attr); + + if (type_quals & TYPE_QUAL_ATOMIC) + { + error_at (loc, + "%<_Atomic%>-qualified function type"); + type_quals &= ~TYPE_QUAL_ATOMIC; + } + else if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl)) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids qualified function types"); + + /* Every function declaration is an external reference + (DECL_EXTERNAL) except for those which are not at file + scope and are explicitly declared "auto". This is + forbidden by standard C (C99 6.7.1p5) and is interpreted by + GCC to signify a forward declaration of a nested function. */ + if (storage_class == csc_auto && current_scope != file_scope) + DECL_EXTERNAL (decl) = 0; + /* In C99, a function which is declared 'inline' with 'extern' + is not an external reference (which is confusing). It + means that the later definition of the function must be output + in this file, C99 6.7.4p6. In GNU C89, a function declared + 'extern inline' is an external reference. */ + else if (declspecs->inline_p && storage_class != csc_static) + DECL_EXTERNAL (decl) = ((storage_class == csc_extern) + == flag_gnu89_inline); + else + DECL_EXTERNAL (decl) = !initialized; + + /* Record absence of global scope for `static' or `auto'. */ + TREE_PUBLIC (decl) + = !(storage_class == csc_static || storage_class == csc_auto); + + /* For a function definition, record the argument information + block where store_parm_decls will look for it. */ + if (funcdef_flag) + current_function_arg_info = arg_info; + + if (declspecs->default_int_p) + C_FUNCTION_IMPLICIT_INT (decl) = 1; + + /* Record presence of `inline' and `_Noreturn', if it is + reasonable. */ + if (flag_hosted && MAIN_NAME_P (declarator->u.id.id)) + { + if (declspecs->inline_p) + pedwarn (loc, 0, "cannot inline function %"); + if (declspecs->noreturn_p) + pedwarn (loc, 0, "% declared %<_Noreturn%>"); + } + else + { + if (declspecs->inline_p) + /* Record that the function is declared `inline'. */ + DECL_DECLARED_INLINE_P (decl) = 1; + if (declspecs->noreturn_p) + { + if (flag_isoc99) + pedwarn_c99 (loc, OPT_Wpedantic, + "ISO C99 does not support %<_Noreturn%>"); + else + pedwarn_c99 (loc, OPT_Wpedantic, + "ISO C90 does not support %<_Noreturn%>"); + TREE_THIS_VOLATILE (decl) = 1; + } + } + } + else + { + /* It's a variable. */ + /* An uninitialized decl with `extern' is a reference. */ + int extern_ref = !initialized && storage_class == csc_extern; + + type = c_build_qualified_type (type, type_quals, orig_qual_type, + orig_qual_indirect); + + /* C99 6.2.2p7: It is invalid (compile-time undefined + behavior) to create an 'extern' declaration for a + variable if there is a global declaration that is + 'static' and the global declaration is not visible. + (If the static declaration _is_ currently visible, + the 'extern' declaration is taken to refer to that decl.) */ + if (extern_ref && current_scope != file_scope) + { + tree global_decl = identifier_global_value (declarator->u.id.id); + tree visible_decl = lookup_name (declarator->u.id.id); + + if (global_decl + && global_decl != visible_decl + && VAR_P (global_decl) + && !TREE_PUBLIC (global_decl)) + error_at (loc, "variable previously declared % " + "redeclared %"); + } + + decl = build_decl (declarator->id_loc, + VAR_DECL, declarator->u.id.id, type); + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + + if (declspecs->inline_p) + pedwarn (loc, 0, "variable %q+D declared %", decl); + if (declspecs->noreturn_p) + pedwarn (loc, 0, "variable %q+D declared %<_Noreturn%>", decl); + + /* At file scope, an initialized extern declaration may follow + a static declaration. In that case, DECL_EXTERNAL will be + reset later in start_decl. */ + DECL_EXTERNAL (decl) = (storage_class == csc_extern); + + /* At file scope, the presence of a `static' or `register' storage + class specifier, or the absence of all storage class specifiers + makes this declaration a definition (perhaps tentative). Also, + the absence of `static' makes it public. */ + if (current_scope == file_scope) + { + TREE_PUBLIC (decl) = storage_class != csc_static; + TREE_STATIC (decl) = !extern_ref; + } + /* Not at file scope, only `static' makes a static definition. */ + else + { + TREE_STATIC (decl) = (storage_class == csc_static); + TREE_PUBLIC (decl) = extern_ref; + } + + if (threadp) + set_decl_tls_model (decl, decl_default_tls_model (decl)); + } + + if ((storage_class == csc_extern + || (storage_class == csc_none + && TREE_CODE (type) == FUNCTION_TYPE + && !funcdef_flag)) + && variably_modified_type_p (type, NULL_TREE)) + { + /* C99 6.7.5.2p2 */ + if (TREE_CODE (type) == FUNCTION_TYPE) + error_at (loc, "non-nested function with variably modified type"); + else + error_at (loc, "object with variably modified type must have " + "no linkage"); + } + + /* For nested functions disqualify ones taking VLAs by value + from inlining since the middle-end cannot deal with this. + ??? We should arrange for those to be passed by reference + with emitting the copy on the caller side in the frontend. */ + if (storage_class == csc_none + && TREE_CODE (type) == FUNCTION_TYPE) + for (tree al = TYPE_ARG_TYPES (type); al; al = TREE_CHAIN (al)) + { + tree arg = TREE_VALUE (al); + if (arg != error_mark_node + && C_TYPE_VARIABLE_SIZE (arg)) + { + DECL_UNINLINABLE (decl) = 1; + break; + } + } + + /* Record `register' declaration for warnings on & + and in case doing stupid register allocation. */ + + if (storage_class == csc_register) + { + C_DECL_REGISTER (decl) = 1; + DECL_REGISTER (decl) = 1; + } + + /* Record constancy and volatility. */ + c_apply_type_quals_to_decl (type_quals, decl); + + /* Apply _Alignas specifiers. */ + if (alignas_align) + { + SET_DECL_ALIGN (decl, alignas_align * BITS_PER_UNIT); + DECL_USER_ALIGN (decl) = 1; + } + + /* If a type has volatile components, it should be stored in memory. + Otherwise, the fact that those components are volatile + will be ignored, and would even crash the compiler. + Of course, this only makes sense on VAR,PARM, and RESULT decl's. */ + if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl)) + && (VAR_P (decl) || TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == RESULT_DECL)) + { + /* It is not an error for a structure with volatile fields to + be declared register, but reset DECL_REGISTER since it + cannot actually go in a register. */ + int was_reg = C_DECL_REGISTER (decl); + C_DECL_REGISTER (decl) = 0; + DECL_REGISTER (decl) = 0; + c_mark_addressable (decl); + C_DECL_REGISTER (decl) = was_reg; + } + + /* This is the earliest point at which we might know the assembler + name of a variable. Thus, if it's known before this, die horribly. */ + gcc_assert (!HAS_DECL_ASSEMBLER_NAME_P (decl) + || !DECL_ASSEMBLER_NAME_SET_P (decl)); + + if (warn_cxx_compat + && VAR_P (decl) + && TREE_PUBLIC (decl) + && TREE_STATIC (decl) + && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)) + || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) + && TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE) + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, + ("non-local variable %qD with anonymous type is " + "questionable in C++"), + decl); + + return decl; + } +} + +/* Decode the parameter-list info for a function type or function definition. + The argument is the value returned by `get_parm_info' (or made in c-parse.c + if there is an identifier list instead of a parameter decl list). + These two functions are separate because when a function returns + or receives functions then each is called multiple times but the order + of calls is different. The last call to `grokparms' is always the one + that contains the formal parameter names of a function definition. + + Return a list of arg types to use in the FUNCTION_TYPE for this function. + + FUNCDEF_FLAG is true for a function definition, false for + a mere declaration. A nonempty identifier-list gets an error message + when FUNCDEF_FLAG is false. */ + +static tree +grokparms (struct c_arg_info *arg_info, bool funcdef_flag) +{ + tree arg_types = arg_info->types; + + if (funcdef_flag && arg_info->had_vla_unspec) + { + /* A function definition isn't function prototype scope C99 6.2.1p4. */ + /* C99 6.7.5.2p4 */ + error ("%<[*]%> not allowed in other than function prototype scope"); + } + + if (arg_types == NULL_TREE && !funcdef_flag + && !in_system_header_at (input_location)) + warning (OPT_Wstrict_prototypes, + "function declaration isn%'t a prototype"); + + if (arg_types == error_mark_node) + /* Don't set TYPE_ARG_TYPES in this case. */ + return NULL_TREE; + + else if (arg_types && TREE_CODE (TREE_VALUE (arg_types)) == IDENTIFIER_NODE) + { + if (!funcdef_flag) + { + pedwarn (input_location, 0, "parameter names (without types) in " + "function declaration"); + arg_info->parms = NULL_TREE; + } + else + arg_info->parms = arg_info->types; + + arg_info->types = NULL_TREE; + return NULL_TREE; + } + else + { + tree parm, type, typelt; + unsigned int parmno; + + /* In C2X, convert () in a function definition to (void). */ + if (flag_isoc2x + && funcdef_flag + && !arg_types + && !arg_info->parms) + arg_types = arg_info->types = void_list_node; + + /* If there is a parameter of incomplete type in a definition, + this is an error. In a declaration this is valid, and a + struct or union type may be completed later, before any calls + or definition of the function. In the case where the tag was + first declared within the parameter list, a warning has + already been given. If a parameter has void type, then + however the function cannot be defined or called, so + warn. */ + + for (parm = arg_info->parms, typelt = arg_types, parmno = 1; + parm; + parm = DECL_CHAIN (parm), typelt = TREE_CHAIN (typelt), parmno++) + { + type = TREE_VALUE (typelt); + if (type == error_mark_node) + continue; + + if (!COMPLETE_TYPE_P (type)) + { + if (funcdef_flag) + { + if (DECL_NAME (parm)) + error_at (input_location, + "parameter %u (%q+D) has incomplete type", + parmno, parm); + else + error_at (DECL_SOURCE_LOCATION (parm), + "parameter %u has incomplete type", + parmno); + + TREE_VALUE (typelt) = error_mark_node; + TREE_TYPE (parm) = error_mark_node; + arg_types = NULL_TREE; + } + else if (VOID_TYPE_P (type)) + { + if (DECL_NAME (parm)) + warning_at (input_location, 0, + "parameter %u (%q+D) has void type", + parmno, parm); + else + warning_at (DECL_SOURCE_LOCATION (parm), 0, + "parameter %u has void type", + parmno); + } + } + + if (DECL_NAME (parm) && TREE_USED (parm)) + warn_if_shadowing (parm); + } + return arg_types; + } +} + +/* Allocate and initialize a c_arg_info structure from the parser's + obstack. */ + +struct c_arg_info * +build_arg_info (void) +{ + struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info); + ret->parms = NULL_TREE; + ret->tags = NULL; + ret->types = NULL_TREE; + ret->others = NULL_TREE; + ret->pending_sizes = NULL; + ret->had_vla_unspec = 0; + return ret; +} + +/* Take apart the current scope and return a c_arg_info structure with + info on a parameter list just parsed. + + This structure is later fed to 'grokparms' and 'store_parm_decls'. + + ELLIPSIS being true means the argument list ended in '...' so don't + append a sentinel (void_list_node) to the end of the type-list. + + EXPR is NULL or an expression that needs to be evaluated for the + side effects of array size expressions in the parameters. */ + +struct c_arg_info * +get_parm_info (bool ellipsis, tree expr) +{ + struct c_binding *b = current_scope->bindings; + struct c_arg_info *arg_info = build_arg_info (); + + tree parms = NULL_TREE; + vec *tags = NULL; + tree types = NULL_TREE; + tree others = NULL_TREE; + + bool gave_void_only_once_err = false; + + arg_info->had_vla_unspec = current_scope->had_vla_unspec; + + /* The bindings in this scope must not get put into a block. + We will take care of deleting the binding nodes. */ + current_scope->bindings = 0; + + /* This function is only called if there was *something* on the + parameter list. */ + gcc_assert (b); + + /* A parameter list consisting solely of 'void' indicates that the + function takes no arguments. But if the 'void' is qualified + (by 'const' or 'volatile'), or has a storage class specifier + ('register'), then the behavior is undefined; issue an error. + Typedefs for 'void' are OK (see DR#157). */ + if (b->prev == 0 /* one binding */ + && TREE_CODE (b->decl) == PARM_DECL /* which is a parameter */ + && !DECL_NAME (b->decl) /* anonymous */ + && VOID_TYPE_P (TREE_TYPE (b->decl))) /* of void type */ + { + if (TYPE_QUALS (TREE_TYPE (b->decl)) != TYPE_UNQUALIFIED + || C_DECL_REGISTER (b->decl)) + error_at (b->locus, "% as only parameter may not be qualified"); + + /* There cannot be an ellipsis. */ + if (ellipsis) + error_at (b->locus, "% must be the only parameter"); + + arg_info->types = void_list_node; + return arg_info; + } + + if (!ellipsis) + types = void_list_node; + + /* Break up the bindings list into parms, tags, types, and others; + apply sanity checks; purge the name-to-decl bindings. */ + while (b) + { + tree decl = b->decl; + tree type = TREE_TYPE (decl); + c_arg_tag tag; + const char *keyword; + + switch (TREE_CODE (decl)) + { + case PARM_DECL: + if (b->id) + { + gcc_assert (I_SYMBOL_BINDING (b->id) == b); + I_SYMBOL_BINDING (b->id) = b->shadowed; + } + + /* Check for forward decls that never got their actual decl. */ + if (TREE_ASM_WRITTEN (decl)) + error_at (b->locus, + "parameter %q+D has just a forward declaration", decl); + /* Check for (..., void, ...) and issue an error. */ + else if (VOID_TYPE_P (type) && !DECL_NAME (decl)) + { + if (!gave_void_only_once_err) + { + error_at (b->locus, "% must be the only parameter"); + gave_void_only_once_err = true; + } + } + else + { + /* Valid parameter, add it to the list. */ + DECL_CHAIN (decl) = parms; + parms = decl; + + /* Since there is a prototype, args are passed in their + declared types. The back end may override this later. */ + DECL_ARG_TYPE (decl) = type; + types = tree_cons (0, type, types); + } + break; + + case ENUMERAL_TYPE: keyword = "enum"; goto tag; + case UNION_TYPE: keyword = "union"; goto tag; + case RECORD_TYPE: keyword = "struct"; goto tag; + tag: + /* Types may not have tag-names, in which case the type + appears in the bindings list with b->id NULL. */ + if (b->id) + { + gcc_assert (I_TAG_BINDING (b->id) == b); + I_TAG_BINDING (b->id) = b->shadowed; + } + + /* Warn about any struct, union or enum tags defined in a + parameter list. The scope of such types is limited to + the parameter list, which is rarely if ever desirable + (it's impossible to call such a function with type- + correct arguments). An anonymous union parm type is + meaningful as a GNU extension, so don't warn for that. */ + if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE) + { + if (b->id) + /* The %s will be one of 'struct', 'union', or 'enum'. */ + warning_at (b->locus, 0, + "%<%s %E%> declared inside parameter list" + " will not be visible outside of this definition or" + " declaration", keyword, b->id); + else + /* The %s will be one of 'struct', 'union', or 'enum'. */ + warning_at (b->locus, 0, + "anonymous %s declared inside parameter list" + " will not be visible outside of this definition or" + " declaration", keyword); + } + + tag.id = b->id; + tag.type = decl; + vec_safe_push (tags, tag); + break; + + case FUNCTION_DECL: + /* FUNCTION_DECLs appear when there is an implicit function + declaration in the parameter list. */ + gcc_assert (b->nested || seen_error ()); + goto set_shadowed; + + case CONST_DECL: + case TYPE_DECL: + /* CONST_DECLs appear here when we have an embedded enum, + and TYPE_DECLs appear here when we have an embedded struct + or union. No warnings for this - we already warned about the + type itself. */ + + /* When we reinsert this decl in the function body, we need + to reconstruct whether it was marked as nested. */ + gcc_assert (!b->nested); + DECL_CHAIN (decl) = others; + others = decl; + /* fall through */ + + case ERROR_MARK: + set_shadowed: + /* error_mark_node appears here when we have an undeclared + variable. Just throw it away. */ + if (b->id) + { + gcc_assert (I_SYMBOL_BINDING (b->id) == b); + I_SYMBOL_BINDING (b->id) = b->shadowed; + } + break; + + /* Other things that might be encountered. */ + case LABEL_DECL: + case VAR_DECL: + default: + gcc_unreachable (); + } + + b = free_binding_and_advance (b); + } + + arg_info->parms = parms; + arg_info->tags = tags; + arg_info->types = types; + arg_info->others = others; + arg_info->pending_sizes = expr; + return arg_info; +} + +/* Get the struct, enum or union (CODE says which) with tag NAME. + Define the tag as a forward-reference with location LOC if it is + not defined. HAVE_STD_ATTRS says whether any standard attributes + were present after the struct, union or enum keyword; ATTRS are the + standard attributes present there. Return a c_typespec structure + for the type specifier. */ + +struct c_typespec +parser_xref_tag (location_t loc, enum tree_code code, tree name, + bool have_std_attrs, tree attrs) +{ + struct c_typespec ret; + tree ref; + location_t refloc; + + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + + /* If a cross reference is requested, look up the type + already defined for this tag and return it. */ + + ref = lookup_tag (code, name, false, &refloc); + /* If this is the right type of tag, return what we found. + (This reference will be shadowed by shadow_tag later if appropriate.) + If this is the wrong type of tag, do not return it. If it was the + wrong type in the same scope, we will have had an error + message already; if in a different scope and declaring + a name, pending_xref_error will give an error message; but if in a + different scope and not declaring a name, this tag should + shadow the previous declaration of a different type of tag, and + this would not work properly if we return the reference found. + (For example, with "struct foo" in an outer scope, "union foo;" + must shadow that tag with a new one of union type.) */ + ret.kind = (ref + ? (have_std_attrs ? ctsk_tagref_attrs : ctsk_tagref) + : (have_std_attrs ? ctsk_tagfirstref_attrs : ctsk_tagfirstref)); + if (ref && TREE_CODE (ref) == code) + { + decl_attributes (&ref, attrs, (int) ATTR_FLAG_TYPE_IN_PLACE); + if (C_TYPE_DEFINED_IN_STRUCT (ref) + && loc != UNKNOWN_LOCATION + && warn_cxx_compat) + { + switch (code) + { + case ENUMERAL_TYPE: + warning_at (loc, OPT_Wc___compat, + ("enum type defined in struct or union " + "is not visible in C++")); + inform (refloc, "enum type defined here"); + break; + case RECORD_TYPE: + warning_at (loc, OPT_Wc___compat, + ("struct defined in struct or union " + "is not visible in C++")); + inform (refloc, "struct defined here"); + break; + case UNION_TYPE: + warning_at (loc, OPT_Wc___compat, + ("union defined in struct or union " + "is not visible in C++")); + inform (refloc, "union defined here"); + break; + default: + gcc_unreachable(); + } + } + + ret.spec = ref; + return ret; + } + + /* If no such tag is yet defined, create a forward-reference node + and record it as the "definition". + When a real declaration of this type is found, + the forward-reference will be altered into a real type. */ + + ref = make_node (code); + if (code == ENUMERAL_TYPE) + { + /* Give the type a default layout like unsigned int + to avoid crashing if it does not get defined. */ + SET_TYPE_MODE (ref, TYPE_MODE (unsigned_type_node)); + SET_TYPE_ALIGN (ref, TYPE_ALIGN (unsigned_type_node)); + TYPE_USER_ALIGN (ref) = 0; + TYPE_UNSIGNED (ref) = 1; + TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node); + TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node); + TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); + } + + pushtag (loc, name, ref); + decl_attributes (&ref, attrs, (int) ATTR_FLAG_TYPE_IN_PLACE); + + ret.spec = ref; + return ret; +} + +/* Get the struct, enum or union (CODE says which) with tag NAME. + Define the tag as a forward-reference if it is not defined. + Return a tree for the type. */ + +tree +xref_tag (enum tree_code code, tree name) +{ + return parser_xref_tag (input_location, code, name, false, NULL_TREE).spec; +} + +/* Make sure that the tag NAME is defined *in the current scope* + at least as a forward reference. + LOC is the location of the struct's definition. + CODE says which kind of tag NAME ought to be. + + This stores the current value of the file static STRUCT_PARSE_INFO + in *ENCLOSING_STRUCT_PARSE_INFO, and points STRUCT_PARSE_INFO at a + new c_struct_parse_info structure. The old value of + STRUCT_PARSE_INFO is restored in finish_struct. */ + +tree +start_struct (location_t loc, enum tree_code code, tree name, + class c_struct_parse_info **enclosing_struct_parse_info) +{ + /* If there is already a tag defined at this scope + (as a forward reference), just return it. */ + + tree ref = NULL_TREE; + location_t refloc = UNKNOWN_LOCATION; + + if (name != NULL_TREE) + ref = lookup_tag (code, name, true, &refloc); + if (ref && TREE_CODE (ref) == code) + { + if (TYPE_STUB_DECL (ref)) + refloc = DECL_SOURCE_LOCATION (TYPE_STUB_DECL (ref)); + + if (TYPE_SIZE (ref)) + { + if (code == UNION_TYPE) + error_at (loc, "redefinition of %", name); + else + error_at (loc, "redefinition of %", name); + if (refloc != UNKNOWN_LOCATION) + inform (refloc, "originally defined here"); + /* Don't create structures using a name already in use. */ + ref = NULL_TREE; + } + else if (C_TYPE_BEING_DEFINED (ref)) + { + if (code == UNION_TYPE) + error_at (loc, "nested redefinition of %", name); + else + error_at (loc, "nested redefinition of %", name); + /* Don't bother to report "originally defined here" for a + nested redefinition; the original definition should be + obvious. */ + /* Don't create structures that contain themselves. */ + ref = NULL_TREE; + } + } + + /* Otherwise create a forward-reference just so the tag is in scope. */ + + if (ref == NULL_TREE || TREE_CODE (ref) != code) + { + ref = make_node (code); + pushtag (loc, name, ref); + } + + C_TYPE_BEING_DEFINED (ref) = 1; + for (tree v = TYPE_MAIN_VARIANT (ref); v; v = TYPE_NEXT_VARIANT (v)) + TYPE_PACKED (v) = flag_pack_struct; + + *enclosing_struct_parse_info = struct_parse_info; + struct_parse_info = new c_struct_parse_info (); + + /* FIXME: This will issue a warning for a use of a type defined + within a statement expr used within sizeof, et. al. This is not + terribly serious as C++ doesn't permit statement exprs within + sizeof anyhow. */ + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + warning_at (loc, OPT_Wc___compat, + "defining type in %qs expression is invalid in C++", + (in_sizeof + ? "sizeof" + : (in_typeof ? "typeof" : "alignof"))); + + return ref; +} + +/* Process the specs, declarator and width (NULL if omitted) + of a structure component, returning a FIELD_DECL node. + WIDTH is non-NULL for bit-fields only, and is an INTEGER_CST node. + DECL_ATTRS is as for grokdeclarator. + + LOC is the location of the structure component. + + This is done during the parsing of the struct declaration. + The FIELD_DECL nodes are chained together and the lot of them + are ultimately passed to `build_struct' to make the RECORD_TYPE node. */ + +tree +grokfield (location_t loc, + struct c_declarator *declarator, struct c_declspecs *declspecs, + tree width, tree *decl_attrs) +{ + tree value; + + if (declarator->kind == cdk_id && declarator->u.id.id == NULL_TREE + && width == NULL_TREE) + { + /* This is an unnamed decl. + + If we have something of the form "union { list } ;" then this + is the anonymous union extension. Similarly for struct. + + If this is something of the form "struct foo;", then + If MS or Plan 9 extensions are enabled, this is handled as + an anonymous struct. + Otherwise this is a forward declaration of a structure tag. + + If this is something of the form "foo;" and foo is a TYPE_DECL, then + If foo names a structure or union without a tag, then this + is an anonymous struct (this is permitted by C11). + If MS or Plan 9 extensions are enabled and foo names a + structure, then again this is an anonymous struct. + Otherwise this is an error. + + Oh what a horrid tangled web we weave. I wonder if MS consciously + took this from Plan 9 or if it was an accident of implementation + that took root before someone noticed the bug... */ + + tree type = declspecs->type; + bool ok = false; + + if (RECORD_OR_UNION_TYPE_P (type) + && (flag_ms_extensions + || flag_plan9_extensions + || !declspecs->typedef_p)) + { + if (flag_ms_extensions || flag_plan9_extensions) + ok = true; + else if (TYPE_NAME (type) == NULL) + ok = true; + else + ok = false; + } + if (!ok) + { + pedwarn (loc, 0, "declaration does not declare anything"); + return NULL_TREE; + } + if (flag_isoc99) + pedwarn_c99 (loc, OPT_Wpedantic, + "ISO C99 doesn%'t support unnamed structs/unions"); + else + pedwarn_c99 (loc, OPT_Wpedantic, + "ISO C90 doesn%'t support unnamed structs/unions"); + } + + value = grokdeclarator (declarator, declspecs, FIELD, false, + width ? &width : NULL, decl_attrs, NULL, NULL, + DEPRECATED_NORMAL); + + finish_decl (value, loc, NULL_TREE, NULL_TREE, NULL_TREE); + DECL_INITIAL (value) = width; + if (width) + SET_DECL_C_BIT_FIELD (value); + + if (warn_cxx_compat && DECL_NAME (value) != NULL_TREE) + { + /* If we currently have a binding for this field, set the + in_struct field in the binding, so that we warn about lookups + which find it. */ + struct c_binding *b = I_SYMBOL_BINDING (DECL_NAME (value)); + if (b != NULL) + { + /* If the in_struct field is not yet set, push it on a list + to be cleared when this struct is finished. */ + if (!b->in_struct) + { + struct_parse_info->fields.safe_push (b); + b->in_struct = 1; + } + } + } + + return value; +} + +/* Subroutine of detect_field_duplicates: return whether X and Y, + which are both fields in the same struct, have duplicate field + names. */ + +static bool +is_duplicate_field (tree x, tree y) +{ + if (DECL_NAME (x) != NULL_TREE && DECL_NAME (x) == DECL_NAME (y)) + return true; + + /* When using -fplan9-extensions, an anonymous field whose name is a + typedef can duplicate a field name. */ + if (flag_plan9_extensions + && (DECL_NAME (x) == NULL_TREE || DECL_NAME (y) == NULL_TREE)) + { + tree xt, xn, yt, yn; + + xt = TREE_TYPE (x); + if (DECL_NAME (x) != NULL_TREE) + xn = DECL_NAME (x); + else if (RECORD_OR_UNION_TYPE_P (xt) + && TYPE_NAME (xt) != NULL_TREE + && TREE_CODE (TYPE_NAME (xt)) == TYPE_DECL) + xn = DECL_NAME (TYPE_NAME (xt)); + else + xn = NULL_TREE; + + yt = TREE_TYPE (y); + if (DECL_NAME (y) != NULL_TREE) + yn = DECL_NAME (y); + else if (RECORD_OR_UNION_TYPE_P (yt) + && TYPE_NAME (yt) != NULL_TREE + && TREE_CODE (TYPE_NAME (yt)) == TYPE_DECL) + yn = DECL_NAME (TYPE_NAME (yt)); + else + yn = NULL_TREE; + + if (xn != NULL_TREE && xn == yn) + return true; + } + + return false; +} + +/* Subroutine of detect_field_duplicates: add the fields of FIELDLIST + to HTAB, giving errors for any duplicates. */ + +static void +detect_field_duplicates_hash (tree fieldlist, + hash_table > *htab) +{ + tree x, y; + tree_node **slot; + + for (x = fieldlist; x ; x = DECL_CHAIN (x)) + if ((y = DECL_NAME (x)) != NULL_TREE) + { + slot = htab->find_slot (y, INSERT); + if (*slot) + { + error ("duplicate member %q+D", x); + DECL_NAME (x) = NULL_TREE; + } + *slot = y; + } + else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) + { + detect_field_duplicates_hash (TYPE_FIELDS (TREE_TYPE (x)), htab); + + /* When using -fplan9-extensions, an anonymous field whose + name is a typedef can duplicate a field name. */ + if (flag_plan9_extensions + && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE + && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL) + { + tree xn = DECL_NAME (TYPE_NAME (TREE_TYPE (x))); + slot = htab->find_slot (xn, INSERT); + if (*slot) + error ("duplicate member %q+D", TYPE_NAME (TREE_TYPE (x))); + *slot = xn; + } + } +} + +/* Generate an error for any duplicate field names in FIELDLIST. Munge + the list such that this does not present a problem later. */ + +static void +detect_field_duplicates (tree fieldlist) +{ + tree x, y; + int timeout = 10; + + /* If the struct is the list of instance variables of an Objective-C + class, then we need to check all the instance variables of + superclasses when checking for duplicates (since you can't have + an instance variable in a subclass with the same name as an + instance variable in a superclass). We pass on this job to the + Objective-C compiler. objc_detect_field_duplicates() will return + false if we are not checking the list of instance variables and + the C frontend should proceed with the standard field duplicate + checks. If we are checking the list of instance variables, the + ObjC frontend will do the check, emit the errors if needed, and + then return true. */ + if (c_dialect_objc ()) + if (objc_detect_field_duplicates (false)) + return; + + /* First, see if there are more than "a few" fields. + This is trivially true if there are zero or one fields. */ + if (!fieldlist || !DECL_CHAIN (fieldlist)) + return; + x = fieldlist; + do { + timeout--; + if (DECL_NAME (x) == NULL_TREE + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) + timeout = 0; + x = DECL_CHAIN (x); + } while (timeout > 0 && x); + + /* If there were "few" fields and no anonymous structures or unions, + avoid the overhead of allocating a hash table. Instead just do + the nested traversal thing. */ + if (timeout > 0) + { + for (x = DECL_CHAIN (fieldlist); x; x = DECL_CHAIN (x)) + /* When using -fplan9-extensions, we can have duplicates + between typedef names and fields. */ + if (DECL_NAME (x) + || (flag_plan9_extensions + && DECL_NAME (x) == NULL_TREE + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)) + && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE + && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL)) + { + for (y = fieldlist; y != x; y = TREE_CHAIN (y)) + if (is_duplicate_field (y, x)) + { + error ("duplicate member %q+D", x); + DECL_NAME (x) = NULL_TREE; + } + } + } + else + { + hash_table > htab (37); + detect_field_duplicates_hash (fieldlist, &htab); + } +} + +/* Finish up struct info used by -Wc++-compat. */ + +static void +warn_cxx_compat_finish_struct (tree fieldlist, enum tree_code code, + location_t record_loc) +{ + unsigned int ix; + tree x; + struct c_binding *b; + + if (fieldlist == NULL_TREE) + { + if (code == RECORD_TYPE) + warning_at (record_loc, OPT_Wc___compat, + "empty struct has size 0 in C, size 1 in C++"); + else + warning_at (record_loc, OPT_Wc___compat, + "empty union has size 0 in C, size 1 in C++"); + } + + /* Set the C_TYPE_DEFINED_IN_STRUCT flag for each type defined in + the current struct. We do this now at the end of the struct + because the flag is used to issue visibility warnings, and we + only want to issue those warnings if the type is referenced + outside of the struct declaration. */ + FOR_EACH_VEC_ELT (struct_parse_info->struct_types, ix, x) + C_TYPE_DEFINED_IN_STRUCT (x) = 1; + + /* The TYPEDEFS_SEEN field of STRUCT_PARSE_INFO is a list of + typedefs used when declaring fields in this struct. If the name + of any of the fields is also a typedef name then the struct would + not parse in C++, because the C++ lookup rules say that the + typedef name would be looked up in the context of the struct, and + would thus be the field rather than the typedef. */ + if (!struct_parse_info->typedefs_seen.is_empty () + && fieldlist != NULL_TREE) + { + /* Use a hash_set using the name of the typedef. We can use + a hash_set because identifiers are interned. */ + hash_set tset; + + FOR_EACH_VEC_ELT (struct_parse_info->typedefs_seen, ix, x) + tset.add (DECL_NAME (x)); + + for (x = fieldlist; x != NULL_TREE; x = DECL_CHAIN (x)) + { + if (DECL_NAME (x) != NULL_TREE + && tset.contains (DECL_NAME (x))) + { + warning_at (DECL_SOURCE_LOCATION (x), OPT_Wc___compat, + ("using %qD as both field and typedef name is " + "invalid in C++"), + x); + /* FIXME: It would be nice to report the location where + the typedef name is used. */ + } + } + } + + /* For each field which has a binding and which was not defined in + an enclosing struct, clear the in_struct field. */ + FOR_EACH_VEC_ELT (struct_parse_info->fields, ix, b) + b->in_struct = 0; +} + +/* Function to help qsort sort FIELD_DECLs by name order. */ + +static int +field_decl_cmp (const void *x_p, const void *y_p) +{ + const tree *const x = (const tree *) x_p; + const tree *const y = (const tree *) y_p; + + if (DECL_NAME (*x) == DECL_NAME (*y)) + /* A nontype is "greater" than a type. */ + return (TREE_CODE (*y) == TYPE_DECL) - (TREE_CODE (*x) == TYPE_DECL); + if (DECL_NAME (*x) == NULL_TREE) + return -1; + if (DECL_NAME (*y) == NULL_TREE) + return 1; + if (DECL_NAME (*x) < DECL_NAME (*y)) + return -1; + return 1; +} + +/* If this structure or union completes the type of any previous + variable declaration, lay it out and output its rtl. */ +static void +finish_incomplete_vars (tree incomplete_vars, bool toplevel) +{ + for (tree x = incomplete_vars; x; x = TREE_CHAIN (x)) + { + tree decl = TREE_VALUE (x); + if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + layout_array_type (TREE_TYPE (decl)); + if (TREE_CODE (decl) != TYPE_DECL) + { + relayout_decl (decl); + if (c_dialect_objc ()) + objc_check_decl (decl); + rest_of_decl_compilation (decl, toplevel, 0); + } + } +} + +/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T. + LOC is the location of the RECORD_TYPE or UNION_TYPE's definition. + FIELDLIST is a chain of FIELD_DECL nodes for the fields. + ATTRIBUTES are attributes to be applied to the structure. + + ENCLOSING_STRUCT_PARSE_INFO is the value of STRUCT_PARSE_INFO when + the struct was started. */ + +tree +finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, + class c_struct_parse_info *enclosing_struct_parse_info) +{ + tree x; + bool toplevel = file_scope == current_scope; + + /* If this type was previously laid out as a forward reference, + make sure we lay it out again. */ + + TYPE_SIZE (t) = NULL_TREE; + + decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); + + if (pedantic) + { + for (x = fieldlist; x; x = DECL_CHAIN (x)) + { + if (DECL_NAME (x) != NULL_TREE) + break; + if (flag_isoc11 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) + break; + } + + if (x == NULL_TREE) + { + if (TREE_CODE (t) == UNION_TYPE) + { + if (fieldlist) + pedwarn (loc, OPT_Wpedantic, "union has no named members"); + else + pedwarn (loc, OPT_Wpedantic, "union has no members"); + } + else + { + if (fieldlist) + pedwarn (loc, OPT_Wpedantic, "struct has no named members"); + else + pedwarn (loc, OPT_Wpedantic, "struct has no members"); + } + } + } + + /* Install struct as DECL_CONTEXT of each field decl. + Also process specified field sizes, found in the DECL_INITIAL, + storing 0 there after the type has been changed to precision equal + to its width, rather than the precision of the specified standard + type. (Correct layout requires the original type to have been preserved + until now.) */ + + bool saw_named_field = false; + for (x = fieldlist; x; x = DECL_CHAIN (x)) + { + if (TREE_TYPE (x) == error_mark_node) + continue; + + DECL_CONTEXT (x) = t; + + /* If any field is const, the structure type is pseudo-const. */ + if (TREE_READONLY (x)) + C_TYPE_FIELDS_READONLY (t) = 1; + else + { + /* A field that is pseudo-const makes the structure likewise. */ + tree t1 = strip_array_types (TREE_TYPE (x)); + if (RECORD_OR_UNION_TYPE_P (t1) && C_TYPE_FIELDS_READONLY (t1)) + C_TYPE_FIELDS_READONLY (t) = 1; + } + + /* Any field that is volatile means variables of this type must be + treated in some ways as volatile. */ + if (TREE_THIS_VOLATILE (x)) + C_TYPE_FIELDS_VOLATILE (t) = 1; + + /* Any field of nominal variable size implies structure is too. */ + if (C_DECL_VARIABLE_SIZE (x)) + C_TYPE_VARIABLE_SIZE (t) = 1; + + if (DECL_C_BIT_FIELD (x)) + { + unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x)); + DECL_SIZE (x) = bitsize_int (width); + DECL_BIT_FIELD (x) = 1; + } + + if (TYPE_PACKED (t) + && (DECL_BIT_FIELD (x) + || TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT)) + DECL_PACKED (x) = 1; + + /* Detect flexible array member in an invalid context. */ + if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE + && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE + && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE + && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE) + { + if (TREE_CODE (t) == UNION_TYPE) + { + error_at (DECL_SOURCE_LOCATION (x), + "flexible array member in union"); + TREE_TYPE (x) = error_mark_node; + } + else if (DECL_CHAIN (x) != NULL_TREE) + { + error_at (DECL_SOURCE_LOCATION (x), + "flexible array member not at end of struct"); + TREE_TYPE (x) = error_mark_node; + } + else if (!saw_named_field) + { + error_at (DECL_SOURCE_LOCATION (x), + "flexible array member in a struct with no named " + "members"); + TREE_TYPE (x) = error_mark_node; + } + } + + if (pedantic && TREE_CODE (t) == RECORD_TYPE + && flexible_array_type_p (TREE_TYPE (x))) + pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, + "invalid use of structure with flexible array member"); + + if (DECL_NAME (x) + || RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) + saw_named_field = true; + } + + detect_field_duplicates (fieldlist); + + /* Now we have the nearly final fieldlist. Record it, + then lay out the structure or union (including the fields). */ + + TYPE_FIELDS (t) = fieldlist; + + maybe_apply_pragma_scalar_storage_order (t); + + layout_type (t); + + if (TYPE_SIZE_UNIT (t) + && TREE_CODE (TYPE_SIZE_UNIT (t)) == INTEGER_CST + && !TREE_OVERFLOW (TYPE_SIZE_UNIT (t)) + && !valid_constant_size_p (TYPE_SIZE_UNIT (t))) + error ("type %qT is too large", t); + + /* Give bit-fields their proper types and rewrite the type of array fields + with scalar component if the enclosing type has reverse storage order. */ + for (tree field = fieldlist; field; field = DECL_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL + && DECL_INITIAL (field) + && TREE_TYPE (field) != error_mark_node) + { + unsigned HOST_WIDE_INT width + = tree_to_uhwi (DECL_INITIAL (field)); + tree type = TREE_TYPE (field); + if (width != TYPE_PRECISION (type)) + { + TREE_TYPE (field) + = c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type)); + SET_DECL_MODE (field, TYPE_MODE (TREE_TYPE (field))); + } + DECL_INITIAL (field) = NULL_TREE; + } + else if (TYPE_REVERSE_STORAGE_ORDER (t) + && TREE_CODE (field) == FIELD_DECL + && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE) + { + tree ftype = TREE_TYPE (field); + tree ctype = strip_array_types (ftype); + if (!RECORD_OR_UNION_TYPE_P (ctype) && TYPE_MODE (ctype) != QImode) + { + tree fmain_type = TYPE_MAIN_VARIANT (ftype); + tree *typep = &fmain_type; + do { + *typep = build_distinct_type_copy (*typep); + TYPE_REVERSE_STORAGE_ORDER (*typep) = 1; + typep = &TREE_TYPE (*typep); + } while (TREE_CODE (*typep) == ARRAY_TYPE); + TREE_TYPE (field) + = c_build_qualified_type (fmain_type, TYPE_QUALS (ftype)); + } + } + + /* Warn on problematic type punning for storage order purposes. */ + if (TREE_CODE (t) == UNION_TYPE + && TREE_CODE (field) == FIELD_DECL + && AGGREGATE_TYPE_P (TREE_TYPE (field))) + { + tree ftype = TREE_TYPE (field); + if (TREE_CODE (ftype) == ARRAY_TYPE) + ftype = strip_array_types (ftype); + if (RECORD_OR_UNION_TYPE_P (ftype) + && TYPE_REVERSE_STORAGE_ORDER (ftype) + != TYPE_REVERSE_STORAGE_ORDER (t)) + warning_at (DECL_SOURCE_LOCATION (field), + OPT_Wscalar_storage_order, + "type punning toggles scalar storage order"); + } + } + + /* Now we have the truly final field list. + Store it in this type and in the variants. */ + + TYPE_FIELDS (t) = fieldlist; + + /* If there are lots of fields, sort so we can look through them fast. + We arbitrarily consider 16 or more elts to be "a lot". */ + + { + int len = 0; + + for (x = fieldlist; x; x = DECL_CHAIN (x)) + { + if (len > 15 || DECL_NAME (x) == NULL) + break; + len += 1; + } + + if (len > 15) + { + tree *field_array; + struct lang_type *space; + struct sorted_fields_type *space2; + + len += list_length (x); + + /* Use the same allocation policy here that make_node uses, to + ensure that this lives as long as the rest of the struct decl. + All decls in an inline function need to be saved. */ + + space = ggc_cleared_alloc (); + space2 = (sorted_fields_type *) ggc_internal_alloc + (sizeof (struct sorted_fields_type) + len * sizeof (tree)); + + len = 0; + space->s = space2; + field_array = &space2->elts[0]; + for (x = fieldlist; x; x = DECL_CHAIN (x)) + { + field_array[len++] = x; + + /* If there is anonymous struct or union, break out of the loop. */ + if (DECL_NAME (x) == NULL) + break; + } + /* Found no anonymous struct/union. Add the TYPE_LANG_SPECIFIC. */ + if (x == NULL) + { + TYPE_LANG_SPECIFIC (t) = space; + TYPE_LANG_SPECIFIC (t)->s->len = len; + field_array = TYPE_LANG_SPECIFIC (t)->s->elts; + qsort (field_array, len, sizeof (tree), field_decl_cmp); + } + } + } + + /* If this was supposed to be a transparent union, but we can't + make it one, warn and turn off the flag. */ + if (TREE_CODE (t) == UNION_TYPE + && TYPE_TRANSPARENT_AGGR (t) + && (!TYPE_FIELDS (t) || TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t)))) + { + TYPE_TRANSPARENT_AGGR (t) = 0; + warning_at (loc, 0, "union cannot be made transparent"); + } + + tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)); + for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) + { + TYPE_FIELDS (x) = TYPE_FIELDS (t); + TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t); + TYPE_TRANSPARENT_AGGR (x) = TYPE_TRANSPARENT_AGGR (t); + C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t); + C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t); + C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); + C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE; + } + + /* Update type location to the one of the definition, instead of e.g. + a forward declaration. */ + if (TYPE_STUB_DECL (t)) + DECL_SOURCE_LOCATION (TYPE_STUB_DECL (t)) = loc; + + /* Finish debugging output for this type. */ + rest_of_type_compilation (t, toplevel); + + finish_incomplete_vars (incomplete_vars, toplevel); + + /* If we're inside a function proper, i.e. not file-scope and not still + parsing parameters, then arrange for the size of a variable sized type + to be bound now. */ + if (building_stmt_list_p () && variably_modified_type_p (t, NULL_TREE)) + add_stmt (build_stmt (loc, + DECL_EXPR, build_decl (loc, TYPE_DECL, NULL, t))); + + if (warn_cxx_compat) + warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc); + + delete struct_parse_info; + + struct_parse_info = enclosing_struct_parse_info; + + /* If this struct is defined inside a struct, add it to + struct_types. */ + if (warn_cxx_compat + && struct_parse_info != NULL + && !in_sizeof && !in_typeof && !in_alignof) + struct_parse_info->struct_types.safe_push (t); + + return t; +} + +static struct { + gt_pointer_operator new_value; + void *cookie; +} resort_data; + +/* This routine compares two fields like field_decl_cmp but using the +pointer operator in resort_data. */ + +static int +resort_field_decl_cmp (const void *x_p, const void *y_p) +{ + const tree *const x = (const tree *) x_p; + const tree *const y = (const tree *) y_p; + + if (DECL_NAME (*x) == DECL_NAME (*y)) + /* A nontype is "greater" than a type. */ + return (TREE_CODE (*y) == TYPE_DECL) - (TREE_CODE (*x) == TYPE_DECL); + if (DECL_NAME (*x) == NULL_TREE) + return -1; + if (DECL_NAME (*y) == NULL_TREE) + return 1; + { + tree d1 = DECL_NAME (*x); + tree d2 = DECL_NAME (*y); + resort_data.new_value (&d1, &d1, resort_data.cookie); + resort_data.new_value (&d2, &d2, resort_data.cookie); + if (d1 < d2) + return -1; + } + return 1; +} + +/* Resort DECL_SORTED_FIELDS because pointers have been reordered. */ + +void +resort_sorted_fields (void *obj, + void * ARG_UNUSED (orig_obj), + gt_pointer_operator new_value, + void *cookie) +{ + struct sorted_fields_type *sf = (struct sorted_fields_type *) obj; + resort_data.new_value = new_value; + resort_data.cookie = cookie; + qsort (&sf->elts[0], sf->len, sizeof (tree), + resort_field_decl_cmp); +} + +/* Lay out the type T, and its element type, and so on. */ + +static void +layout_array_type (tree t) +{ + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + layout_array_type (TREE_TYPE (t)); + layout_type (t); +} + +/* Begin compiling the definition of an enumeration type. + NAME is its name (or null if anonymous). + LOC is the enum's location. + Returns the type object, as yet incomplete. + Also records info about it so that build_enumerator + may be used to declare the individual values as they are read. */ + +tree +start_enum (location_t loc, struct c_enum_contents *the_enum, tree name) +{ + tree enumtype = NULL_TREE; + location_t enumloc = UNKNOWN_LOCATION; + + /* If this is the real definition for a previous forward reference, + fill in the contents in the same object that used to be the + forward reference. */ + + if (name != NULL_TREE) + enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc); + + if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE) + { + enumtype = make_node (ENUMERAL_TYPE); + pushtag (loc, name, enumtype); + } + /* Update type location to the one of the definition, instead of e.g. + a forward declaration. */ + else if (TYPE_STUB_DECL (enumtype)) + { + enumloc = DECL_SOURCE_LOCATION (TYPE_STUB_DECL (enumtype)); + DECL_SOURCE_LOCATION (TYPE_STUB_DECL (enumtype)) = loc; + } + + if (C_TYPE_BEING_DEFINED (enumtype)) + error_at (loc, "nested redefinition of %", name); + + C_TYPE_BEING_DEFINED (enumtype) = 1; + + if (TYPE_VALUES (enumtype) != NULL_TREE) + { + /* This enum is a named one that has been declared already. */ + error_at (loc, "redeclaration of %", name); + if (enumloc != UNKNOWN_LOCATION) + inform (enumloc, "originally defined here"); + + /* Completely replace its old definition. + The old enumerators remain defined, however. */ + TYPE_VALUES (enumtype) = NULL_TREE; + } + + the_enum->enum_next_value = integer_zero_node; + the_enum->enum_overflow = 0; + + if (flag_short_enums) + for (tree v = TYPE_MAIN_VARIANT (enumtype); v; v = TYPE_NEXT_VARIANT (v)) + TYPE_PACKED (v) = 1; + + /* FIXME: This will issue a warning for a use of a type defined + within sizeof in a statement expr. This is not terribly serious + as C++ doesn't permit statement exprs within sizeof anyhow. */ + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + warning_at (loc, OPT_Wc___compat, + "defining type in %qs expression is invalid in C++", + (in_sizeof + ? "sizeof" + : (in_typeof ? "typeof" : "alignof"))); + + return enumtype; +} + +/* After processing and defining all the values of an enumeration type, + install their decls in the enumeration type and finish it off. + ENUMTYPE is the type object, VALUES a list of decl-value pairs, + and ATTRIBUTES are the specified attributes. + Returns ENUMTYPE. */ + +tree +finish_enum (tree enumtype, tree values, tree attributes) +{ + tree pair, tem; + tree minnode = NULL_TREE, maxnode = NULL_TREE; + int precision; + signop sign; + bool toplevel = (file_scope == current_scope); + struct lang_type *lt; + + decl_attributes (&enumtype, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); + + /* Calculate the maximum value of any enumerator in this type. */ + + if (values == error_mark_node) + minnode = maxnode = integer_zero_node; + else + { + minnode = maxnode = TREE_VALUE (values); + for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair)) + { + tree value = TREE_VALUE (pair); + if (tree_int_cst_lt (maxnode, value)) + maxnode = value; + if (tree_int_cst_lt (value, minnode)) + minnode = value; + } + } + + /* Construct the final type of this enumeration. It is the same + as one of the integral types - the narrowest one that fits, except + that normally we only go as narrow as int - and signed iff any of + the values are negative. */ + sign = (tree_int_cst_sgn (minnode) >= 0) ? UNSIGNED : SIGNED; + precision = MAX (tree_int_cst_min_precision (minnode, sign), + tree_int_cst_min_precision (maxnode, sign)); + + /* If the precision of the type was specified with an attribute and it + was too small, give an error. Otherwise, use it. */ + if (TYPE_PRECISION (enumtype) && lookup_attribute ("mode", attributes)) + { + if (precision > TYPE_PRECISION (enumtype)) + { + TYPE_PRECISION (enumtype) = 0; + error ("specified mode too small for enumerated values"); + } + else + precision = TYPE_PRECISION (enumtype); + } + else + TYPE_PRECISION (enumtype) = 0; + + if (TYPE_PACKED (enumtype) + || precision > TYPE_PRECISION (integer_type_node) + || TYPE_PRECISION (enumtype)) + { + tem = c_common_type_for_size (precision, sign == UNSIGNED ? 1 : 0); + if (tem == NULL) + { + warning (0, "enumeration values exceed range of largest integer"); + tem = long_long_integer_type_node; + } + } + else + tem = sign == UNSIGNED ? unsigned_type_node : integer_type_node; + + TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); + TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); + TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); + SET_TYPE_ALIGN (enumtype, TYPE_ALIGN (tem)); + TYPE_SIZE (enumtype) = NULL_TREE; + TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); + + layout_type (enumtype); + + if (values != error_mark_node) + { + /* Change the type of the enumerators to be the enum type. We + need to do this irrespective of the size of the enum, for + proper type checking. Replace the DECL_INITIALs of the + enumerators, and the value slots of the list, with copies + that have the enum type; they cannot be modified in place + because they may be shared (e.g. integer_zero_node) Finally, + change the purpose slots to point to the names of the decls. */ + for (pair = values; pair; pair = TREE_CHAIN (pair)) + { + tree enu = TREE_PURPOSE (pair); + tree ini = DECL_INITIAL (enu); + + TREE_TYPE (enu) = enumtype; + + /* The ISO C Standard mandates enumerators to have type int, + even though the underlying type of an enum type is + unspecified. However, GCC allows enumerators of any + integer type as an extensions. build_enumerator() + converts any enumerators that fit in an int to type int, + to avoid promotions to unsigned types when comparing + integers with enumerators that fit in the int range. + When -pedantic is given, build_enumerator() would have + already warned about those that don't fit. Here we + convert the rest to the enumerator type. */ + if (TREE_TYPE (ini) != integer_type_node) + ini = convert (enumtype, ini); + + DECL_INITIAL (enu) = ini; + TREE_PURPOSE (pair) = DECL_NAME (enu); + TREE_VALUE (pair) = ini; + } + + TYPE_VALUES (enumtype) = values; + } + + /* Record the min/max values so that we can warn about bit-field + enumerations that are too small for the values. */ + lt = ggc_cleared_alloc (); + lt->enum_min = minnode; + lt->enum_max = maxnode; + TYPE_LANG_SPECIFIC (enumtype) = lt; + + /* Fix up all variant types of this enum type. */ + tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (enumtype)); + for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem)) + { + C_TYPE_INCOMPLETE_VARS (tem) = NULL_TREE; + if (tem == enumtype) + continue; + TYPE_VALUES (tem) = TYPE_VALUES (enumtype); + TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype); + TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype); + TYPE_SIZE (tem) = TYPE_SIZE (enumtype); + TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype); + SET_TYPE_MODE (tem, TYPE_MODE (enumtype)); + TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype); + SET_TYPE_ALIGN (tem, TYPE_ALIGN (enumtype)); + TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype); + TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); + TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); + } + + /* Finish debugging output for this type. */ + rest_of_type_compilation (enumtype, toplevel); + + finish_incomplete_vars (incomplete_vars, toplevel); + + /* If this enum is defined inside a struct, add it to + struct_types. */ + if (warn_cxx_compat + && struct_parse_info != NULL + && !in_sizeof && !in_typeof && !in_alignof) + struct_parse_info->struct_types.safe_push (enumtype); + + C_TYPE_BEING_DEFINED (enumtype) = 0; + + return enumtype; +} + +/* Build and install a CONST_DECL for one value of the + current enumeration type (one that was begun with start_enum). + DECL_LOC is the location of the enumerator. + LOC is the location of the '=' operator if any, DECL_LOC otherwise. + Return a tree-list containing the CONST_DECL and its value. + Assignment of sequential values by default is handled here. */ + +tree +build_enumerator (location_t decl_loc, location_t loc, + struct c_enum_contents *the_enum, tree name, tree value) +{ + tree decl, type; + + /* Validate and default VALUE. */ + + if (value != NULL_TREE) + { + /* Don't issue more errors for error_mark_node (i.e. an + undeclared identifier) - just ignore the value expression. */ + if (value == error_mark_node) + value = NULL_TREE; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (value))) + { + error_at (loc, "enumerator value for %qE is not an integer constant", + name); + value = NULL_TREE; + } + else + { + if (TREE_CODE (value) != INTEGER_CST) + { + value = c_fully_fold (value, false, NULL); + if (TREE_CODE (value) == INTEGER_CST) + pedwarn (loc, OPT_Wpedantic, + "enumerator value for %qE is not an integer " + "constant expression", name); + } + if (TREE_CODE (value) != INTEGER_CST) + { + error ("enumerator value for %qE is not an integer constant", + name); + value = NULL_TREE; + } + else + { + value = default_conversion (value); + constant_expression_warning (value); + } + } + } + + /* Default based on previous value. */ + /* It should no longer be possible to have NON_LVALUE_EXPR + in the default. */ + if (value == NULL_TREE) + { + value = the_enum->enum_next_value; + if (the_enum->enum_overflow) + error_at (loc, "overflow in enumeration values"); + } + /* Even though the underlying type of an enum is unspecified, the + type of enumeration constants is explicitly defined as int + (6.4.4.3/2 in the C99 Standard). GCC allows any integer type as + an extension. */ + else if (!int_fits_type_p (value, integer_type_node)) + pedwarn (loc, OPT_Wpedantic, + "ISO C restricts enumerator values to range of %"); + + /* The ISO C Standard mandates enumerators to have type int, even + though the underlying type of an enum type is unspecified. + However, GCC allows enumerators of any integer type as an + extensions. Here we convert any enumerators that fit in an int + to type int, to avoid promotions to unsigned types when comparing + integers with enumerators that fit in the int range. When + -pedantic is given, we would have already warned about those that + don't fit. We have to do this here rather than in finish_enum + because this value may be used to define more enumerators. */ + if (int_fits_type_p (value, integer_type_node)) + value = convert (integer_type_node, value); + + /* Set basis for default for next value. */ + the_enum->enum_next_value + = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), + PLUS_EXPR, value, integer_one_node, false); + the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value); + + /* Now create a declaration for the enum value name. */ + + type = TREE_TYPE (value); + type = c_common_type_for_size (MAX (TYPE_PRECISION (type), + TYPE_PRECISION (integer_type_node)), + (TYPE_PRECISION (type) + >= TYPE_PRECISION (integer_type_node) + && TYPE_UNSIGNED (type))); + + decl = build_decl (decl_loc, CONST_DECL, name, type); + DECL_INITIAL (decl) = convert (type, value); + pushdecl (decl); + + return tree_cons (decl, value, NULL_TREE); +} + +/* Implement LANG_HOOKS_SIMULATE_ENUM_DECL. */ + +tree +c_simulate_enum_decl (location_t loc, const char *name, + vec *values_ptr) +{ + location_t saved_loc = input_location; + input_location = loc; + + struct c_enum_contents the_enum; + tree enumtype = start_enum (loc, &the_enum, get_identifier (name)); + + tree value_chain = NULL_TREE; + string_int_pair *value; + vec values = *values_ptr; + unsigned int i; + FOR_EACH_VEC_ELT (values, i, value) + { + tree decl = build_enumerator (loc, loc, &the_enum, + get_identifier (value->first), + build_int_cst (integer_type_node, + value->second)); + TREE_CHAIN (decl) = value_chain; + value_chain = decl; + } + + finish_enum (enumtype, nreverse (value_chain), NULL_TREE); + + input_location = saved_loc; + return enumtype; +} + +/* Implement LANG_HOOKS_SIMULATE_RECORD_DECL. */ + +tree +c_simulate_record_decl (location_t loc, const char *name, + array_slice fields) +{ + location_t saved_loc = input_location; + input_location = loc; + + class c_struct_parse_info *struct_info; + tree ident = get_identifier (name); + tree type = start_struct (loc, RECORD_TYPE, ident, &struct_info); + + for (unsigned int i = 0; i < fields.size (); ++i) + { + DECL_FIELD_CONTEXT (fields[i]) = type; + if (i > 0) + DECL_CHAIN (fields[i - 1]) = fields[i]; + } + + finish_struct (loc, type, fields[0], NULL_TREE, struct_info); + + tree decl = build_decl (loc, TYPE_DECL, ident, type); + set_underlying_type (decl); + lang_hooks.decls.pushdecl (decl); + + input_location = saved_loc; + return type; +} + +/* Create the FUNCTION_DECL for a function definition. + DECLSPECS, DECLARATOR and ATTRIBUTES are the parts of + the declaration; they describe the function's name and the type it returns, + but twisted together in a fashion that parallels the syntax of C. + + This function creates a binding context for the function body + as well as setting up the FUNCTION_DECL in current_function_decl. + + Returns true on success. If the DECLARATOR is not suitable for a function + (it defines a datum instead), we return false to report a parse error. */ + +bool +start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, + tree attributes) +{ + tree decl1, old_decl; + tree restype, resdecl; + location_t loc; + + current_function_returns_value = 0; /* Assume, until we see it does. */ + current_function_returns_null = 0; + current_function_returns_abnormally = 0; + warn_about_return_type = 0; + c_switch_stack = NULL; + + /* Indicate no valid break/continue context. */ + in_statement = 0; + + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL, + &attributes, NULL, NULL, DEPRECATED_NORMAL); + invoke_plugin_callbacks (PLUGIN_START_PARSE_FUNCTION, decl1); + + /* If the declarator is not suitable for a function definition, + cause a syntax error. */ + if (decl1 == NULL_TREE + || TREE_CODE (decl1) != FUNCTION_DECL) + return false; + + loc = DECL_SOURCE_LOCATION (decl1); + + /* A nested function is not global. */ + if (current_function_decl != NULL_TREE) + TREE_PUBLIC (decl1) = 0; + + c_decl_attributes (&decl1, attributes, 0); + + if (DECL_DECLARED_INLINE_P (decl1) + && DECL_UNINLINABLE (decl1) + && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl1))) + warning_at (loc, OPT_Wattributes, + "inline function %qD given attribute %qs", + decl1, "noinline"); + + /* Handle gnu_inline attribute. */ + if (declspecs->inline_p + && !flag_gnu89_inline + && TREE_CODE (decl1) == FUNCTION_DECL + && (lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl1)) + || current_function_decl)) + { + if (declspecs->storage_class != csc_static) + DECL_EXTERNAL (decl1) = !DECL_EXTERNAL (decl1); + } + + announce_function (decl1); + + if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1)))) + { + error_at (loc, "return type is an incomplete type"); + /* Make it return void instead. */ + TREE_TYPE (decl1) + = build_function_type (void_type_node, + TYPE_ARG_TYPES (TREE_TYPE (decl1))); + } + + if (warn_about_return_type) + warn_defaults_to (loc, flag_isoc99 ? OPT_Wimplicit_int + : (warn_return_type > 0 ? OPT_Wreturn_type + : OPT_Wimplicit_int), + "return type defaults to %"); + + /* Make the init_value nonzero so pushdecl knows this is not tentative. + error_mark_node is replaced below (in pop_scope) with the BLOCK. */ + DECL_INITIAL (decl1) = error_mark_node; + + /* If this definition isn't a prototype and we had a prototype declaration + before, copy the arg type info from that prototype. */ + old_decl = lookup_name_in_scope (DECL_NAME (decl1), current_scope); + if (old_decl && TREE_CODE (old_decl) != FUNCTION_DECL) + old_decl = NULL_TREE; + + current_function_prototype_locus = UNKNOWN_LOCATION; + current_function_prototype_built_in = false; + current_function_prototype_arg_types = NULL_TREE; + tree newtype = TREE_TYPE (decl1); + tree oldtype = old_decl ? TREE_TYPE (old_decl) : newtype; + if (!prototype_p (newtype)) + { + tree oldrt = TREE_TYPE (oldtype); + tree newrt = TREE_TYPE (newtype); + if (old_decl != NULL_TREE + && TREE_CODE (oldtype) == FUNCTION_TYPE + && comptypes (oldrt, newrt)) + { + if (stdarg_p (oldtype)) + { + auto_diagnostic_group d; + warning_at (loc, 0, "%q+D defined as variadic function " + "without prototype", decl1); + locate_old_decl (old_decl); + } + TREE_TYPE (decl1) = composite_type (oldtype, newtype); + current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl); + current_function_prototype_built_in + = C_DECL_BUILTIN_PROTOTYPE (old_decl); + current_function_prototype_arg_types + = TYPE_ARG_TYPES (newtype); + } + if (TREE_PUBLIC (decl1)) + { + /* If there is an external prototype declaration of this + function, record its location but do not copy information + to this decl. This may be an invisible declaration + (built-in or in a scope which has finished) or simply + have more refined argument types than any declaration + found above. */ + struct c_binding *b; + for (b = I_SYMBOL_BINDING (DECL_NAME (decl1)); b; b = b->shadowed) + if (B_IN_SCOPE (b, external_scope)) + break; + if (b) + { + tree ext_decl, ext_type; + ext_decl = b->decl; + ext_type = b->u.type ? b->u.type : TREE_TYPE (ext_decl); + if (TREE_CODE (ext_type) == FUNCTION_TYPE + && comptypes (TREE_TYPE (TREE_TYPE (decl1)), + TREE_TYPE (ext_type))) + { + current_function_prototype_locus + = DECL_SOURCE_LOCATION (ext_decl); + current_function_prototype_built_in + = C_DECL_BUILTIN_PROTOTYPE (ext_decl); + current_function_prototype_arg_types + = TYPE_ARG_TYPES (ext_type); + } + } + } + } + + /* Optionally warn of old-fashioned def with no previous prototype. */ + if (warn_strict_prototypes + && old_decl != error_mark_node + && !prototype_p (TREE_TYPE (decl1)) + && C_DECL_ISNT_PROTOTYPE (old_decl)) + warning_at (loc, OPT_Wstrict_prototypes, + "function declaration isn%'t a prototype"); + /* Optionally warn of any global def with no previous prototype. */ + else if (warn_missing_prototypes + && old_decl != error_mark_node + && TREE_PUBLIC (decl1) + && !MAIN_NAME_P (DECL_NAME (decl1)) + && C_DECL_ISNT_PROTOTYPE (old_decl) + && !DECL_DECLARED_INLINE_P (decl1)) + warning_at (loc, OPT_Wmissing_prototypes, + "no previous prototype for %qD", decl1); + /* Optionally warn of any def with no previous prototype + if the function has already been used. */ + else if (warn_missing_prototypes + && old_decl != NULL_TREE + && old_decl != error_mark_node + && TREE_USED (old_decl) + && !prototype_p (TREE_TYPE (old_decl))) + warning_at (loc, OPT_Wmissing_prototypes, + "%qD was used with no prototype before its definition", decl1); + /* Optionally warn of any global def with no previous declaration. */ + else if (warn_missing_declarations + && TREE_PUBLIC (decl1) + && old_decl == NULL_TREE + && !MAIN_NAME_P (DECL_NAME (decl1)) + && !DECL_DECLARED_INLINE_P (decl1)) + warning_at (loc, OPT_Wmissing_declarations, + "no previous declaration for %qD", + decl1); + /* Optionally warn of any def with no previous declaration + if the function has already been used. */ + else if (warn_missing_declarations + && old_decl != NULL_TREE + && old_decl != error_mark_node + && TREE_USED (old_decl) + && C_DECL_IMPLICIT (old_decl)) + warning_at (loc, OPT_Wmissing_declarations, + "%qD was used with no declaration before its definition", decl1); + + /* This function exists in static storage. + (This does not mean `static' in the C sense!) */ + TREE_STATIC (decl1) = 1; + + /* This is the earliest point at which we might know the assembler + name of the function. Thus, if it's set before this, die horribly. */ + gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl1)); + + /* If #pragma weak was used, mark the decl weak now. */ + if (current_scope == file_scope) + maybe_apply_pragma_weak (decl1); + + /* Warn for unlikely, improbable, or stupid declarations of `main'. */ + if (warn_main && MAIN_NAME_P (DECL_NAME (decl1))) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1))) + != integer_type_node) + pedwarn (loc, OPT_Wmain, "return type of %qD is not %", decl1); + else if (TYPE_ATOMIC (TREE_TYPE (TREE_TYPE (decl1)))) + pedwarn (loc, OPT_Wmain, "%<_Atomic%>-qualified return type of %qD", + decl1); + + check_main_parameter_types (decl1); + + if (!TREE_PUBLIC (decl1)) + pedwarn (loc, OPT_Wmain, + "%qD is normally a non-static function", decl1); + } + + tree parms = current_function_arg_info->parms; + if (old_decl) + { + location_t origloc = DECL_SOURCE_LOCATION (old_decl); + warn_parm_array_mismatch (origloc, old_decl, parms); + } + + /* Record the decl so that the function name is defined. + If we already have a decl for this name, and it is a FUNCTION_DECL, + use the old decl. */ + + current_function_decl = pushdecl (decl1); + + if (tree access = build_attr_access_from_parms (parms, false)) + decl_attributes (¤t_function_decl, access, ATTR_FLAG_INTERNAL, + old_decl); + + push_scope (); + declare_parm_level (); + + restype = TREE_TYPE (TREE_TYPE (current_function_decl)); + resdecl = build_decl (loc, RESULT_DECL, NULL_TREE, restype); + DECL_ARTIFICIAL (resdecl) = 1; + DECL_IGNORED_P (resdecl) = 1; + DECL_RESULT (current_function_decl) = resdecl; + + start_fname_decls (); + + return true; +} + +/* Subroutine of store_parm_decls which handles new-style function + definitions (prototype format). The parms already have decls, so we + need only record them as in effect and complain if any redundant + old-style parm decls were written. */ +static void +store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info) +{ + tree decl; + c_arg_tag *tag; + unsigned ix; + + if (current_scope->bindings) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "old-style parameter declarations in prototyped " + "function definition"); + + /* Get rid of the old-style declarations. */ + pop_scope (); + push_scope (); + } + /* Don't issue this warning for nested functions, and don't issue this + warning if we got here because ARG_INFO_TYPES was error_mark_node + (this happens when a function definition has just an ellipsis in + its parameter list). */ + else if (!in_system_header_at (input_location) + && !current_function_scope + && arg_info->types != error_mark_node) + warning_at (DECL_SOURCE_LOCATION (fndecl), OPT_Wtraditional, + "traditional C rejects ISO C style function definitions"); + + /* Now make all the parameter declarations visible in the function body. + We can bypass most of the grunt work of pushdecl. */ + for (decl = arg_info->parms; decl; decl = DECL_CHAIN (decl)) + { + DECL_CONTEXT (decl) = current_function_decl; + if (DECL_NAME (decl)) + { + bind (DECL_NAME (decl), decl, current_scope, + /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); + if (!TREE_USED (decl)) + warn_if_shadowing (decl); + } + else + pedwarn_c11 (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic, + "ISO C does not support omitting parameter names in " + "function definitions before C2X"); + } + + /* Record the parameter list in the function declaration. */ + DECL_ARGUMENTS (fndecl) = arg_info->parms; + + /* Now make all the ancillary declarations visible, likewise. */ + for (decl = arg_info->others; decl; decl = DECL_CHAIN (decl)) + { + DECL_CONTEXT (decl) = current_function_decl; + if (DECL_NAME (decl)) + bind (DECL_NAME (decl), decl, current_scope, + /*invisible=*/false, + /*nested=*/(TREE_CODE (decl) == FUNCTION_DECL), + UNKNOWN_LOCATION); + } + + /* And all the tag declarations. */ + FOR_EACH_VEC_SAFE_ELT_REVERSE (arg_info->tags, ix, tag) + if (tag->id) + bind (tag->id, tag->type, current_scope, + /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION); +} + +/* Subroutine of store_parm_decls which handles old-style function + definitions (separate parameter list and declarations). */ + +static void +store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) +{ + struct c_binding *b; + tree parm, decl, last; + tree parmids = arg_info->parms; + hash_set seen_args; + + if (!in_system_header_at (input_location)) + { + if (flag_isoc2x) + pedwarn (DECL_SOURCE_LOCATION (fndecl), + OPT_Wold_style_definition, "old-style function definition"); + else + warning_at (DECL_SOURCE_LOCATION (fndecl), + OPT_Wold_style_definition, + "old-style function definition"); + } + + if (current_scope->had_vla_unspec) + error ("%<[*]%> not allowed in other than function prototype scope"); + + /* Match each formal parameter name with its declaration. Save each + decl in the appropriate TREE_PURPOSE slot of the parmids chain. */ + for (parm = parmids; parm; parm = TREE_CHAIN (parm)) + { + if (TREE_VALUE (parm) == NULL_TREE) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "parameter name missing from parameter list"); + TREE_PURPOSE (parm) = NULL_TREE; + continue; + } + + b = I_SYMBOL_BINDING (TREE_VALUE (parm)); + if (b && B_IN_CURRENT_SCOPE (b)) + { + decl = b->decl; + /* Skip erroneous parameters. */ + if (decl == error_mark_node) + continue; + /* If we got something other than a PARM_DECL it is an error. */ + if (TREE_CODE (decl) != PARM_DECL) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qD declared as a non-parameter", decl); + continue; + } + /* If the declaration is already marked, we have a duplicate + name. Complain and ignore the duplicate. */ + else if (seen_args.contains (decl)) + { + error_at (DECL_SOURCE_LOCATION (decl), + "multiple parameters named %qD", decl); + TREE_PURPOSE (parm) = NULL_TREE; + continue; + } + /* If the declaration says "void", complain and turn it into + an int. */ + else if (VOID_TYPE_P (TREE_TYPE (decl))) + { + error_at (DECL_SOURCE_LOCATION (decl), + "parameter %qD declared with void type", decl); + TREE_TYPE (decl) = integer_type_node; + DECL_ARG_TYPE (decl) = integer_type_node; + layout_decl (decl, 0); + } + warn_if_shadowing (decl); + } + /* If no declaration found, default to int. */ + else + { + /* FIXME diagnostics: This should be the location of the argument, + not the FNDECL. E.g., for an old-style declaration + + int f10(v) { blah; } + + We should use the location of the V, not the F10. + Unfortunately, the V is an IDENTIFIER_NODE which has no + location. In the future we need locations for c_arg_info + entries. + + See gcc.dg/Wshadow-3.c for an example of this problem. */ + decl = build_decl (DECL_SOURCE_LOCATION (fndecl), + PARM_DECL, TREE_VALUE (parm), integer_type_node); + DECL_ARG_TYPE (decl) = TREE_TYPE (decl); + pushdecl (decl); + warn_if_shadowing (decl); + + if (flag_isoc99) + pedwarn (DECL_SOURCE_LOCATION (decl), + OPT_Wimplicit_int, "type of %qD defaults to %", + decl); + else + warning_at (DECL_SOURCE_LOCATION (decl), + OPT_Wmissing_parameter_type, + "type of %qD defaults to %", decl); + } + + TREE_PURPOSE (parm) = decl; + seen_args.add (decl); + } + + /* Now examine the parms chain for incomplete declarations + and declarations with no corresponding names. */ + + for (b = current_scope->bindings; b; b = b->prev) + { + parm = b->decl; + if (TREE_CODE (parm) != PARM_DECL) + continue; + + if (TREE_TYPE (parm) != error_mark_node + && !COMPLETE_TYPE_P (TREE_TYPE (parm))) + { + error_at (DECL_SOURCE_LOCATION (parm), + "parameter %qD has incomplete type", parm); + TREE_TYPE (parm) = error_mark_node; + } + + if (!seen_args.contains (parm)) + { + error_at (DECL_SOURCE_LOCATION (parm), + "declaration for parameter %qD but no such parameter", + parm); + + /* Pretend the parameter was not missing. + This gets us to a standard state and minimizes + further error messages. */ + parmids = chainon (parmids, tree_cons (parm, 0, 0)); + } + } + + /* Chain the declarations together in the order of the list of + names. Store that chain in the function decl, replacing the + list of names. Update the current scope to match. */ + DECL_ARGUMENTS (fndecl) = NULL_TREE; + + for (parm = parmids; parm; parm = TREE_CHAIN (parm)) + if (TREE_PURPOSE (parm)) + break; + if (parm && TREE_PURPOSE (parm)) + { + last = TREE_PURPOSE (parm); + DECL_ARGUMENTS (fndecl) = last; + + for (parm = TREE_CHAIN (parm); parm; parm = TREE_CHAIN (parm)) + if (TREE_PURPOSE (parm)) + { + DECL_CHAIN (last) = TREE_PURPOSE (parm); + last = TREE_PURPOSE (parm); + } + DECL_CHAIN (last) = NULL_TREE; + } + + /* If there was a previous prototype, + set the DECL_ARG_TYPE of each argument according to + the type previously specified, and report any mismatches. */ + + if (current_function_prototype_arg_types) + { + tree type; + for (parm = DECL_ARGUMENTS (fndecl), + type = current_function_prototype_arg_types; + parm || (type != NULL_TREE + && TREE_VALUE (type) != error_mark_node + && TYPE_MAIN_VARIANT (TREE_VALUE (type)) != void_type_node); + parm = DECL_CHAIN (parm), type = TREE_CHAIN (type)) + { + if (parm == NULL_TREE + || type == NULL_TREE + || (TREE_VALUE (type) != error_mark_node + && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)) + { + if (current_function_prototype_built_in) + warning_at (DECL_SOURCE_LOCATION (fndecl), + 0, "number of arguments doesn%'t match " + "built-in prototype"); + else + { + /* FIXME diagnostics: This should be the location of + FNDECL, but there is bug when a prototype is + declared inside function context, but defined + outside of it (e.g., gcc.dg/pr15698-2.c). In + which case FNDECL gets the location of the + prototype, not the definition. */ + error_at (input_location, + "number of arguments doesn%'t match prototype"); + + error_at (current_function_prototype_locus, + "prototype declaration"); + } + break; + } + /* Type for passing arg must be consistent with that + declared for the arg. ISO C says we take the unqualified + type for parameters declared with qualified type. */ + if (TREE_TYPE (parm) != error_mark_node + && TREE_VALUE (type) != error_mark_node + && ((TYPE_ATOMIC (DECL_ARG_TYPE (parm)) + != TYPE_ATOMIC (TREE_VALUE (type))) + || !comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)), + TYPE_MAIN_VARIANT (TREE_VALUE (type))))) + { + if ((TYPE_ATOMIC (DECL_ARG_TYPE (parm)) + == TYPE_ATOMIC (TREE_VALUE (type))) + && (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) + == TYPE_MAIN_VARIANT (TREE_VALUE (type)))) + { + /* Adjust argument to match prototype. E.g. a previous + `int foo(float);' prototype causes + `int foo(x) float x; {...}' to be treated like + `int foo(float x) {...}'. This is particularly + useful for argument types like uid_t. */ + DECL_ARG_TYPE (parm) = TREE_TYPE (parm); + + if (targetm.calls.promote_prototypes (TREE_TYPE (current_function_decl)) + && INTEGRAL_TYPE_P (TREE_TYPE (parm)) + && (TYPE_PRECISION (TREE_TYPE (parm)) + < TYPE_PRECISION (integer_type_node))) + DECL_ARG_TYPE (parm) + = c_type_promotes_to (TREE_TYPE (parm)); + + /* ??? Is it possible to get here with a + built-in prototype or will it always have + been diagnosed as conflicting with an + old-style definition and discarded? */ + if (current_function_prototype_built_in) + warning_at (DECL_SOURCE_LOCATION (parm), + OPT_Wpedantic, "promoted argument %qD " + "doesn%'t match built-in prototype", parm); + else + { + pedwarn (DECL_SOURCE_LOCATION (parm), + OPT_Wpedantic, "promoted argument %qD " + "doesn%'t match prototype", parm); + pedwarn (current_function_prototype_locus, OPT_Wpedantic, + "prototype declaration"); + } + } + else + { + if (current_function_prototype_built_in) + warning_at (DECL_SOURCE_LOCATION (parm), + 0, "argument %qD doesn%'t match " + "built-in prototype", parm); + else + { + error_at (DECL_SOURCE_LOCATION (parm), + "argument %qD doesn%'t match prototype", parm); + error_at (current_function_prototype_locus, + "prototype declaration"); + } + } + } + } + TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = NULL_TREE; + } + + /* Otherwise, create a prototype that would match. */ + + else + { + tree actual = NULL_TREE, last = NULL_TREE, type; + + for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm)) + { + type = tree_cons (NULL_TREE, DECL_ARG_TYPE (parm), NULL_TREE); + if (last) + TREE_CHAIN (last) = type; + else + actual = type; + last = type; + } + type = tree_cons (NULL_TREE, void_type_node, NULL_TREE); + if (last) + TREE_CHAIN (last) = type; + else + actual = type; + + /* We are going to assign a new value for the TYPE_ACTUAL_ARG_TYPES + of the type of this function, but we need to avoid having this + affect the types of other similarly-typed functions, so we must + first force the generation of an identical (but separate) type + node for the relevant function type. The new node we create + will be a variant of the main variant of the original function + type. */ + + TREE_TYPE (fndecl) = build_variant_type_copy (TREE_TYPE (fndecl)); + + TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = actual; + } +} + +/* Store parameter declarations passed in ARG_INFO into the current + function declaration. */ + +void +store_parm_decls_from (struct c_arg_info *arg_info) +{ + current_function_arg_info = arg_info; + store_parm_decls (); +} + +/* Called by walk_tree to look for and update context-less labels + or labels with context in the parent function. */ + +static tree +set_labels_context_r (tree *tp, int *walk_subtrees, void *data) +{ + tree ctx = static_cast(data); + if (TREE_CODE (*tp) == LABEL_EXPR + && (DECL_CONTEXT (LABEL_EXPR_LABEL (*tp)) == NULL_TREE + || DECL_CONTEXT (LABEL_EXPR_LABEL (*tp)) == DECL_CONTEXT (ctx))) + { + DECL_CONTEXT (LABEL_EXPR_LABEL (*tp)) = ctx; + *walk_subtrees = 0; + } + + return NULL_TREE; +} + +/* Store the parameter declarations into the current function declaration. + This is called after parsing the parameter declarations, before + digesting the body of the function. + + For an old-style definition, construct a prototype out of the old-style + parameter declarations and inject it into the function's type. */ + +void +store_parm_decls (void) +{ + tree fndecl = current_function_decl; + bool proto; + + /* The argument information block for FNDECL. */ + struct c_arg_info *arg_info = current_function_arg_info; + current_function_arg_info = 0; + + /* True if this definition is written with a prototype. In C2X, an + empty argument list was converted to (void) in grokparms; in + older C standard versions, it does not give the function a type + with a prototype for future calls. */ + proto = arg_info->types != 0; + + if (proto) + store_parm_decls_newstyle (fndecl, arg_info); + else + store_parm_decls_oldstyle (fndecl, arg_info); + + /* The next call to push_scope will be a function body. */ + + next_is_function_body = true; + + /* Write a record describing this function definition to the prototypes + file (if requested). */ + + gen_aux_info_record (fndecl, 1, 0, proto); + + /* Initialize the RTL code for the function. */ + allocate_struct_function (fndecl, false); + + if (warn_unused_local_typedefs) + cfun->language = ggc_cleared_alloc (); + + /* Begin the statement tree for this function. */ + DECL_SAVED_TREE (fndecl) = push_stmt_list (); + + /* ??? Insert the contents of the pending sizes list into the function + to be evaluated. The only reason left to have this is + void foo(int n, int array[n++]) + because we throw away the array type in favor of a pointer type, and + thus won't naturally see the SAVE_EXPR containing the increment. All + other pending sizes would be handled by gimplify_parameters. */ + if (arg_info->pending_sizes) + { + /* In very special circumstances, e.g. for code like + _Atomic int i = 5; + void f (int a[i += 2]) {} + we need to execute the atomic assignment on function entry. + But in this case, it is not just a straight store, it has the + op= form, which means that build_atomic_assign has generated + gotos, labels, etc. Because at that time the function decl + for F has not been created yet, those labels do not have any + function context. But we have the fndecl now, so update the + labels accordingly. gimplify_expr would crash otherwise. + Or with nested functions the labels could be created with parent + function's context, while when the statement is emitted at the + start of the nested function, it needs the nested function's + context. */ + walk_tree_without_duplicates (&arg_info->pending_sizes, + set_labels_context_r, fndecl); + add_stmt (arg_info->pending_sizes); + } +} + +/* Store PARM_DECLs in PARMS into scope temporarily. Used for + c_finish_omp_declare_simd for function prototypes. No diagnostics + should be done. */ + +void +temp_store_parm_decls (tree fndecl, tree parms) +{ + push_scope (); + for (tree p = parms; p; p = DECL_CHAIN (p)) + { + DECL_CONTEXT (p) = fndecl; + if (DECL_NAME (p)) + bind (DECL_NAME (p), p, current_scope, + /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); + } +} + +/* Undo what temp_store_parm_decls did. */ + +void +temp_pop_parm_decls (void) +{ + /* Clear all bindings in this temporary scope, so that + pop_scope doesn't create a BLOCK. */ + struct c_binding *b = current_scope->bindings; + current_scope->bindings = NULL; + for (; b; b = free_binding_and_advance (b)) + { + gcc_assert (TREE_CODE (b->decl) == PARM_DECL + || b->decl == error_mark_node); + gcc_assert (I_SYMBOL_BINDING (b->id) == b); + I_SYMBOL_BINDING (b->id) = b->shadowed; + if (b->shadowed && b->shadowed->u.type) + TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type; + } + pop_scope (); +} + + +/* Finish up a function declaration and compile that function + all the way to assembler language output. Then free the storage + for the function definition. + + This is called after parsing the body of the function definition. */ + +void +finish_function (location_t end_loc) +{ + tree fndecl = current_function_decl; + + if (c_dialect_objc ()) + objc_finish_function (); + + if (TREE_CODE (fndecl) == FUNCTION_DECL + && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))) + { + tree args = DECL_ARGUMENTS (fndecl); + for (; args; args = DECL_CHAIN (args)) + { + tree type = TREE_TYPE (args); + if (INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (args) = c_type_promotes_to (type); + } + } + + if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node) + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + /* Must mark the RESULT_DECL as being in this function. */ + + if (DECL_RESULT (fndecl) && DECL_RESULT (fndecl) != error_mark_node) + DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; + + if (MAIN_NAME_P (DECL_NAME (fndecl)) && flag_hosted + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) + == integer_type_node && flag_isoc99) + { + /* Hack. We don't want the middle-end to warn that this return + is unreachable, so we mark its location as special. Using + UNKNOWN_LOCATION has the problem that it gets clobbered in + annotate_one_with_locus. A cleaner solution might be to + ensure ! should_carry_locus_p (stmt), but that needs a flag. + */ + c_finish_return (BUILTINS_LOCATION, integer_zero_node, NULL_TREE); + } + + /* Tie off the statement tree for this function. */ + DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl)); + + finish_fname_decls (); + + /* Complain if there's no return statement only if option specified on + command line. */ + if (warn_return_type > 0 + && TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE + && !current_function_returns_value && !current_function_returns_null + /* Don't complain if we are no-return. */ + && !current_function_returns_abnormally + /* Don't complain if we are declared noreturn. */ + && !TREE_THIS_VOLATILE (fndecl) + /* Don't warn for main(). */ + && !MAIN_NAME_P (DECL_NAME (fndecl)) + /* Or if they didn't actually specify a return type. */ + && !C_FUNCTION_IMPLICIT_INT (fndecl) + /* Normally, with -Wreturn-type, flow will complain, but we might + optimize out static functions. */ + && !TREE_PUBLIC (fndecl) + && targetm.warn_func_return (fndecl) + && warning (OPT_Wreturn_type, + "no return statement in function returning non-void")) + suppress_warning (fndecl, OPT_Wreturn_type); + + /* Complain about parameters that are only set, but never otherwise used. */ + if (warn_unused_but_set_parameter) + { + tree decl; + + for (decl = DECL_ARGUMENTS (fndecl); + decl; + decl = DECL_CHAIN (decl)) + if (TREE_USED (decl) + && TREE_CODE (decl) == PARM_DECL + && !DECL_READ_P (decl) + && DECL_NAME (decl) + && !DECL_ARTIFICIAL (decl) + && !warning_suppressed_p (decl, OPT_Wunused_but_set_parameter)) + warning_at (DECL_SOURCE_LOCATION (decl), + OPT_Wunused_but_set_parameter, + "parameter %qD set but not used", decl); + } + + /* Complain about locally defined typedefs that are not used in this + function. */ + maybe_warn_unused_local_typedefs (); + + /* Possibly warn about unused parameters. */ + if (warn_unused_parameter) + do_warn_unused_parameter (fndecl); + + /* Store the end of the function, so that we get good line number + info for the epilogue. */ + cfun->function_end_locus = end_loc; + + /* Finalize the ELF visibility for the function. */ + c_determine_visibility (fndecl); + + /* For GNU C extern inline functions disregard inline limits. */ + if (DECL_EXTERNAL (fndecl) + && DECL_DECLARED_INLINE_P (fndecl) + && (flag_gnu89_inline + || lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (fndecl)))) + DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1; + + /* Genericize before inlining. Delay genericizing nested functions + until their parent function is genericized. Since finalizing + requires GENERIC, delay that as well. */ + + if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node + && !undef_nested_function) + { + if (!decl_function_context (fndecl)) + { + invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl); + c_genericize (fndecl); + + /* ??? Objc emits functions after finalizing the compilation unit. + This should be cleaned up later and this conditional removed. */ + if (symtab->global_info_ready) + { + cgraph_node::add_new_function (fndecl, false); + return; + } + cgraph_node::finalize_function (fndecl, false); + } + else + { + /* Register this function with cgraph just far enough to get it + added to our parent's nested function list. Handy, since the + C front end doesn't have such a list. */ + (void) cgraph_node::get_create (fndecl); + } + } + + if (!decl_function_context (fndecl)) + undef_nested_function = false; + + if (cfun->language != NULL) + { + ggc_free (cfun->language); + cfun->language = NULL; + } + + /* We're leaving the context of this function, so zap cfun. + It's still in DECL_STRUCT_FUNCTION, and we'll restore it in + tree_rest_of_compilation. */ + set_cfun (NULL); + invoke_plugin_callbacks (PLUGIN_FINISH_PARSE_FUNCTION, current_function_decl); + current_function_decl = NULL; +} + +/* Check the declarations given in a for-loop for satisfying the C99 + constraints. If exactly one such decl is found, return it. LOC is + the location of the opening parenthesis of the for loop. The last + parameter allows you to control the "for loop initial declarations + are only allowed in C99 mode". Normally, you should pass + flag_isoc99 as that parameter. But in some cases (Objective-C + foreach loop, for example) we want to run the checks in this + function even if not in C99 mode, so we allow the caller to turn + off the error about not being in C99 mode. +*/ + +tree +check_for_loop_decls (location_t loc, bool turn_off_iso_c99_error) +{ + struct c_binding *b; + tree one_decl = NULL_TREE; + int n_decls = 0; + + if (!turn_off_iso_c99_error) + { + static bool hint = true; + /* If we get here, declarations have been used in a for loop without + the C99 for loop scope. This doesn't make much sense, so don't + allow it. */ + error_at (loc, "% loop initial declarations " + "are only allowed in C99 or C11 mode"); + if (hint) + { + inform (loc, + "use option %<-std=c99%>, %<-std=gnu99%>, %<-std=c11%> or " + "%<-std=gnu11%> to compile your code"); + hint = false; + } + return NULL_TREE; + } + else + pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not support % loop " + "initial declarations"); + + /* C99 subclause 6.8.5 paragraph 3: + + [#3] The declaration part of a for statement shall only + declare identifiers for objects having storage class auto or + register. + + It isn't clear whether, in this sentence, "identifiers" binds to + "shall only declare" or to "objects" - that is, whether all identifiers + declared must be identifiers for objects, or whether the restriction + only applies to those that are. (A question on this in comp.std.c + in November 2000 received no answer.) We implement the strictest + interpretation, to avoid creating an extension which later causes + problems. */ + + for (b = current_scope->bindings; b; b = b->prev) + { + tree id = b->id; + tree decl = b->decl; + + if (!id) + continue; + + switch (TREE_CODE (decl)) + { + case VAR_DECL: + { + location_t decl_loc = DECL_SOURCE_LOCATION (decl); + if (TREE_STATIC (decl)) + error_at (decl_loc, + "declaration of static variable %qD in % loop " + "initial declaration", decl); + else if (DECL_EXTERNAL (decl)) + error_at (decl_loc, + "declaration of % variable %qD in % loop " + "initial declaration", decl); + } + break; + + case RECORD_TYPE: + error_at (loc, + "% declared in % loop initial " + "declaration", id); + break; + case UNION_TYPE: + error_at (loc, + "% declared in % loop initial declaration", + id); + break; + case ENUMERAL_TYPE: + error_at (loc, "% declared in % loop " + "initial declaration", id); + break; + default: + error_at (loc, "declaration of non-variable " + "%qD in % loop initial declaration", decl); + } + + n_decls++; + one_decl = decl; + } + + return n_decls == 1 ? one_decl : NULL_TREE; +} + +/* Save and reinitialize the variables + used during compilation of a C function. */ + +void +c_push_function_context (void) +{ + struct language_function *p = cfun->language; + /* cfun->language might have been already allocated by the use of + -Wunused-local-typedefs. In that case, just re-use it. */ + if (p == NULL) + cfun->language = p = ggc_cleared_alloc (); + + p->base.x_stmt_tree = c_stmt_tree; + c_stmt_tree.x_cur_stmt_list = vec_safe_copy (c_stmt_tree.x_cur_stmt_list); + p->x_in_statement = in_statement; + p->x_switch_stack = c_switch_stack; + p->arg_info = current_function_arg_info; + p->returns_value = current_function_returns_value; + p->returns_null = current_function_returns_null; + p->returns_abnormally = current_function_returns_abnormally; + p->warn_about_return_type = warn_about_return_type; + + push_function_context (); +} + +/* Restore the variables used during compilation of a C function. */ + +void +c_pop_function_context (void) +{ + struct language_function *p; + + pop_function_context (); + p = cfun->language; + + /* When -Wunused-local-typedefs is in effect, cfun->languages is + used to store data throughout the life time of the current cfun, + So don't deallocate it. */ + if (!warn_unused_local_typedefs) + cfun->language = NULL; + + if (DECL_STRUCT_FUNCTION (current_function_decl) == 0 + && DECL_SAVED_TREE (current_function_decl) == NULL_TREE) + { + /* Stop pointing to the local nodes about to be freed. */ + /* But DECL_INITIAL must remain nonzero so we know this + was an actual function definition. */ + DECL_INITIAL (current_function_decl) = error_mark_node; + DECL_ARGUMENTS (current_function_decl) = NULL_TREE; + } + + c_stmt_tree = p->base.x_stmt_tree; + p->base.x_stmt_tree.x_cur_stmt_list = NULL; + in_statement = p->x_in_statement; + c_switch_stack = p->x_switch_stack; + current_function_arg_info = p->arg_info; + current_function_returns_value = p->returns_value; + current_function_returns_null = p->returns_null; + current_function_returns_abnormally = p->returns_abnormally; + warn_about_return_type = p->warn_about_return_type; +} + +/* The functions below are required for functionality of doing + function at once processing in the C front end. Currently these + functions are not called from anywhere in the C front end, but as + these changes continue, that will change. */ + +/* Returns the stmt_tree (if any) to which statements are currently + being added. If there is no active statement-tree, NULL is + returned. */ + +stmt_tree +current_stmt_tree (void) +{ + return &c_stmt_tree; +} + +/* Return the global value of T as a symbol. */ + +tree +identifier_global_value (tree t) +{ + struct c_binding *b; + + for (b = I_SYMBOL_BINDING (t); b; b = b->shadowed) + if (B_IN_FILE_SCOPE (b) || B_IN_EXTERNAL_SCOPE (b)) + return b->decl; + + return NULL_TREE; +} + +/* Return the global value of tag T as a symbol. */ + +tree +identifier_global_tag (tree t) +{ + struct c_binding *b; + + for (b = I_TAG_BINDING (t); b; b = b->shadowed) + if (B_IN_FILE_SCOPE (b) || B_IN_EXTERNAL_SCOPE (b)) + return b->decl; + + return NULL_TREE; +} + +/* Returns true if NAME refers to a built-in function or function-like + operator. */ + +bool +names_builtin_p (const char *name) +{ + tree id = get_identifier (name); + if (tree decl = identifier_global_value (id)) + return TREE_CODE (decl) == FUNCTION_DECL && DECL_IS_UNDECLARED_BUILTIN (decl); + + /* Also detect common reserved C words that aren't strictly built-in + functions. */ + switch (C_RID_CODE (id)) + { + case RID_BUILTIN_CONVERTVECTOR: + case RID_BUILTIN_HAS_ATTRIBUTE: + case RID_BUILTIN_SHUFFLE: + case RID_BUILTIN_SHUFFLEVECTOR: + case RID_BUILTIN_ASSOC_BARRIER: + case RID_CHOOSE_EXPR: + case RID_OFFSETOF: + case RID_TYPES_COMPATIBLE_P: + return true; + default: + break; + } + + return false; +} + +/* In C, the only C-linkage public declaration is at file scope. */ + +tree +c_linkage_bindings (tree name) +{ + return identifier_global_value (name); +} + +/* Record a builtin type for C. If NAME is non-NULL, it is the name used; + otherwise the name is found in ridpointers from RID_INDEX. */ + +void +record_builtin_type (enum rid rid_index, const char *name, tree type) +{ + tree id, decl; + if (name == 0) + id = ridpointers[(int) rid_index]; + else + id = get_identifier (name); + decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL, id, type); + pushdecl (decl); + if (debug_hooks->type_decl) + debug_hooks->type_decl (decl, false); +} + +/* Build the void_list_node (void_type_node having been created). */ +tree +build_void_list_node (void) +{ + tree t = build_tree_list (NULL_TREE, void_type_node); + return t; +} + +/* Return a c_parm structure with the given SPECS, ATTRS and DECLARATOR. */ + +struct c_parm * +build_c_parm (struct c_declspecs *specs, tree attrs, + struct c_declarator *declarator, + location_t loc) +{ + struct c_parm *ret = XOBNEW (&parser_obstack, struct c_parm); + ret->specs = specs; + ret->attrs = attrs; + ret->declarator = declarator; + ret->loc = loc; + return ret; +} + +/* Return a declarator with nested attributes. TARGET is the inner + declarator to which these attributes apply. ATTRS are the + attributes. */ + +struct c_declarator * +build_attrs_declarator (tree attrs, struct c_declarator *target) +{ + struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); + ret->kind = cdk_attrs; + ret->declarator = target; + ret->u.attrs = attrs; + return ret; +} + +/* Return a declarator for a function with arguments specified by ARGS + and return type specified by TARGET. */ + +struct c_declarator * +build_function_declarator (struct c_arg_info *args, + struct c_declarator *target) +{ + struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); + ret->kind = cdk_function; + ret->declarator = target; + ret->u.arg_info = args; + return ret; +} + +/* Return a declarator for the identifier IDENT (which may be + NULL_TREE for an abstract declarator). */ + +struct c_declarator * +build_id_declarator (tree ident) +{ + struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); + ret->kind = cdk_id; + ret->declarator = 0; + ret->u.id.id = ident; + ret->u.id.attrs = NULL_TREE; + /* Default value - may get reset to a more precise location. */ + ret->id_loc = input_location; + return ret; +} + +/* Return something to represent absolute declarators containing a *. + TARGET is the absolute declarator that the * contains. + TYPE_QUALS_ATTRS is a structure for type qualifiers and attributes + to apply to the pointer type. */ + +struct c_declarator * +make_pointer_declarator (struct c_declspecs *type_quals_attrs, + struct c_declarator *target) +{ + tree attrs; + int quals = 0; + struct c_declarator *itarget = target; + struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); + if (type_quals_attrs) + { + attrs = type_quals_attrs->attrs; + quals = quals_from_declspecs (type_quals_attrs); + if (attrs != NULL_TREE) + itarget = build_attrs_declarator (attrs, target); + } + ret->kind = cdk_pointer; + ret->declarator = itarget; + ret->u.pointer_quals = quals; + return ret; +} + +/* Return a pointer to a structure for an empty list of declaration + specifiers. */ + +struct c_declspecs * +build_null_declspecs (void) +{ + struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs); + memset (ret, 0, sizeof *ret); + ret->align_log = -1; + ret->typespec_word = cts_none; + ret->storage_class = csc_none; + ret->expr_const_operands = true; + ret->typespec_kind = ctsk_none; + ret->address_space = ADDR_SPACE_GENERIC; + return ret; +} + +/* Add the address space ADDRSPACE to the declaration specifiers + SPECS, returning SPECS. */ + +struct c_declspecs * +declspecs_add_addrspace (location_t location, + struct c_declspecs *specs, addr_space_t as) +{ + specs->non_sc_seen_p = true; + specs->declspecs_seen_p = true; + specs->non_std_attrs_seen_p = true; + + if (!ADDR_SPACE_GENERIC_P (specs->address_space) + && specs->address_space != as) + error ("incompatible address space qualifiers %qs and %qs", + c_addr_space_name (as), + c_addr_space_name (specs->address_space)); + else + { + specs->address_space = as; + specs->locations[cdw_address_space] = location; + } + return specs; +} + +/* Add the type qualifier QUAL to the declaration specifiers SPECS, + returning SPECS. */ + +struct c_declspecs * +declspecs_add_qual (location_t loc, + struct c_declspecs *specs, tree qual) +{ + enum rid i; + bool dupe = false; + specs->non_sc_seen_p = true; + specs->declspecs_seen_p = true; + specs->non_std_attrs_seen_p = true; + gcc_assert (TREE_CODE (qual) == IDENTIFIER_NODE + && C_IS_RESERVED_WORD (qual)); + i = C_RID_CODE (qual); + location_t prev_loc = UNKNOWN_LOCATION; + switch (i) + { + case RID_CONST: + dupe = specs->const_p; + specs->const_p = true; + prev_loc = specs->locations[cdw_const]; + specs->locations[cdw_const] = loc; + break; + case RID_VOLATILE: + dupe = specs->volatile_p; + specs->volatile_p = true; + prev_loc = specs->locations[cdw_volatile]; + specs->locations[cdw_volatile] = loc; + break; + case RID_RESTRICT: + dupe = specs->restrict_p; + specs->restrict_p = true; + prev_loc = specs->locations[cdw_restrict]; + specs->locations[cdw_restrict] = loc; + break; + case RID_ATOMIC: + dupe = specs->atomic_p; + specs->atomic_p = true; + prev_loc = specs->locations[cdw_atomic]; + specs->locations[cdw_atomic] = loc; + break; + default: + gcc_unreachable (); + } + if (dupe) + { + bool warned = pedwarn_c90 (loc, OPT_Wpedantic, + "duplicate %qE declaration specifier", qual); + if (!warned + && warn_duplicate_decl_specifier + && prev_loc >= RESERVED_LOCATION_COUNT + && !from_macro_expansion_at (prev_loc) + && !from_macro_expansion_at (loc)) + warning_at (loc, OPT_Wduplicate_decl_specifier, + "duplicate %qE declaration specifier", qual); + } + return specs; +} + +/* Add the type specifier TYPE to the declaration specifiers SPECS, + returning SPECS. */ + +struct c_declspecs * +declspecs_add_type (location_t loc, struct c_declspecs *specs, + struct c_typespec spec) +{ + tree type = spec.spec; + specs->non_sc_seen_p = true; + specs->declspecs_seen_p = true; + specs->non_std_attrs_seen_p = true; + specs->typespec_kind = spec.kind; + if (TREE_DEPRECATED (type)) + specs->deprecated_p = true; + if (TREE_UNAVAILABLE (type)) + specs->unavailable_p = true; + + /* Handle type specifier keywords. */ + if (TREE_CODE (type) == IDENTIFIER_NODE + && C_IS_RESERVED_WORD (type) + && C_RID_CODE (type) != RID_CXX_COMPAT_WARN) + { + enum rid i = C_RID_CODE (type); + if (specs->type) + { + error_at (loc, "two or more data types in declaration specifiers"); + return specs; + } + if ((int) i <= (int) RID_LAST_MODIFIER) + { + /* "long", "short", "signed", "unsigned", "_Complex" or "_Sat". */ + bool dupe = false; + switch (i) + { + case RID_LONG: + if (specs->long_long_p) + { + error_at (loc, "% is too long for GCC"); + break; + } + if (specs->long_p) + { + if (specs->typespec_word == cts_double) + { + error_at (loc, + ("both % and % in " + "declaration specifiers")); + break; + } + pedwarn_c90 (loc, OPT_Wlong_long, + "ISO C90 does not support %"); + specs->long_long_p = 1; + specs->locations[cdw_long_long] = loc; + break; + } + if (specs->short_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_int_n) + error_at (loc, + ("both % and %<__int%d%> in " + "declaration specifiers"), + int_n_data[specs->int_n_idx].bitsize); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both % and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_char) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_float) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_floatn_nx) + error_at (loc, + ("both % and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both % and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both % and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both % and %<_Decimal128%> in " + "declaration specifiers")); + else + { + specs->long_p = true; + specs->locations[cdw_long] = loc; + } + break; + case RID_SHORT: + dupe = specs->short_p; + if (specs->long_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_int_n) + error_at (loc, + ("both % and %<__int%d%> in " + "declaration specifiers"), + int_n_data[specs->int_n_idx].bitsize); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both % and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_char) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_float) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_double) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_floatn_nx) + error_at (loc, + ("both % and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both % and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both % and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both % and %<_Decimal128%> in " + "declaration specifiers")); + else + { + specs->short_p = true; + specs->locations[cdw_short] = loc; + } + break; + case RID_SIGNED: + dupe = specs->signed_p; + if (specs->unsigned_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both % and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_float) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_double) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_floatn_nx) + error_at (loc, + ("both % and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both % and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both % and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both % and %<_Decimal128%> in " + "declaration specifiers")); + else + { + specs->signed_p = true; + specs->locations[cdw_signed] = loc; + } + break; + case RID_UNSIGNED: + dupe = specs->unsigned_p; + if (specs->signed_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both % and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_float) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_double) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_floatn_nx) + error_at (loc, + ("both % and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both % and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both % and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both % and %<_Decimal128%> in " + "declaration specifiers")); + else + { + specs->unsigned_p = true; + specs->locations[cdw_unsigned] = loc; + } + break; + case RID_COMPLEX: + dupe = specs->complex_p; + if (!in_system_header_at (loc)) + pedwarn_c90 (loc, OPT_Wpedantic, + "ISO C90 does not support complex types"); + if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both % and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both % and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both % and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both % and %<_Decimal128%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_fract) + error_at (loc, + ("both % and %<_Fract%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_accum) + error_at (loc, + ("both % and %<_Accum%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both % and %<_Sat%> in " + "declaration specifiers")); + else + { + specs->complex_p = true; + specs->locations[cdw_complex] = loc; + } + break; + case RID_SAT: + dupe = specs->saturating_p; + pedwarn (loc, OPT_Wpedantic, + "ISO C does not support saturating types"); + if (specs->typespec_word == cts_int_n) + { + error_at (loc, + ("both %<_Sat%> and %<__int%d%> in " + "declaration specifiers"), + int_n_data[specs->int_n_idx].bitsize); + } + else if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both %<_Sat%> and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_bool) + error_at (loc, + ("both %<_Sat%> and %<_Bool%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_char) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_int) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_float) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_double) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else if (specs->typespec_word == cts_floatn_nx) + error_at (loc, + ("both %<_Sat%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->typespec_word == cts_dfloat32) + error_at (loc, + ("both %<_Sat%> and %<_Decimal32%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat64) + error_at (loc, + ("both %<_Sat%> and %<_Decimal64%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_dfloat128) + error_at (loc, + ("both %<_Sat%> and %<_Decimal128%> in " + "declaration specifiers")); + else if (specs->complex_p) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else + { + specs->saturating_p = true; + specs->locations[cdw_saturating] = loc; + } + break; + default: + gcc_unreachable (); + } + + if (dupe) + error_at (loc, "duplicate %qE", type); + + return specs; + } + else + { + /* "void", "_Bool", "char", "int", "float", "double", + "_FloatN", "_FloatNx", "_Decimal32", "__intN", + "_Decimal64", "_Decimal128", "_Fract", "_Accum" or + "__auto_type". */ + if (specs->typespec_word != cts_none) + { + error_at (loc, + "two or more data types in declaration specifiers"); + return specs; + } + switch (i) + { + case RID_AUTO_TYPE: + if (specs->long_p) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->signed_p) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->unsigned_p) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->complex_p) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<__auto_type%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_auto_type; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_INT_N_0: + case RID_INT_N_1: + case RID_INT_N_2: + case RID_INT_N_3: + specs->int_n_idx = i - RID_INT_N_0; + if (!in_system_header_at (input_location) + /* If the INT_N type ends in "__", and so is of the format + "__intN__", don't pedwarn. */ + && (strncmp (IDENTIFIER_POINTER (type) + + (IDENTIFIER_LENGTH (type) - 2), "__", 2) != 0)) + pedwarn (loc, OPT_Wpedantic, + "ISO C does not support %<__int%d%> types", + int_n_data[specs->int_n_idx].bitsize); + + if (specs->long_p) + error_at (loc, + ("both %<__int%d%> and % in " + "declaration specifiers"), + int_n_data[specs->int_n_idx].bitsize); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<__int%d%> in " + "declaration specifiers"), + int_n_data[specs->int_n_idx].bitsize); + else if (specs->short_p) + error_at (loc, + ("both %<__int%d%> and % in " + "declaration specifiers"), + int_n_data[specs->int_n_idx].bitsize); + else if (! int_n_enabled_p[specs->int_n_idx]) + { + specs->typespec_word = cts_int_n; + error_at (loc, + "%<__int%d%> is not supported on this target", + int_n_data[specs->int_n_idx].bitsize); + } + else + { + specs->typespec_word = cts_int_n; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_VOID: + if (specs->long_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->signed_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->unsigned_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->complex_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_void; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_BOOL: + if (!in_system_header_at (loc)) + pedwarn_c90 (loc, OPT_Wpedantic, + "ISO C90 does not support boolean types"); + if (specs->long_p) + error_at (loc, + ("both % and %<_Bool%> in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both % and %<_Bool%> in " + "declaration specifiers")); + else if (specs->signed_p) + error_at (loc, + ("both % and %<_Bool%> in " + "declaration specifiers")); + else if (specs->unsigned_p) + error_at (loc, + ("both % and %<_Bool%> in " + "declaration specifiers")); + else if (specs->complex_p) + error_at (loc, + ("both % and %<_Bool%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<_Bool%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_bool; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_CHAR: + if (specs->long_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_char; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_INT: + if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_int; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_FLOAT: + if (specs->long_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->signed_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->unsigned_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_float; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_DOUBLE: + if (specs->long_long_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->signed_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->unsigned_p) + error_at (loc, + ("both % and % in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and % in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_double; + specs->locations[cdw_typespec] = loc; + } + return specs; + CASE_RID_FLOATN_NX: + specs->floatn_nx_idx = i - RID_FLOATN_NX_FIRST; + if (!in_system_header_at (input_location)) + pedwarn (loc, OPT_Wpedantic, + "ISO C does not support the %<_Float%d%s%> type", + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + + if (specs->long_p) + error_at (loc, + ("both % and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->short_p) + error_at (loc, + ("both % and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->signed_p) + error_at (loc, + ("both % and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->unsigned_p) + error_at (loc, + ("both % and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE) + { + specs->typespec_word = cts_floatn_nx; + error_at (loc, + "%<_Float%d%s%> is not supported on this target", + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + } + else + { + specs->typespec_word = cts_floatn_nx; + specs->locations[cdw_typespec] = loc; + } + return specs; + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + { + const char *str; + if (i == RID_DFLOAT32) + str = "_Decimal32"; + else if (i == RID_DFLOAT64) + str = "_Decimal64"; + else + str = "_Decimal128"; + if (specs->long_long_p) + error_at (loc, + ("both % and %qs in " + "declaration specifiers"), + str); + if (specs->long_p) + error_at (loc, + ("both % and %qs in " + "declaration specifiers"), + str); + else if (specs->short_p) + error_at (loc, + ("both % and %qs in " + "declaration specifiers"), + str); + else if (specs->signed_p) + error_at (loc, + ("both % and %qs in " + "declaration specifiers"), + str); + else if (specs->unsigned_p) + error_at (loc, + ("both % and %qs in " + "declaration specifiers"), + str); + else if (specs->complex_p) + error_at (loc, + ("both % and %qs in " + "declaration specifiers"), + str); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %qs in " + "declaration specifiers"), + str); + else if (i == RID_DFLOAT32) + specs->typespec_word = cts_dfloat32; + else if (i == RID_DFLOAT64) + specs->typespec_word = cts_dfloat64; + else + specs->typespec_word = cts_dfloat128; + specs->locations[cdw_typespec] = loc; + } + if (!targetm.decimal_float_supported_p ()) + error_at (loc, + ("decimal floating-point not supported " + "for this target")); + pedwarn_c11 (loc, OPT_Wpedantic, + "ISO C does not support decimal floating-point " + "before C2X"); + return specs; + case RID_FRACT: + case RID_ACCUM: + { + const char *str; + if (i == RID_FRACT) + str = "_Fract"; + else + str = "_Accum"; + if (specs->complex_p) + error_at (loc, + ("both % and %qs in " + "declaration specifiers"), + str); + else if (i == RID_FRACT) + specs->typespec_word = cts_fract; + else + specs->typespec_word = cts_accum; + specs->locations[cdw_typespec] = loc; + } + if (!targetm.fixed_point_supported_p ()) + error_at (loc, + "fixed-point types not supported for this target"); + pedwarn (loc, OPT_Wpedantic, + "ISO C does not support fixed-point types"); + return specs; + default: + /* ObjC reserved word "id", handled below. */ + break; + } + } + } + + /* Now we have a typedef (a TYPE_DECL node), an identifier (some + form of ObjC type, cases such as "int" and "long" being handled + above), a TYPE (struct, union, enum and typeof specifiers) or an + ERROR_MARK. In none of these cases may there have previously + been any type specifiers. */ + if (specs->type || specs->typespec_word != cts_none + || specs->long_p || specs->short_p || specs->signed_p + || specs->unsigned_p || specs->complex_p) + error_at (loc, "two or more data types in declaration specifiers"); + else if (TREE_CODE (type) == TYPE_DECL) + { + if (TREE_TYPE (type) == error_mark_node) + ; /* Allow the type to default to int to avoid cascading errors. */ + else + { + specs->type = TREE_TYPE (type); + specs->decl_attr = DECL_ATTRIBUTES (type); + specs->typedef_p = true; + specs->explicit_signed_p = C_TYPEDEF_EXPLICITLY_SIGNED (type); + specs->locations[cdw_typedef] = loc; + + /* If this typedef name is defined in a struct, then a C++ + lookup would return a different value. */ + if (warn_cxx_compat + && I_SYMBOL_BINDING (DECL_NAME (type))->in_struct) + warning_at (loc, OPT_Wc___compat, + "C++ lookup of %qD would return a field, not a type", + type); + + /* If we are parsing a struct, record that a struct field + used a typedef. */ + if (warn_cxx_compat && struct_parse_info != NULL) + struct_parse_info->typedefs_seen.safe_push (type); + } + } + else if (TREE_CODE (type) == IDENTIFIER_NODE) + { + tree t = lookup_name (type); + if (!t || TREE_CODE (t) != TYPE_DECL) + error_at (loc, "%qE fails to be a typedef or built in type", type); + else if (TREE_TYPE (t) == error_mark_node) + ; + else + { + specs->type = TREE_TYPE (t); + specs->locations[cdw_typespec] = loc; + } + } + else + { + if (TREE_CODE (type) != ERROR_MARK && spec.kind == ctsk_typeof) + { + specs->typedef_p = true; + specs->locations[cdw_typedef] = loc; + if (spec.expr) + { + if (specs->expr) + specs->expr = build2 (COMPOUND_EXPR, TREE_TYPE (spec.expr), + specs->expr, spec.expr); + else + specs->expr = spec.expr; + specs->expr_const_operands &= spec.expr_const_operands; + } + } + specs->type = type; + } + + return specs; +} + +/* Add the storage class specifier or function specifier SCSPEC to the + declaration specifiers SPECS, returning SPECS. */ + +struct c_declspecs * +declspecs_add_scspec (location_t loc, + struct c_declspecs *specs, + tree scspec) +{ + enum rid i; + enum c_storage_class n = csc_none; + bool dupe = false; + specs->declspecs_seen_p = true; + specs->non_std_attrs_seen_p = true; + gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE + && C_IS_RESERVED_WORD (scspec)); + i = C_RID_CODE (scspec); + if (specs->non_sc_seen_p) + warning (OPT_Wold_style_declaration, + "%qE is not at beginning of declaration", scspec); + switch (i) + { + case RID_INLINE: + /* C99 permits duplicate inline. Although of doubtful utility, + it seems simplest to permit it in gnu89 mode as well, as + there is also little utility in maintaining this as a + difference between gnu89 and C99 inline. */ + dupe = false; + specs->inline_p = true; + specs->locations[cdw_inline] = loc; + break; + case RID_NORETURN: + /* Duplicate _Noreturn is permitted. */ + dupe = false; + specs->noreturn_p = true; + specs->locations[cdw_noreturn] = loc; + break; + case RID_THREAD: + dupe = specs->thread_p; + if (specs->storage_class == csc_auto) + error ("%qE used with %", scspec); + else if (specs->storage_class == csc_register) + error ("%qE used with %", scspec); + else if (specs->storage_class == csc_typedef) + error ("%qE used with %", scspec); + else + { + specs->thread_p = true; + specs->thread_gnu_p = (strcmp (IDENTIFIER_POINTER (scspec), + "__thread") == 0); + /* A diagnostic is not required for the use of this + identifier in the implementation namespace; only diagnose + it for the C11 spelling because of existing code using + the other spelling. */ + if (!specs->thread_gnu_p) + { + if (flag_isoc99) + pedwarn_c99 (loc, OPT_Wpedantic, + "ISO C99 does not support %qE", scspec); + else + pedwarn_c99 (loc, OPT_Wpedantic, + "ISO C90 does not support %qE", scspec); + } + specs->locations[cdw_thread] = loc; + } + break; + case RID_AUTO: + n = csc_auto; + break; + case RID_EXTERN: + n = csc_extern; + /* Diagnose "__thread extern". */ + if (specs->thread_p && specs->thread_gnu_p) + error ("%<__thread%> before %"); + break; + case RID_REGISTER: + n = csc_register; + break; + case RID_STATIC: + n = csc_static; + /* Diagnose "__thread static". */ + if (specs->thread_p && specs->thread_gnu_p) + error ("%<__thread%> before %"); + break; + case RID_TYPEDEF: + n = csc_typedef; + break; + default: + gcc_unreachable (); + } + if (n != csc_none && n == specs->storage_class) + dupe = true; + if (dupe) + { + if (i == RID_THREAD) + error ("duplicate %<_Thread_local%> or %<__thread%>"); + else + error ("duplicate %qE", scspec); + } + if (n != csc_none) + { + if (specs->storage_class != csc_none && n != specs->storage_class) + { + error ("multiple storage classes in declaration specifiers"); + } + else + { + specs->storage_class = n; + specs->locations[cdw_storage_class] = loc; + if (n != csc_extern && n != csc_static && specs->thread_p) + { + error ("%qs used with %qE", + specs->thread_gnu_p ? "__thread" : "_Thread_local", + scspec); + specs->thread_p = false; + } + } + } + return specs; +} + +/* Add the attributes ATTRS to the declaration specifiers SPECS, + returning SPECS. */ + +struct c_declspecs * +declspecs_add_attrs (location_t loc, struct c_declspecs *specs, tree attrs) +{ + specs->attrs = chainon (attrs, specs->attrs); + specs->locations[cdw_attributes] = loc; + specs->declspecs_seen_p = true; + /* In the case of standard attributes at the start of the + declaration, the caller will reset this. */ + specs->non_std_attrs_seen_p = true; + return specs; +} + +/* Add an _Alignas specifier (expression ALIGN, or type whose + alignment is ALIGN) to the declaration specifiers SPECS, returning + SPECS. */ +struct c_declspecs * +declspecs_add_alignas (location_t loc, + struct c_declspecs *specs, tree align) +{ + specs->alignas_p = true; + specs->locations[cdw_alignas] = loc; + if (align == error_mark_node) + return specs; + + /* Only accept the alignment if it's valid and greater than + the current one. Zero is invalid but by C11 required to + be silently ignored. */ + int align_log = check_user_alignment (align, false, /* warn_zero = */false); + if (align_log > specs->align_log) + specs->align_log = align_log; + return specs; +} + +/* Combine "long", "short", "signed", "unsigned" and "_Complex" type + specifiers with any other type specifier to determine the resulting + type. This is where ISO C checks on complex types are made, since + "_Complex long" is a prefix of the valid ISO C type "_Complex long + double". Also apply postfix standard attributes to modify the type. */ + +struct c_declspecs * +finish_declspecs (struct c_declspecs *specs) +{ + /* If a type was specified as a whole, we have no modifiers and are + done. */ + if (specs->type != NULL_TREE) + { + gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p + && !specs->complex_p); + + /* Set a dummy type. */ + if (TREE_CODE (specs->type) == ERROR_MARK) + specs->type = integer_type_node; + goto handle_postfix_attrs; + } + + /* If none of "void", "_Bool", "char", "int", "float" or "double" + has been specified, treat it as "int" unless "_Complex" is + present and there are no other specifiers. If we just have + "_Complex", it is equivalent to "_Complex double", but e.g. + "_Complex short" is equivalent to "_Complex short int". */ + if (specs->typespec_word == cts_none) + { + if (specs->saturating_p) + { + error_at (specs->locations[cdw_saturating], + "%<_Sat%> is used without %<_Fract%> or %<_Accum%>"); + if (!targetm.fixed_point_supported_p ()) + error_at (specs->locations[cdw_saturating], + "fixed-point types not supported for this target"); + specs->typespec_word = cts_fract; + } + else if (specs->long_p || specs->short_p + || specs->signed_p || specs->unsigned_p) + { + specs->typespec_word = cts_int; + } + else if (specs->complex_p) + { + specs->typespec_word = cts_double; + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, + "ISO C does not support plain % meaning " + "%"); + } + else + { + specs->typespec_word = cts_int; + specs->default_int_p = true; + /* We don't diagnose this here because grokdeclarator will + give more specific diagnostics according to whether it is + a function definition. */ + } + } + + /* If "signed" was specified, record this to distinguish "int" and + "signed int" in the case of a bit-field with + -funsigned-bitfields. */ + specs->explicit_signed_p = specs->signed_p; + + /* Now compute the actual type. */ + switch (specs->typespec_word) + { + case cts_auto_type: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p + && !specs->complex_p); + /* Type to be filled in later. */ + if (specs->postfix_attrs) + error ("%<__auto_type%> followed by %<[[]]%> attributes"); + break; + case cts_void: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p + && !specs->complex_p); + specs->type = void_type_node; + break; + case cts_bool: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p + && !specs->complex_p); + specs->type = boolean_type_node; + break; + case cts_char: + gcc_assert (!specs->long_p && !specs->short_p); + gcc_assert (!(specs->signed_p && specs->unsigned_p)); + if (specs->signed_p) + specs->type = signed_char_type_node; + else if (specs->unsigned_p) + specs->type = unsigned_char_type_node; + else + specs->type = char_type_node; + if (specs->complex_p) + { + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, + "ISO C does not support complex integer types"); + specs->type = build_complex_type (specs->type); + } + break; + case cts_int_n: + gcc_assert (!specs->long_p && !specs->short_p && !specs->long_long_p); + gcc_assert (!(specs->signed_p && specs->unsigned_p)); + if (! int_n_enabled_p[specs->int_n_idx]) + specs->type = integer_type_node; + else + specs->type = (specs->unsigned_p + ? int_n_trees[specs->int_n_idx].unsigned_type + : int_n_trees[specs->int_n_idx].signed_type); + if (specs->complex_p) + { + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, + "ISO C does not support complex integer types"); + specs->type = build_complex_type (specs->type); + } + break; + case cts_int: + gcc_assert (!(specs->long_p && specs->short_p)); + gcc_assert (!(specs->signed_p && specs->unsigned_p)); + if (specs->long_long_p) + specs->type = (specs->unsigned_p + ? long_long_unsigned_type_node + : long_long_integer_type_node); + else if (specs->long_p) + specs->type = (specs->unsigned_p + ? long_unsigned_type_node + : long_integer_type_node); + else if (specs->short_p) + specs->type = (specs->unsigned_p + ? short_unsigned_type_node + : short_integer_type_node); + else + specs->type = (specs->unsigned_p + ? unsigned_type_node + : integer_type_node); + if (specs->complex_p) + { + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, + "ISO C does not support complex integer types"); + specs->type = build_complex_type (specs->type); + } + break; + case cts_float: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p); + specs->type = (specs->complex_p + ? complex_float_type_node + : float_type_node); + break; + case cts_double: + gcc_assert (!specs->long_long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p); + if (specs->long_p) + { + specs->type = (specs->complex_p + ? complex_long_double_type_node + : long_double_type_node); + } + else + { + specs->type = (specs->complex_p + ? complex_double_type_node + : double_type_node); + } + break; + case cts_floatn_nx: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p); + if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE) + specs->type = integer_type_node; + else if (specs->complex_p) + specs->type = COMPLEX_FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx); + else + specs->type = FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx); + break; + case cts_dfloat32: + case cts_dfloat64: + case cts_dfloat128: + gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p && !specs->complex_p); + if (!targetm.decimal_float_supported_p ()) + specs->type = integer_type_node; + else if (specs->typespec_word == cts_dfloat32) + specs->type = dfloat32_type_node; + else if (specs->typespec_word == cts_dfloat64) + specs->type = dfloat64_type_node; + else + specs->type = dfloat128_type_node; + break; + case cts_fract: + gcc_assert (!specs->complex_p); + if (!targetm.fixed_point_supported_p ()) + specs->type = integer_type_node; + else if (specs->saturating_p) + { + if (specs->long_long_p) + specs->type = specs->unsigned_p + ? sat_unsigned_long_long_fract_type_node + : sat_long_long_fract_type_node; + else if (specs->long_p) + specs->type = specs->unsigned_p + ? sat_unsigned_long_fract_type_node + : sat_long_fract_type_node; + else if (specs->short_p) + specs->type = specs->unsigned_p + ? sat_unsigned_short_fract_type_node + : sat_short_fract_type_node; + else + specs->type = specs->unsigned_p + ? sat_unsigned_fract_type_node + : sat_fract_type_node; + } + else + { + if (specs->long_long_p) + specs->type = specs->unsigned_p + ? unsigned_long_long_fract_type_node + : long_long_fract_type_node; + else if (specs->long_p) + specs->type = specs->unsigned_p + ? unsigned_long_fract_type_node + : long_fract_type_node; + else if (specs->short_p) + specs->type = specs->unsigned_p + ? unsigned_short_fract_type_node + : short_fract_type_node; + else + specs->type = specs->unsigned_p + ? unsigned_fract_type_node + : fract_type_node; + } + break; + case cts_accum: + gcc_assert (!specs->complex_p); + if (!targetm.fixed_point_supported_p ()) + specs->type = integer_type_node; + else if (specs->saturating_p) + { + if (specs->long_long_p) + specs->type = specs->unsigned_p + ? sat_unsigned_long_long_accum_type_node + : sat_long_long_accum_type_node; + else if (specs->long_p) + specs->type = specs->unsigned_p + ? sat_unsigned_long_accum_type_node + : sat_long_accum_type_node; + else if (specs->short_p) + specs->type = specs->unsigned_p + ? sat_unsigned_short_accum_type_node + : sat_short_accum_type_node; + else + specs->type = specs->unsigned_p + ? sat_unsigned_accum_type_node + : sat_accum_type_node; + } + else + { + if (specs->long_long_p) + specs->type = specs->unsigned_p + ? unsigned_long_long_accum_type_node + : long_long_accum_type_node; + else if (specs->long_p) + specs->type = specs->unsigned_p + ? unsigned_long_accum_type_node + : long_accum_type_node; + else if (specs->short_p) + specs->type = specs->unsigned_p + ? unsigned_short_accum_type_node + : short_accum_type_node; + else + specs->type = specs->unsigned_p + ? unsigned_accum_type_node + : accum_type_node; + } + break; + default: + gcc_unreachable (); + } + handle_postfix_attrs: + if (specs->type != NULL) + { + specs->postfix_attrs = c_warn_type_attributes (specs->postfix_attrs); + decl_attributes (&specs->type, specs->postfix_attrs, 0); + specs->postfix_attrs = NULL_TREE; + } + + return specs; +} + +/* Perform final processing on one file scope's declarations (or the + external scope's declarations), GLOBALS. */ + +static void +c_write_global_declarations_1 (tree globals) +{ + tree decl; + bool reconsider; + + /* Process the decls in the order they were written. */ + for (decl = globals; decl; decl = DECL_CHAIN (decl)) + { + /* Check for used but undefined static functions using the C + standard's definition of "used", and set TREE_NO_WARNING so + that check_global_declaration doesn't repeat the check. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_INITIAL (decl) == NULL_TREE + && DECL_EXTERNAL (decl) + && !TREE_PUBLIC (decl)) + { + if (C_DECL_USED (decl)) + { + /* TODO: Add OPT_Wundefined-inline. */ + if (pedwarn (input_location, 0, "%q+F used but never defined", + decl)) + suppress_warning (decl /* OPT_Wundefined-inline. */); + } + /* For -Wunused-function warn about unused static prototypes. */ + else if (warn_unused_function + && ! DECL_ARTIFICIAL (decl) + && ! warning_suppressed_p (decl, OPT_Wunused_function)) + { + if (warning (OPT_Wunused_function, + "%q+F declared % but never defined", + decl)) + suppress_warning (decl, OPT_Wunused_function); + } + } + + wrapup_global_declaration_1 (decl); + } + + do + { + reconsider = false; + for (decl = globals; decl; decl = DECL_CHAIN (decl)) + reconsider |= wrapup_global_declaration_2 (decl); + } + while (reconsider); +} + +/* Preserve the external declarations scope across a garbage collect. */ +static GTY(()) tree ext_block; + +/* Collect all references relevant to SOURCE_FILE. */ + +static void +collect_all_refs (const char *source_file) +{ + tree t; + unsigned i; + + FOR_EACH_VEC_ELT (*all_translation_units, i, t) + collect_ada_nodes (BLOCK_VARS (DECL_INITIAL (t)), source_file); + + collect_ada_nodes (BLOCK_VARS (ext_block), source_file); +} + +/* Collect source file references at global level. */ + +static void +collect_source_refs (void) +{ + tree t; + tree decls; + tree decl; + unsigned i; + + FOR_EACH_VEC_ELT (*all_translation_units, i, t) + { + decls = DECL_INITIAL (t); + for (decl = BLOCK_VARS (decls); decl; decl = TREE_CHAIN (decl)) + if (!DECL_IS_UNDECLARED_BUILTIN (decl)) + collect_source_ref (DECL_SOURCE_FILE (decl)); + } + + for (decl = BLOCK_VARS (ext_block); decl; decl = TREE_CHAIN (decl)) + if (!DECL_IS_UNDECLARED_BUILTIN (decl)) + collect_source_ref (DECL_SOURCE_FILE (decl)); +} + +/* Free attribute access data that are not needed by the middle end. */ + +static void +free_attr_access_data () +{ + struct cgraph_node *n; + + /* Iterate over all functions declared in the translation unit. */ + FOR_EACH_FUNCTION (n) + { + for (tree parm = DECL_ARGUMENTS (n->decl); parm; parm = TREE_CHAIN (parm)) + if (tree attrs = DECL_ATTRIBUTES (parm)) + attr_access::free_lang_data (attrs); + + tree fntype = TREE_TYPE (n->decl); + if (!fntype || fntype == error_mark_node) + continue; + tree attrs = TYPE_ATTRIBUTES (fntype); + if (!attrs) + continue; + + attr_access::free_lang_data (attrs); + } +} + +/* Perform any final parser cleanups and generate initial debugging + information. */ + +void +c_parse_final_cleanups (void) +{ + tree t; + unsigned i; + + /* We don't want to do this if generating a PCH. */ + if (pch_file) + return; + + timevar_stop (TV_PHASE_PARSING); + timevar_start (TV_PHASE_DEFERRED); + + /* Do the Objective-C stuff. This is where all the Objective-C + module stuff gets generated (symtab, class/protocol/selector + lists etc). */ + if (c_dialect_objc ()) + objc_write_global_declarations (); + + /* Close the external scope. */ + ext_block = pop_scope (); + external_scope = 0; + gcc_assert (!current_scope); + + /* Handle -fdump-ada-spec[-slim]. */ + if (flag_dump_ada_spec || flag_dump_ada_spec_slim) + { + /* Build a table of files to generate specs for */ + collect_source_ref (main_input_filename); + if (!flag_dump_ada_spec_slim) + collect_source_refs (); + + dump_ada_specs (collect_all_refs, NULL); + } + + /* Process all file scopes in this compilation, and the external_scope, + through wrapup_global_declarations. */ + FOR_EACH_VEC_ELT (*all_translation_units, i, t) + c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t))); + c_write_global_declarations_1 (BLOCK_VARS (ext_block)); + + if (!in_lto_p) + free_attr_access_data (); + + timevar_stop (TV_PHASE_DEFERRED); + timevar_start (TV_PHASE_PARSING); + + ext_block = NULL; +} + +/* Register reserved keyword WORD as qualifier for address space AS. */ + +void +c_register_addr_space (const char *word, addr_space_t as) +{ + int rid = RID_FIRST_ADDR_SPACE + as; + tree id; + + /* Address space qualifiers are only supported + in C with GNU extensions enabled. */ + if (c_dialect_objc () || flag_no_asm) + return; + + id = get_identifier (word); + C_SET_RID_CODE (id, rid); + C_IS_RESERVED_WORD (id) = 1; + ridpointers [rid] = id; +} + +/* Return identifier to look up for omp declare reduction. */ + +tree +c_omp_reduction_id (enum tree_code reduction_code, tree reduction_id) +{ + const char *p = NULL; + switch (reduction_code) + { + case PLUS_EXPR: p = "+"; break; + case MULT_EXPR: p = "*"; break; + case MINUS_EXPR: p = "-"; break; + case BIT_AND_EXPR: p = "&"; break; + case BIT_XOR_EXPR: p = "^"; break; + case BIT_IOR_EXPR: p = "|"; break; + case TRUTH_ANDIF_EXPR: p = "&&"; break; + case TRUTH_ORIF_EXPR: p = "||"; break; + case MIN_EXPR: p = "min"; break; + case MAX_EXPR: p = "max"; break; + default: + break; + } + + if (p == NULL) + { + if (TREE_CODE (reduction_id) != IDENTIFIER_NODE) + return error_mark_node; + p = IDENTIFIER_POINTER (reduction_id); + } + + const char prefix[] = "omp declare reduction "; + size_t lenp = sizeof (prefix); + size_t len = strlen (p); + char *name = XALLOCAVEC (char, lenp + len); + memcpy (name, prefix, lenp - 1); + memcpy (name + lenp - 1, p, len + 1); + return get_identifier (name); +} + +/* Lookup REDUCTION_ID in the current scope, or create an artificial + VAR_DECL, bind it into the current scope and return it. */ + +tree +c_omp_reduction_decl (tree reduction_id) +{ + struct c_binding *b = I_SYMBOL_BINDING (reduction_id); + if (b != NULL && B_IN_CURRENT_SCOPE (b)) + return b->decl; + + tree decl = build_decl (BUILTINS_LOCATION, VAR_DECL, + reduction_id, integer_type_node); + DECL_ARTIFICIAL (decl) = 1; + DECL_EXTERNAL (decl) = 1; + TREE_STATIC (decl) = 1; + TREE_PUBLIC (decl) = 0; + bind (reduction_id, decl, current_scope, true, false, BUILTINS_LOCATION); + return decl; +} + +/* Lookup REDUCTION_ID in the first scope where it has entry for TYPE. */ + +tree +c_omp_reduction_lookup (tree reduction_id, tree type) +{ + struct c_binding *b = I_SYMBOL_BINDING (reduction_id); + while (b) + { + tree t; + for (t = DECL_INITIAL (b->decl); t; t = TREE_CHAIN (t)) + if (comptypes (TREE_PURPOSE (t), type)) + return TREE_VALUE (t); + b = b->shadowed; + } + return error_mark_node; +} + +/* Helper function called via walk_tree, to diagnose invalid + #pragma omp declare reduction combiners or initializers. */ + +tree +c_check_omp_declare_reduction_r (tree *tp, int *, void *data) +{ + tree *vars = (tree *) data; + if (SSA_VAR_P (*tp) + && !DECL_ARTIFICIAL (*tp) + && *tp != vars[0] + && *tp != vars[1]) + { + location_t loc = DECL_SOURCE_LOCATION (vars[0]); + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (vars[0])), "omp_out") == 0) + error_at (loc, "%<#pragma omp declare reduction%> combiner refers to " + "variable %qD which is not % nor %", + *tp); + else + error_at (loc, "%<#pragma omp declare reduction%> initializer refers " + "to variable %qD which is not % nor " + "%", + *tp); + return *tp; + } + return NULL_TREE; +} + + +bool +c_check_in_current_scope (tree decl) +{ + struct c_binding *b = I_SYMBOL_BINDING (DECL_NAME (decl)); + return b != NULL && B_IN_CURRENT_SCOPE (b); +} + +#include "gt-c-c-decl.h" diff --git a/gcc/c/c-errors.c b/gcc/c/c-errors.c deleted file mode 100644 index ced12ed..0000000 --- a/gcc/c/c-errors.c +++ /dev/null @@ -1,163 +0,0 @@ -/* Various diagnostic subroutines for the GNU C language. - Copyright (C) 2000-2022 Free Software Foundation, Inc. - Contributed by Gabriel Dos Reis - -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 -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "c-tree.h" -#include "opts.h" - -/* Issue an ISO C11 pedantic warning MSGID if -pedantic outside C2X mode, - otherwise issue warning MSGID if -Wc11-c2X-compat is specified. - This function is supposed to be used for matters that are allowed in - ISO C2X but not supported in ISO C11, thus we explicitly don't pedwarn - when C2X is specified. */ - -bool -pedwarn_c11 (location_t location, int opt, const char *gmsgid, ...) -{ - diagnostic_info diagnostic; - va_list ap; - bool warned = false; - rich_location richloc (line_table, location); - - va_start (ap, gmsgid); - /* If desired, issue the C11/C2X compat warning, which is more specific - than -pedantic. */ - if (warn_c11_c2x_compat > 0) - { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, - (pedantic && !flag_isoc2x) - ? DK_PEDWARN : DK_WARNING); - diagnostic.option_index = OPT_Wc11_c2x_compat; - warned = diagnostic_report_diagnostic (global_dc, &diagnostic); - } - /* -Wno-c11-c2x-compat suppresses even the pedwarns. */ - else if (warn_c11_c2x_compat == 0) - ; - /* For -pedantic outside C2X, issue a pedwarn. */ - else if (pedantic && !flag_isoc2x) - { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN); - diagnostic.option_index = opt; - warned = diagnostic_report_diagnostic (global_dc, &diagnostic); - } - va_end (ap); - return warned; -} - -/* Issue an ISO C99 pedantic warning MSGID if -pedantic outside C11 mode, - otherwise issue warning MSGID if -Wc99-c11-compat is specified. - This function is supposed to be used for matters that are allowed in - ISO C11 but not supported in ISO C99, thus we explicitly don't pedwarn - when C11 is specified. */ - -bool -pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...) -{ - diagnostic_info diagnostic; - va_list ap; - bool warned = false; - rich_location richloc (line_table, location); - - va_start (ap, gmsgid); - /* If desired, issue the C99/C11 compat warning, which is more specific - than -pedantic. */ - if (warn_c99_c11_compat > 0) - { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, - (pedantic && !flag_isoc11) - ? DK_PEDWARN : DK_WARNING); - diagnostic.option_index = OPT_Wc99_c11_compat; - warned = diagnostic_report_diagnostic (global_dc, &diagnostic); - } - /* -Wno-c99-c11-compat suppresses even the pedwarns. */ - else if (warn_c99_c11_compat == 0) - ; - /* For -pedantic outside C11, issue a pedwarn. */ - else if (pedantic && !flag_isoc11) - { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN); - diagnostic.option_index = opt; - warned = diagnostic_report_diagnostic (global_dc, &diagnostic); - } - va_end (ap); - return warned; -} - -/* Issue an ISO C90 pedantic warning MSGID if -pedantic outside C99 mode, - otherwise issue warning MSGID if -Wc90-c99-compat is specified, or if - a specific option such as -Wlong-long is specified. - This function is supposed to be used for matters that are allowed in - ISO C99 but not supported in ISO C90, thus we explicitly don't pedwarn - when C99 is specified. (There is no flag_c90.) */ - -bool -pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...) -{ - diagnostic_info diagnostic; - va_list ap; - bool warned = false; - rich_location richloc (line_table, location); - - va_start (ap, gmsgid); - /* Warnings such as -Wvla are the most specific ones. */ - if (opt != OPT_Wpedantic) - { - int opt_var = *(int *) option_flag_var (opt, &global_options); - if (opt_var == 0) - goto out; - else if (opt_var > 0) - { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, - (pedantic && !flag_isoc99) - ? DK_PEDWARN : DK_WARNING); - diagnostic.option_index = opt; - diagnostic_report_diagnostic (global_dc, &diagnostic); - warned = true; - goto out; - } - } - /* Maybe we want to issue the C90/C99 compat warning, which is more - specific than -pedantic. */ - if (warn_c90_c99_compat > 0) - { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, - (pedantic && !flag_isoc99) - ? DK_PEDWARN : DK_WARNING); - diagnostic.option_index = OPT_Wc90_c99_compat; - diagnostic_report_diagnostic (global_dc, &diagnostic); - } - /* -Wno-c90-c99-compat suppresses the pedwarns. */ - else if (warn_c90_c99_compat == 0) - ; - /* For -pedantic outside C99, issue a pedwarn. */ - else if (pedantic && !flag_isoc99) - { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN); - diagnostic.option_index = opt; - diagnostic_report_diagnostic (global_dc, &diagnostic); - warned = true; - } -out: - va_end (ap); - return warned; -} diff --git a/gcc/c/c-errors.cc b/gcc/c/c-errors.cc new file mode 100644 index 0000000..ced12ed --- /dev/null +++ b/gcc/c/c-errors.cc @@ -0,0 +1,163 @@ +/* Various diagnostic subroutines for the GNU C language. + Copyright (C) 2000-2022 Free Software Foundation, Inc. + Contributed by Gabriel Dos Reis + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "c-tree.h" +#include "opts.h" + +/* Issue an ISO C11 pedantic warning MSGID if -pedantic outside C2X mode, + otherwise issue warning MSGID if -Wc11-c2X-compat is specified. + This function is supposed to be used for matters that are allowed in + ISO C2X but not supported in ISO C11, thus we explicitly don't pedwarn + when C2X is specified. */ + +bool +pedwarn_c11 (location_t location, int opt, const char *gmsgid, ...) +{ + diagnostic_info diagnostic; + va_list ap; + bool warned = false; + rich_location richloc (line_table, location); + + va_start (ap, gmsgid); + /* If desired, issue the C11/C2X compat warning, which is more specific + than -pedantic. */ + if (warn_c11_c2x_compat > 0) + { + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + (pedantic && !flag_isoc2x) + ? DK_PEDWARN : DK_WARNING); + diagnostic.option_index = OPT_Wc11_c2x_compat; + warned = diagnostic_report_diagnostic (global_dc, &diagnostic); + } + /* -Wno-c11-c2x-compat suppresses even the pedwarns. */ + else if (warn_c11_c2x_compat == 0) + ; + /* For -pedantic outside C2X, issue a pedwarn. */ + else if (pedantic && !flag_isoc2x) + { + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN); + diagnostic.option_index = opt; + warned = diagnostic_report_diagnostic (global_dc, &diagnostic); + } + va_end (ap); + return warned; +} + +/* Issue an ISO C99 pedantic warning MSGID if -pedantic outside C11 mode, + otherwise issue warning MSGID if -Wc99-c11-compat is specified. + This function is supposed to be used for matters that are allowed in + ISO C11 but not supported in ISO C99, thus we explicitly don't pedwarn + when C11 is specified. */ + +bool +pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...) +{ + diagnostic_info diagnostic; + va_list ap; + bool warned = false; + rich_location richloc (line_table, location); + + va_start (ap, gmsgid); + /* If desired, issue the C99/C11 compat warning, which is more specific + than -pedantic. */ + if (warn_c99_c11_compat > 0) + { + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + (pedantic && !flag_isoc11) + ? DK_PEDWARN : DK_WARNING); + diagnostic.option_index = OPT_Wc99_c11_compat; + warned = diagnostic_report_diagnostic (global_dc, &diagnostic); + } + /* -Wno-c99-c11-compat suppresses even the pedwarns. */ + else if (warn_c99_c11_compat == 0) + ; + /* For -pedantic outside C11, issue a pedwarn. */ + else if (pedantic && !flag_isoc11) + { + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN); + diagnostic.option_index = opt; + warned = diagnostic_report_diagnostic (global_dc, &diagnostic); + } + va_end (ap); + return warned; +} + +/* Issue an ISO C90 pedantic warning MSGID if -pedantic outside C99 mode, + otherwise issue warning MSGID if -Wc90-c99-compat is specified, or if + a specific option such as -Wlong-long is specified. + This function is supposed to be used for matters that are allowed in + ISO C99 but not supported in ISO C90, thus we explicitly don't pedwarn + when C99 is specified. (There is no flag_c90.) */ + +bool +pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...) +{ + diagnostic_info diagnostic; + va_list ap; + bool warned = false; + rich_location richloc (line_table, location); + + va_start (ap, gmsgid); + /* Warnings such as -Wvla are the most specific ones. */ + if (opt != OPT_Wpedantic) + { + int opt_var = *(int *) option_flag_var (opt, &global_options); + if (opt_var == 0) + goto out; + else if (opt_var > 0) + { + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + (pedantic && !flag_isoc99) + ? DK_PEDWARN : DK_WARNING); + diagnostic.option_index = opt; + diagnostic_report_diagnostic (global_dc, &diagnostic); + warned = true; + goto out; + } + } + /* Maybe we want to issue the C90/C99 compat warning, which is more + specific than -pedantic. */ + if (warn_c90_c99_compat > 0) + { + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + (pedantic && !flag_isoc99) + ? DK_PEDWARN : DK_WARNING); + diagnostic.option_index = OPT_Wc90_c99_compat; + diagnostic_report_diagnostic (global_dc, &diagnostic); + } + /* -Wno-c90-c99-compat suppresses the pedwarns. */ + else if (warn_c90_c99_compat == 0) + ; + /* For -pedantic outside C99, issue a pedwarn. */ + else if (pedantic && !flag_isoc99) + { + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN); + diagnostic.option_index = opt; + diagnostic_report_diagnostic (global_dc, &diagnostic); + warned = true; + } +out: + va_end (ap); + return warned; +} diff --git a/gcc/c/c-fold.c b/gcc/c/c-fold.c deleted file mode 100644 index fc593753..0000000 --- a/gcc/c/c-fold.c +++ /dev/null @@ -1,698 +0,0 @@ -/* Support for fully folding sub-trees of an expression for C compiler. - Copyright (C) 1992-2022 Free Software Foundation, Inc. - -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 -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "target.h" -#include "function.h" -#include "bitmap.h" -#include "c-tree.h" -#include "intl.h" -#include "gimplify.h" - -static tree c_fully_fold_internal (tree expr, bool, bool *, bool *, bool, - bool); - -/* If DISABLE is true, stop issuing warnings. This is used when - parsing code that we know will not be executed. This function may - be called multiple times, and works as a stack. */ - -static void -c_disable_warnings (bool disable) -{ - if (disable) - { - ++c_inhibit_evaluation_warnings; - fold_defer_overflow_warnings (); - } -} - -/* If ENABLE is true, reenable issuing warnings. */ - -static void -c_enable_warnings (bool enable) -{ - if (enable) - { - --c_inhibit_evaluation_warnings; - fold_undefer_and_ignore_overflow_warnings (); - } -} - -/* Try to fold ARRAY_REF ary[index] if possible and not handled by - normal fold, return NULL_TREE otherwise. */ - -static tree -c_fold_array_ref (tree type, tree ary, tree index) -{ - if (TREE_CODE (ary) != STRING_CST - || TREE_CODE (index) != INTEGER_CST - || TREE_OVERFLOW (index) - || TREE_CODE (TREE_TYPE (ary)) != ARRAY_TYPE - || !tree_fits_uhwi_p (index)) - return NULL_TREE; - - tree elem_type = TREE_TYPE (TREE_TYPE (ary)); - unsigned elem_nchars = (TYPE_PRECISION (elem_type) - / TYPE_PRECISION (char_type_node)); - unsigned len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars; - tree nelts = array_type_nelts (TREE_TYPE (ary)); - bool dummy1 = true, dummy2 = true; - nelts = c_fully_fold_internal (nelts, true, &dummy1, &dummy2, false, false); - unsigned HOST_WIDE_INT i = tree_to_uhwi (index); - if (!tree_int_cst_le (index, nelts) - || i >= len - || i + elem_nchars > len) - return NULL_TREE; - - if (elem_nchars == 1) - return build_int_cst (type, TREE_STRING_POINTER (ary)[i]); - - const unsigned char *ptr - = ((const unsigned char *)TREE_STRING_POINTER (ary) + i * elem_nchars); - return native_interpret_expr (type, ptr, elem_nchars); -} - -/* Fully fold EXPR, an expression that was not folded (beyond integer - constant expressions and null pointer constants) when being built - up. If IN_INIT, this is in a static initializer and certain - changes are made to the folding done. Clear *MAYBE_CONST if - MAYBE_CONST is not NULL and EXPR is definitely not a constant - expression because it contains an evaluated operator (in C99) or an - operator outside of sizeof returning an integer constant (in C90) - not permitted in constant expressions, or because it contains an - evaluated arithmetic overflow. (*MAYBE_CONST should typically be - set to true by callers before calling this function.) Return the - folded expression. Function arguments have already been folded - before calling this function, as have the contents of SAVE_EXPR, - TARGET_EXPR, BIND_EXPR, VA_ARG_EXPR, OBJ_TYPE_REF and - C_MAYBE_CONST_EXPR. LVAL is true if it should be treated as an - lvalue. */ - -tree -c_fully_fold (tree expr, bool in_init, bool *maybe_const, bool lval) -{ - tree ret; - tree eptype = NULL_TREE; - bool dummy = true; - bool maybe_const_itself = true; - location_t loc = EXPR_LOCATION (expr); - - if (!maybe_const) - maybe_const = &dummy; - if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) - { - eptype = TREE_TYPE (expr); - expr = TREE_OPERAND (expr, 0); - } - ret = c_fully_fold_internal (expr, in_init, maybe_const, - &maybe_const_itself, false, lval); - if (eptype) - ret = fold_convert_loc (loc, eptype, ret); - *maybe_const &= maybe_const_itself; - return ret; -} - -/* Internal helper for c_fully_fold. EXPR and IN_INIT are as for - c_fully_fold. *MAYBE_CONST_OPERANDS is cleared because of operands - not permitted, while *MAYBE_CONST_ITSELF is cleared because of - arithmetic overflow (for C90, *MAYBE_CONST_OPERANDS is carried from - both evaluated and unevaluated subexpressions while - *MAYBE_CONST_ITSELF is carried from only evaluated - subexpressions). FOR_INT_CONST indicates if EXPR is an expression - with integer constant operands, and if any of the operands doesn't - get folded to an integer constant, don't fold the expression itself. - LVAL indicates folding of lvalue, where we can't replace it with - an rvalue. */ - -static tree -c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, - bool *maybe_const_itself, bool for_int_const, bool lval) -{ - tree ret = expr; - enum tree_code code = TREE_CODE (expr); - enum tree_code_class kind = TREE_CODE_CLASS (code); - location_t loc = EXPR_LOCATION (expr); - tree op0, op1, op2, op3; - tree orig_op0, orig_op1, orig_op2; - bool op0_const = true, op1_const = true, op2_const = true; - bool op0_const_self = true, op1_const_self = true, op2_const_self = true; - bool nowarning = warning_suppressed_p (expr, OPT_Woverflow); - bool unused_p; - bool op0_lval = false; - source_range old_range; - - /* Constants, declarations, statements, errors, and anything else not - counted as an expression cannot usefully be folded further at this - point. */ - if (!IS_EXPR_CODE_CLASS (kind) || kind == tcc_statement) - { - /* Except for variables which we can optimize to its initializer. */ - if (VAR_P (expr) && !lval && (optimize || in_init)) - { - if (in_init) - ret = decl_constant_value_1 (expr, true); - else - { - ret = decl_constant_value (expr); - if (ret != expr - && (TYPE_MODE (TREE_TYPE (ret)) == BLKmode - || TREE_CODE (TREE_TYPE (ret)) == ARRAY_TYPE)) - return expr; - } - /* Avoid unwanted tree sharing between the initializer and current - function's body where the tree can be modified e.g. by the - gimplifier. */ - if (ret != expr && TREE_STATIC (expr)) - ret = unshare_expr (ret); - return ret; - } - return expr; - } - - if (IS_EXPR_CODE_CLASS (kind)) - old_range = EXPR_LOCATION_RANGE (expr); - - /* Operands of variable-length expressions (function calls) have - already been folded, as have __builtin_* function calls, and such - expressions cannot occur in constant expressions. */ - if (kind == tcc_vl_exp) - { - *maybe_const_operands = false; - ret = fold (expr); - goto out; - } - - if (code == C_MAYBE_CONST_EXPR) - { - tree pre = C_MAYBE_CONST_EXPR_PRE (expr); - tree inner = C_MAYBE_CONST_EXPR_EXPR (expr); - if (C_MAYBE_CONST_EXPR_NON_CONST (expr)) - *maybe_const_operands = false; - if (C_MAYBE_CONST_EXPR_INT_OPERANDS (expr)) - { - *maybe_const_itself = false; - inner = c_fully_fold_internal (inner, in_init, maybe_const_operands, - maybe_const_itself, true, lval); - } - if (pre && !in_init) - ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr), pre, inner); - else - ret = inner; - goto out; - } - - /* Assignment, increment, decrement, function call and comma - operators, and statement expressions, cannot occur in constant - expressions if evaluated / outside of sizeof. (Function calls - were handled above, though VA_ARG_EXPR is treated like a function - call here, and statement expressions are handled through - C_MAYBE_CONST_EXPR to avoid folding inside them.) */ - switch (code) - { - case MODIFY_EXPR: - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - case COMPOUND_EXPR: - *maybe_const_operands = false; - break; - - case VA_ARG_EXPR: - case TARGET_EXPR: - case BIND_EXPR: - case OBJ_TYPE_REF: - *maybe_const_operands = false; - ret = fold (expr); - goto out; - - default: - break; - } - - /* Fold individual tree codes as appropriate. */ - switch (code) - { - case COMPOUND_LITERAL_EXPR: - /* Any non-constancy will have been marked in a containing - C_MAYBE_CONST_EXPR; there is no more folding to do here. */ - goto out; - - case COMPONENT_REF: - orig_op0 = op0 = TREE_OPERAND (expr, 0); - op1 = TREE_OPERAND (expr, 1); - op2 = TREE_OPERAND (expr, 2); - op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, - maybe_const_itself, for_int_const, lval); - STRIP_TYPE_NOPS (op0); - if (op0 != orig_op0) - ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2); - if (ret != expr) - { - TREE_READONLY (ret) = TREE_READONLY (expr); - TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); - } - if (!lval) - ret = fold (ret); - goto out; - - case ARRAY_REF: - orig_op0 = op0 = TREE_OPERAND (expr, 0); - orig_op1 = op1 = TREE_OPERAND (expr, 1); - op2 = TREE_OPERAND (expr, 2); - op3 = TREE_OPERAND (expr, 3); - op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, - maybe_const_itself, for_int_const, lval); - STRIP_TYPE_NOPS (op0); - op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, - maybe_const_itself, for_int_const, false); - STRIP_TYPE_NOPS (op1); - /* Fold "foo"[2] in initializers. */ - if (!lval && in_init) - { - ret = c_fold_array_ref (TREE_TYPE (expr), op0, op1); - if (ret) - goto out; - ret = expr; - } - if (op0 != orig_op0 || op1 != orig_op1) - ret = build4 (ARRAY_REF, TREE_TYPE (expr), op0, op1, op2, op3); - if (ret != expr) - { - TREE_READONLY (ret) = TREE_READONLY (expr); - TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); - TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); - } - if (!lval) - ret = fold (ret); - goto out; - - case MODIFY_EXPR: - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - op0_lval = true; - /* FALLTHRU */ - case COMPOUND_EXPR: - case PLUS_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case POINTER_PLUS_EXPR: - case POINTER_DIFF_EXPR: - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case TRUNC_MOD_EXPR: - case RDIV_EXPR: - case EXACT_DIV_EXPR: - case LSHIFT_EXPR: - case RSHIFT_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - case BIT_AND_EXPR: - case LT_EXPR: - case LE_EXPR: - case GT_EXPR: - case GE_EXPR: - case EQ_EXPR: - case NE_EXPR: - case COMPLEX_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - case UNORDERED_EXPR: - case ORDERED_EXPR: - case UNLT_EXPR: - case UNLE_EXPR: - case UNGT_EXPR: - case UNGE_EXPR: - case UNEQ_EXPR: - case MEM_REF: - /* Binary operations evaluating both arguments (increment and - decrement are binary internally in GCC). */ - orig_op0 = op0 = TREE_OPERAND (expr, 0); - orig_op1 = op1 = TREE_OPERAND (expr, 1); - op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, - maybe_const_itself, for_int_const, - op0_lval); - STRIP_TYPE_NOPS (op0); - /* The RHS of a MODIFY_EXPR was fully folded when building that - expression for the sake of conversion warnings. */ - if (code != MODIFY_EXPR) - op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, - maybe_const_itself, for_int_const, false); - STRIP_TYPE_NOPS (op1); - - if (for_int_const && (TREE_CODE (op0) != INTEGER_CST - || TREE_CODE (op1) != INTEGER_CST)) - goto out; - - if (op0 != orig_op0 || op1 != orig_op1 || in_init) - ret = in_init - ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1) - : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1); - else - ret = fold (expr); - if (TREE_OVERFLOW_P (ret) - && !TREE_OVERFLOW_P (op0) - && !(BINARY_CLASS_P (op0) && TREE_OVERFLOW_P (TREE_OPERAND (op0, 1))) - && !TREE_OVERFLOW_P (op1)) - overflow_warning (EXPR_LOC_OR_LOC (expr, input_location), ret, expr); - if (code == LSHIFT_EXPR - && TREE_CODE (orig_op0) != INTEGER_CST - && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE - && TREE_CODE (op0) == INTEGER_CST - && c_inhibit_evaluation_warnings == 0 - && tree_int_cst_sgn (op0) < 0) - warning_at (loc, OPT_Wshift_negative_value, - "left shift of negative value"); - if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR) - && TREE_CODE (orig_op1) != INTEGER_CST - && TREE_CODE (op1) == INTEGER_CST - && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE - && c_inhibit_evaluation_warnings == 0) - { - if (tree_int_cst_sgn (op1) < 0) - warning_at (loc, OPT_Wshift_count_negative, - (code == LSHIFT_EXPR - ? G_("left shift count is negative") - : G_("right shift count is negative"))); - else if ((TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE - || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE) - && compare_tree_int (op1, - TYPE_PRECISION (TREE_TYPE (orig_op0))) - >= 0) - warning_at (loc, OPT_Wshift_count_overflow, - (code == LSHIFT_EXPR - ? G_("left shift count >= width of type") - : G_("right shift count >= width of type"))); - else if (TREE_CODE (TREE_TYPE (orig_op0)) == VECTOR_TYPE - && compare_tree_int (op1, - TYPE_PRECISION (TREE_TYPE (TREE_TYPE (orig_op0)))) - >= 0) - warning_at (loc, OPT_Wshift_count_overflow, - code == LSHIFT_EXPR - ? G_("left shift count >= width of vector element") - : G_("right shift count >= width of vector element")); - } - if (code == LSHIFT_EXPR - /* If either OP0 has been folded to INTEGER_CST... */ - && ((TREE_CODE (orig_op0) != INTEGER_CST - && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE - && TREE_CODE (op0) == INTEGER_CST) - /* ...or if OP1 has been folded to INTEGER_CST... */ - || (TREE_CODE (orig_op1) != INTEGER_CST - && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE - && TREE_CODE (op1) == INTEGER_CST)) - && c_inhibit_evaluation_warnings == 0) - /* ...then maybe we can detect an overflow. */ - maybe_warn_shift_overflow (loc, op0, op1); - if ((code == TRUNC_DIV_EXPR - || code == CEIL_DIV_EXPR - || code == FLOOR_DIV_EXPR - || code == EXACT_DIV_EXPR - || code == TRUNC_MOD_EXPR) - && TREE_CODE (orig_op1) != INTEGER_CST - && TREE_CODE (op1) == INTEGER_CST - && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE - || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE) - && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE) - warn_for_div_by_zero (loc, op1); - if (code == MEM_REF - && ret != expr - && TREE_CODE (ret) == MEM_REF) - { - TREE_READONLY (ret) = TREE_READONLY (expr); - TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); - TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); - } - goto out; - - case ADDR_EXPR: - op0_lval = true; - goto unary; - case REALPART_EXPR: - case IMAGPART_EXPR: - case VIEW_CONVERT_EXPR: - op0_lval = lval; - /* FALLTHRU */ - case INDIRECT_REF: - case FIX_TRUNC_EXPR: - case FLOAT_EXPR: - CASE_CONVERT: - case ADDR_SPACE_CONVERT_EXPR: - case NON_LVALUE_EXPR: - case NEGATE_EXPR: - case BIT_NOT_EXPR: - case TRUTH_NOT_EXPR: - case CONJ_EXPR: - unary: - /* Unary operations. */ - orig_op0 = op0 = TREE_OPERAND (expr, 0); - op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, - maybe_const_itself, for_int_const, - op0_lval); - STRIP_TYPE_NOPS (op0); - - if (for_int_const && TREE_CODE (op0) != INTEGER_CST) - goto out; - - /* ??? Cope with user tricks that amount to offsetof. The middle-end is - not prepared to deal with them if they occur in initializers. */ - if (op0 != orig_op0 - && code == ADDR_EXPR - && (op1 = get_base_address (op0)) != NULL_TREE - && INDIRECT_REF_P (op1) - && TREE_CONSTANT (TREE_OPERAND (op1, 0))) - ret = fold_offsetof (op0, TREE_TYPE (expr)); - else if (op0 != orig_op0 || in_init) - ret = in_init - ? fold_build1_initializer_loc (loc, code, TREE_TYPE (expr), op0) - : fold_build1_loc (loc, code, TREE_TYPE (expr), op0); - else - ret = fold (expr); - if (code == INDIRECT_REF - && ret != expr - && INDIRECT_REF_P (ret)) - { - TREE_READONLY (ret) = TREE_READONLY (expr); - TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); - TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); - } - switch (code) - { - case FIX_TRUNC_EXPR: - case FLOAT_EXPR: - CASE_CONVERT: - /* Don't warn about explicit conversions. We will already - have warned about suspect implicit conversions. */ - break; - - default: - if (TREE_OVERFLOW_P (ret) && !TREE_OVERFLOW_P (op0)) - overflow_warning (EXPR_LOCATION (expr), ret, op0); - break; - } - goto out; - - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - /* Binary operations not necessarily evaluating both - arguments. */ - orig_op0 = op0 = TREE_OPERAND (expr, 0); - orig_op1 = op1 = TREE_OPERAND (expr, 1); - op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self, - for_int_const, false); - STRIP_TYPE_NOPS (op0); - - unused_p = (op0 == (code == TRUTH_ANDIF_EXPR - ? truthvalue_false_node - : truthvalue_true_node)); - c_disable_warnings (unused_p); - op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self, - for_int_const, false); - STRIP_TYPE_NOPS (op1); - c_enable_warnings (unused_p); - - if (for_int_const - && (TREE_CODE (op0) != INTEGER_CST - /* Require OP1 be an INTEGER_CST only if it's evaluated. */ - || (!unused_p && TREE_CODE (op1) != INTEGER_CST))) - goto out; - - if (op0 != orig_op0 || op1 != orig_op1 || in_init) - ret = in_init - ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1) - : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1); - else - ret = fold (expr); - *maybe_const_operands &= op0_const; - *maybe_const_itself &= op0_const_self; - if (!(flag_isoc99 - && op0_const - && op0_const_self - && (code == TRUTH_ANDIF_EXPR - ? op0 == truthvalue_false_node - : op0 == truthvalue_true_node))) - *maybe_const_operands &= op1_const; - if (!(op0_const - && op0_const_self - && (code == TRUTH_ANDIF_EXPR - ? op0 == truthvalue_false_node - : op0 == truthvalue_true_node))) - *maybe_const_itself &= op1_const_self; - goto out; - - case COND_EXPR: - orig_op0 = op0 = TREE_OPERAND (expr, 0); - orig_op1 = op1 = TREE_OPERAND (expr, 1); - orig_op2 = op2 = TREE_OPERAND (expr, 2); - op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self, - for_int_const, false); - - STRIP_TYPE_NOPS (op0); - c_disable_warnings (op0 == truthvalue_false_node); - op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self, - for_int_const, false); - STRIP_TYPE_NOPS (op1); - c_enable_warnings (op0 == truthvalue_false_node); - - c_disable_warnings (op0 == truthvalue_true_node); - op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self, - for_int_const, false); - STRIP_TYPE_NOPS (op2); - c_enable_warnings (op0 == truthvalue_true_node); - - if (for_int_const - && (TREE_CODE (op0) != INTEGER_CST - /* Only the evaluated operand must be an INTEGER_CST. */ - || (op0 == truthvalue_true_node - ? TREE_CODE (op1) != INTEGER_CST - : TREE_CODE (op2) != INTEGER_CST))) - goto out; - - if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2) - ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2); - else - ret = fold (expr); - *maybe_const_operands &= op0_const; - *maybe_const_itself &= op0_const_self; - if (!(flag_isoc99 - && op0_const - && op0_const_self - && op0 == truthvalue_false_node)) - *maybe_const_operands &= op1_const; - if (!(op0_const - && op0_const_self - && op0 == truthvalue_false_node)) - *maybe_const_itself &= op1_const_self; - if (!(flag_isoc99 - && op0_const - && op0_const_self - && op0 == truthvalue_true_node)) - *maybe_const_operands &= op2_const; - if (!(op0_const - && op0_const_self - && op0 == truthvalue_true_node)) - *maybe_const_itself &= op2_const_self; - goto out; - - case VEC_COND_EXPR: - orig_op0 = op0 = TREE_OPERAND (expr, 0); - orig_op1 = op1 = TREE_OPERAND (expr, 1); - orig_op2 = op2 = TREE_OPERAND (expr, 2); - op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, - maybe_const_itself, for_int_const, false); - STRIP_TYPE_NOPS (op0); - op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, - maybe_const_itself, for_int_const, false); - STRIP_TYPE_NOPS (op1); - op2 = c_fully_fold_internal (op2, in_init, maybe_const_operands, - maybe_const_itself, for_int_const, false); - STRIP_TYPE_NOPS (op2); - - if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2) - ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2); - else - ret = fold (expr); - goto out; - - case EXCESS_PRECISION_EXPR: - /* Each case where an operand with excess precision may be - encountered must remove the EXCESS_PRECISION_EXPR around - inner operands and possibly put one around the whole - expression or possibly convert to the semantic type (which - c_fully_fold does); we cannot tell at this stage which is - appropriate in any particular case. */ - gcc_unreachable (); - - case SAVE_EXPR: - /* Make sure to fold the contents of a SAVE_EXPR exactly once. */ - op0 = TREE_OPERAND (expr, 0); - if (!SAVE_EXPR_FOLDED_P (expr)) - { - op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, - maybe_const_itself, for_int_const, - false); - TREE_OPERAND (expr, 0) = op0; - SAVE_EXPR_FOLDED_P (expr) = true; - } - /* Return the SAVE_EXPR operand if it is invariant. */ - if (tree_invariant_p (op0)) - ret = op0; - goto out; - - default: - /* Various codes may appear through folding built-in functions - and their arguments. */ - goto out; - } - - out: - /* Some folding may introduce NON_LVALUE_EXPRs; all lvalue checks - have been done by this point, so remove them again. */ - nowarning |= warning_suppressed_p (ret, OPT_Woverflow); - STRIP_TYPE_NOPS (ret); - if (nowarning && !warning_suppressed_p (ret, OPT_Woverflow)) - { - if (!CAN_HAVE_LOCATION_P (ret)) - ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret); - suppress_warning (ret, OPT_Woverflow); - } - if (ret != expr) - { - protected_set_expr_location (ret, loc); - if (IS_EXPR_CODE_CLASS (kind)) - set_source_range (ret, old_range.m_start, old_range.m_finish); - } - return ret; -} - -/* Fold X for consideration by one of the warning functions when checking - whether an expression has a constant value. */ - -tree -fold_for_warn (tree x) -{ - /* The C front-end has already folded X appropriately. */ - return x; -} diff --git a/gcc/c/c-fold.cc b/gcc/c/c-fold.cc new file mode 100644 index 0000000..fc593753 --- /dev/null +++ b/gcc/c/c-fold.cc @@ -0,0 +1,698 @@ +/* Support for fully folding sub-trees of an expression for C compiler. + Copyright (C) 1992-2022 Free Software Foundation, Inc. + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "function.h" +#include "bitmap.h" +#include "c-tree.h" +#include "intl.h" +#include "gimplify.h" + +static tree c_fully_fold_internal (tree expr, bool, bool *, bool *, bool, + bool); + +/* If DISABLE is true, stop issuing warnings. This is used when + parsing code that we know will not be executed. This function may + be called multiple times, and works as a stack. */ + +static void +c_disable_warnings (bool disable) +{ + if (disable) + { + ++c_inhibit_evaluation_warnings; + fold_defer_overflow_warnings (); + } +} + +/* If ENABLE is true, reenable issuing warnings. */ + +static void +c_enable_warnings (bool enable) +{ + if (enable) + { + --c_inhibit_evaluation_warnings; + fold_undefer_and_ignore_overflow_warnings (); + } +} + +/* Try to fold ARRAY_REF ary[index] if possible and not handled by + normal fold, return NULL_TREE otherwise. */ + +static tree +c_fold_array_ref (tree type, tree ary, tree index) +{ + if (TREE_CODE (ary) != STRING_CST + || TREE_CODE (index) != INTEGER_CST + || TREE_OVERFLOW (index) + || TREE_CODE (TREE_TYPE (ary)) != ARRAY_TYPE + || !tree_fits_uhwi_p (index)) + return NULL_TREE; + + tree elem_type = TREE_TYPE (TREE_TYPE (ary)); + unsigned elem_nchars = (TYPE_PRECISION (elem_type) + / TYPE_PRECISION (char_type_node)); + unsigned len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars; + tree nelts = array_type_nelts (TREE_TYPE (ary)); + bool dummy1 = true, dummy2 = true; + nelts = c_fully_fold_internal (nelts, true, &dummy1, &dummy2, false, false); + unsigned HOST_WIDE_INT i = tree_to_uhwi (index); + if (!tree_int_cst_le (index, nelts) + || i >= len + || i + elem_nchars > len) + return NULL_TREE; + + if (elem_nchars == 1) + return build_int_cst (type, TREE_STRING_POINTER (ary)[i]); + + const unsigned char *ptr + = ((const unsigned char *)TREE_STRING_POINTER (ary) + i * elem_nchars); + return native_interpret_expr (type, ptr, elem_nchars); +} + +/* Fully fold EXPR, an expression that was not folded (beyond integer + constant expressions and null pointer constants) when being built + up. If IN_INIT, this is in a static initializer and certain + changes are made to the folding done. Clear *MAYBE_CONST if + MAYBE_CONST is not NULL and EXPR is definitely not a constant + expression because it contains an evaluated operator (in C99) or an + operator outside of sizeof returning an integer constant (in C90) + not permitted in constant expressions, or because it contains an + evaluated arithmetic overflow. (*MAYBE_CONST should typically be + set to true by callers before calling this function.) Return the + folded expression. Function arguments have already been folded + before calling this function, as have the contents of SAVE_EXPR, + TARGET_EXPR, BIND_EXPR, VA_ARG_EXPR, OBJ_TYPE_REF and + C_MAYBE_CONST_EXPR. LVAL is true if it should be treated as an + lvalue. */ + +tree +c_fully_fold (tree expr, bool in_init, bool *maybe_const, bool lval) +{ + tree ret; + tree eptype = NULL_TREE; + bool dummy = true; + bool maybe_const_itself = true; + location_t loc = EXPR_LOCATION (expr); + + if (!maybe_const) + maybe_const = &dummy; + if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) + { + eptype = TREE_TYPE (expr); + expr = TREE_OPERAND (expr, 0); + } + ret = c_fully_fold_internal (expr, in_init, maybe_const, + &maybe_const_itself, false, lval); + if (eptype) + ret = fold_convert_loc (loc, eptype, ret); + *maybe_const &= maybe_const_itself; + return ret; +} + +/* Internal helper for c_fully_fold. EXPR and IN_INIT are as for + c_fully_fold. *MAYBE_CONST_OPERANDS is cleared because of operands + not permitted, while *MAYBE_CONST_ITSELF is cleared because of + arithmetic overflow (for C90, *MAYBE_CONST_OPERANDS is carried from + both evaluated and unevaluated subexpressions while + *MAYBE_CONST_ITSELF is carried from only evaluated + subexpressions). FOR_INT_CONST indicates if EXPR is an expression + with integer constant operands, and if any of the operands doesn't + get folded to an integer constant, don't fold the expression itself. + LVAL indicates folding of lvalue, where we can't replace it with + an rvalue. */ + +static tree +c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, + bool *maybe_const_itself, bool for_int_const, bool lval) +{ + tree ret = expr; + enum tree_code code = TREE_CODE (expr); + enum tree_code_class kind = TREE_CODE_CLASS (code); + location_t loc = EXPR_LOCATION (expr); + tree op0, op1, op2, op3; + tree orig_op0, orig_op1, orig_op2; + bool op0_const = true, op1_const = true, op2_const = true; + bool op0_const_self = true, op1_const_self = true, op2_const_self = true; + bool nowarning = warning_suppressed_p (expr, OPT_Woverflow); + bool unused_p; + bool op0_lval = false; + source_range old_range; + + /* Constants, declarations, statements, errors, and anything else not + counted as an expression cannot usefully be folded further at this + point. */ + if (!IS_EXPR_CODE_CLASS (kind) || kind == tcc_statement) + { + /* Except for variables which we can optimize to its initializer. */ + if (VAR_P (expr) && !lval && (optimize || in_init)) + { + if (in_init) + ret = decl_constant_value_1 (expr, true); + else + { + ret = decl_constant_value (expr); + if (ret != expr + && (TYPE_MODE (TREE_TYPE (ret)) == BLKmode + || TREE_CODE (TREE_TYPE (ret)) == ARRAY_TYPE)) + return expr; + } + /* Avoid unwanted tree sharing between the initializer and current + function's body where the tree can be modified e.g. by the + gimplifier. */ + if (ret != expr && TREE_STATIC (expr)) + ret = unshare_expr (ret); + return ret; + } + return expr; + } + + if (IS_EXPR_CODE_CLASS (kind)) + old_range = EXPR_LOCATION_RANGE (expr); + + /* Operands of variable-length expressions (function calls) have + already been folded, as have __builtin_* function calls, and such + expressions cannot occur in constant expressions. */ + if (kind == tcc_vl_exp) + { + *maybe_const_operands = false; + ret = fold (expr); + goto out; + } + + if (code == C_MAYBE_CONST_EXPR) + { + tree pre = C_MAYBE_CONST_EXPR_PRE (expr); + tree inner = C_MAYBE_CONST_EXPR_EXPR (expr); + if (C_MAYBE_CONST_EXPR_NON_CONST (expr)) + *maybe_const_operands = false; + if (C_MAYBE_CONST_EXPR_INT_OPERANDS (expr)) + { + *maybe_const_itself = false; + inner = c_fully_fold_internal (inner, in_init, maybe_const_operands, + maybe_const_itself, true, lval); + } + if (pre && !in_init) + ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr), pre, inner); + else + ret = inner; + goto out; + } + + /* Assignment, increment, decrement, function call and comma + operators, and statement expressions, cannot occur in constant + expressions if evaluated / outside of sizeof. (Function calls + were handled above, though VA_ARG_EXPR is treated like a function + call here, and statement expressions are handled through + C_MAYBE_CONST_EXPR to avoid folding inside them.) */ + switch (code) + { + case MODIFY_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case COMPOUND_EXPR: + *maybe_const_operands = false; + break; + + case VA_ARG_EXPR: + case TARGET_EXPR: + case BIND_EXPR: + case OBJ_TYPE_REF: + *maybe_const_operands = false; + ret = fold (expr); + goto out; + + default: + break; + } + + /* Fold individual tree codes as appropriate. */ + switch (code) + { + case COMPOUND_LITERAL_EXPR: + /* Any non-constancy will have been marked in a containing + C_MAYBE_CONST_EXPR; there is no more folding to do here. */ + goto out; + + case COMPONENT_REF: + orig_op0 = op0 = TREE_OPERAND (expr, 0); + op1 = TREE_OPERAND (expr, 1); + op2 = TREE_OPERAND (expr, 2); + op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, + maybe_const_itself, for_int_const, lval); + STRIP_TYPE_NOPS (op0); + if (op0 != orig_op0) + ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2); + if (ret != expr) + { + TREE_READONLY (ret) = TREE_READONLY (expr); + TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); + } + if (!lval) + ret = fold (ret); + goto out; + + case ARRAY_REF: + orig_op0 = op0 = TREE_OPERAND (expr, 0); + orig_op1 = op1 = TREE_OPERAND (expr, 1); + op2 = TREE_OPERAND (expr, 2); + op3 = TREE_OPERAND (expr, 3); + op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, + maybe_const_itself, for_int_const, lval); + STRIP_TYPE_NOPS (op0); + op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, + maybe_const_itself, for_int_const, false); + STRIP_TYPE_NOPS (op1); + /* Fold "foo"[2] in initializers. */ + if (!lval && in_init) + { + ret = c_fold_array_ref (TREE_TYPE (expr), op0, op1); + if (ret) + goto out; + ret = expr; + } + if (op0 != orig_op0 || op1 != orig_op1) + ret = build4 (ARRAY_REF, TREE_TYPE (expr), op0, op1, op2, op3); + if (ret != expr) + { + TREE_READONLY (ret) = TREE_READONLY (expr); + TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); + TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); + } + if (!lval) + ret = fold (ret); + goto out; + + case MODIFY_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + op0_lval = true; + /* FALLTHRU */ + case COMPOUND_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case POINTER_PLUS_EXPR: + case POINTER_DIFF_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case TRUNC_MOD_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + case COMPLEX_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case UNORDERED_EXPR: + case ORDERED_EXPR: + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + case MEM_REF: + /* Binary operations evaluating both arguments (increment and + decrement are binary internally in GCC). */ + orig_op0 = op0 = TREE_OPERAND (expr, 0); + orig_op1 = op1 = TREE_OPERAND (expr, 1); + op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, + maybe_const_itself, for_int_const, + op0_lval); + STRIP_TYPE_NOPS (op0); + /* The RHS of a MODIFY_EXPR was fully folded when building that + expression for the sake of conversion warnings. */ + if (code != MODIFY_EXPR) + op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, + maybe_const_itself, for_int_const, false); + STRIP_TYPE_NOPS (op1); + + if (for_int_const && (TREE_CODE (op0) != INTEGER_CST + || TREE_CODE (op1) != INTEGER_CST)) + goto out; + + if (op0 != orig_op0 || op1 != orig_op1 || in_init) + ret = in_init + ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1) + : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1); + else + ret = fold (expr); + if (TREE_OVERFLOW_P (ret) + && !TREE_OVERFLOW_P (op0) + && !(BINARY_CLASS_P (op0) && TREE_OVERFLOW_P (TREE_OPERAND (op0, 1))) + && !TREE_OVERFLOW_P (op1)) + overflow_warning (EXPR_LOC_OR_LOC (expr, input_location), ret, expr); + if (code == LSHIFT_EXPR + && TREE_CODE (orig_op0) != INTEGER_CST + && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE + && TREE_CODE (op0) == INTEGER_CST + && c_inhibit_evaluation_warnings == 0 + && tree_int_cst_sgn (op0) < 0) + warning_at (loc, OPT_Wshift_negative_value, + "left shift of negative value"); + if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR) + && TREE_CODE (orig_op1) != INTEGER_CST + && TREE_CODE (op1) == INTEGER_CST + && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE + && c_inhibit_evaluation_warnings == 0) + { + if (tree_int_cst_sgn (op1) < 0) + warning_at (loc, OPT_Wshift_count_negative, + (code == LSHIFT_EXPR + ? G_("left shift count is negative") + : G_("right shift count is negative"))); + else if ((TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE + || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE) + && compare_tree_int (op1, + TYPE_PRECISION (TREE_TYPE (orig_op0))) + >= 0) + warning_at (loc, OPT_Wshift_count_overflow, + (code == LSHIFT_EXPR + ? G_("left shift count >= width of type") + : G_("right shift count >= width of type"))); + else if (TREE_CODE (TREE_TYPE (orig_op0)) == VECTOR_TYPE + && compare_tree_int (op1, + TYPE_PRECISION (TREE_TYPE (TREE_TYPE (orig_op0)))) + >= 0) + warning_at (loc, OPT_Wshift_count_overflow, + code == LSHIFT_EXPR + ? G_("left shift count >= width of vector element") + : G_("right shift count >= width of vector element")); + } + if (code == LSHIFT_EXPR + /* If either OP0 has been folded to INTEGER_CST... */ + && ((TREE_CODE (orig_op0) != INTEGER_CST + && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE + && TREE_CODE (op0) == INTEGER_CST) + /* ...or if OP1 has been folded to INTEGER_CST... */ + || (TREE_CODE (orig_op1) != INTEGER_CST + && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE + && TREE_CODE (op1) == INTEGER_CST)) + && c_inhibit_evaluation_warnings == 0) + /* ...then maybe we can detect an overflow. */ + maybe_warn_shift_overflow (loc, op0, op1); + if ((code == TRUNC_DIV_EXPR + || code == CEIL_DIV_EXPR + || code == FLOOR_DIV_EXPR + || code == EXACT_DIV_EXPR + || code == TRUNC_MOD_EXPR) + && TREE_CODE (orig_op1) != INTEGER_CST + && TREE_CODE (op1) == INTEGER_CST + && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE + || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE) + && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE) + warn_for_div_by_zero (loc, op1); + if (code == MEM_REF + && ret != expr + && TREE_CODE (ret) == MEM_REF) + { + TREE_READONLY (ret) = TREE_READONLY (expr); + TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); + TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); + } + goto out; + + case ADDR_EXPR: + op0_lval = true; + goto unary; + case REALPART_EXPR: + case IMAGPART_EXPR: + case VIEW_CONVERT_EXPR: + op0_lval = lval; + /* FALLTHRU */ + case INDIRECT_REF: + case FIX_TRUNC_EXPR: + case FLOAT_EXPR: + CASE_CONVERT: + case ADDR_SPACE_CONVERT_EXPR: + case NON_LVALUE_EXPR: + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case CONJ_EXPR: + unary: + /* Unary operations. */ + orig_op0 = op0 = TREE_OPERAND (expr, 0); + op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, + maybe_const_itself, for_int_const, + op0_lval); + STRIP_TYPE_NOPS (op0); + + if (for_int_const && TREE_CODE (op0) != INTEGER_CST) + goto out; + + /* ??? Cope with user tricks that amount to offsetof. The middle-end is + not prepared to deal with them if they occur in initializers. */ + if (op0 != orig_op0 + && code == ADDR_EXPR + && (op1 = get_base_address (op0)) != NULL_TREE + && INDIRECT_REF_P (op1) + && TREE_CONSTANT (TREE_OPERAND (op1, 0))) + ret = fold_offsetof (op0, TREE_TYPE (expr)); + else if (op0 != orig_op0 || in_init) + ret = in_init + ? fold_build1_initializer_loc (loc, code, TREE_TYPE (expr), op0) + : fold_build1_loc (loc, code, TREE_TYPE (expr), op0); + else + ret = fold (expr); + if (code == INDIRECT_REF + && ret != expr + && INDIRECT_REF_P (ret)) + { + TREE_READONLY (ret) = TREE_READONLY (expr); + TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); + TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); + } + switch (code) + { + case FIX_TRUNC_EXPR: + case FLOAT_EXPR: + CASE_CONVERT: + /* Don't warn about explicit conversions. We will already + have warned about suspect implicit conversions. */ + break; + + default: + if (TREE_OVERFLOW_P (ret) && !TREE_OVERFLOW_P (op0)) + overflow_warning (EXPR_LOCATION (expr), ret, op0); + break; + } + goto out; + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + /* Binary operations not necessarily evaluating both + arguments. */ + orig_op0 = op0 = TREE_OPERAND (expr, 0); + orig_op1 = op1 = TREE_OPERAND (expr, 1); + op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self, + for_int_const, false); + STRIP_TYPE_NOPS (op0); + + unused_p = (op0 == (code == TRUTH_ANDIF_EXPR + ? truthvalue_false_node + : truthvalue_true_node)); + c_disable_warnings (unused_p); + op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self, + for_int_const, false); + STRIP_TYPE_NOPS (op1); + c_enable_warnings (unused_p); + + if (for_int_const + && (TREE_CODE (op0) != INTEGER_CST + /* Require OP1 be an INTEGER_CST only if it's evaluated. */ + || (!unused_p && TREE_CODE (op1) != INTEGER_CST))) + goto out; + + if (op0 != orig_op0 || op1 != orig_op1 || in_init) + ret = in_init + ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1) + : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1); + else + ret = fold (expr); + *maybe_const_operands &= op0_const; + *maybe_const_itself &= op0_const_self; + if (!(flag_isoc99 + && op0_const + && op0_const_self + && (code == TRUTH_ANDIF_EXPR + ? op0 == truthvalue_false_node + : op0 == truthvalue_true_node))) + *maybe_const_operands &= op1_const; + if (!(op0_const + && op0_const_self + && (code == TRUTH_ANDIF_EXPR + ? op0 == truthvalue_false_node + : op0 == truthvalue_true_node))) + *maybe_const_itself &= op1_const_self; + goto out; + + case COND_EXPR: + orig_op0 = op0 = TREE_OPERAND (expr, 0); + orig_op1 = op1 = TREE_OPERAND (expr, 1); + orig_op2 = op2 = TREE_OPERAND (expr, 2); + op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self, + for_int_const, false); + + STRIP_TYPE_NOPS (op0); + c_disable_warnings (op0 == truthvalue_false_node); + op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self, + for_int_const, false); + STRIP_TYPE_NOPS (op1); + c_enable_warnings (op0 == truthvalue_false_node); + + c_disable_warnings (op0 == truthvalue_true_node); + op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self, + for_int_const, false); + STRIP_TYPE_NOPS (op2); + c_enable_warnings (op0 == truthvalue_true_node); + + if (for_int_const + && (TREE_CODE (op0) != INTEGER_CST + /* Only the evaluated operand must be an INTEGER_CST. */ + || (op0 == truthvalue_true_node + ? TREE_CODE (op1) != INTEGER_CST + : TREE_CODE (op2) != INTEGER_CST))) + goto out; + + if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2) + ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2); + else + ret = fold (expr); + *maybe_const_operands &= op0_const; + *maybe_const_itself &= op0_const_self; + if (!(flag_isoc99 + && op0_const + && op0_const_self + && op0 == truthvalue_false_node)) + *maybe_const_operands &= op1_const; + if (!(op0_const + && op0_const_self + && op0 == truthvalue_false_node)) + *maybe_const_itself &= op1_const_self; + if (!(flag_isoc99 + && op0_const + && op0_const_self + && op0 == truthvalue_true_node)) + *maybe_const_operands &= op2_const; + if (!(op0_const + && op0_const_self + && op0 == truthvalue_true_node)) + *maybe_const_itself &= op2_const_self; + goto out; + + case VEC_COND_EXPR: + orig_op0 = op0 = TREE_OPERAND (expr, 0); + orig_op1 = op1 = TREE_OPERAND (expr, 1); + orig_op2 = op2 = TREE_OPERAND (expr, 2); + op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, + maybe_const_itself, for_int_const, false); + STRIP_TYPE_NOPS (op0); + op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, + maybe_const_itself, for_int_const, false); + STRIP_TYPE_NOPS (op1); + op2 = c_fully_fold_internal (op2, in_init, maybe_const_operands, + maybe_const_itself, for_int_const, false); + STRIP_TYPE_NOPS (op2); + + if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2) + ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2); + else + ret = fold (expr); + goto out; + + case EXCESS_PRECISION_EXPR: + /* Each case where an operand with excess precision may be + encountered must remove the EXCESS_PRECISION_EXPR around + inner operands and possibly put one around the whole + expression or possibly convert to the semantic type (which + c_fully_fold does); we cannot tell at this stage which is + appropriate in any particular case. */ + gcc_unreachable (); + + case SAVE_EXPR: + /* Make sure to fold the contents of a SAVE_EXPR exactly once. */ + op0 = TREE_OPERAND (expr, 0); + if (!SAVE_EXPR_FOLDED_P (expr)) + { + op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, + maybe_const_itself, for_int_const, + false); + TREE_OPERAND (expr, 0) = op0; + SAVE_EXPR_FOLDED_P (expr) = true; + } + /* Return the SAVE_EXPR operand if it is invariant. */ + if (tree_invariant_p (op0)) + ret = op0; + goto out; + + default: + /* Various codes may appear through folding built-in functions + and their arguments. */ + goto out; + } + + out: + /* Some folding may introduce NON_LVALUE_EXPRs; all lvalue checks + have been done by this point, so remove them again. */ + nowarning |= warning_suppressed_p (ret, OPT_Woverflow); + STRIP_TYPE_NOPS (ret); + if (nowarning && !warning_suppressed_p (ret, OPT_Woverflow)) + { + if (!CAN_HAVE_LOCATION_P (ret)) + ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret); + suppress_warning (ret, OPT_Woverflow); + } + if (ret != expr) + { + protected_set_expr_location (ret, loc); + if (IS_EXPR_CODE_CLASS (kind)) + set_source_range (ret, old_range.m_start, old_range.m_finish); + } + return ret; +} + +/* Fold X for consideration by one of the warning functions when checking + whether an expression has a constant value. */ + +tree +fold_for_warn (tree x) +{ + /* The C front-end has already folded X appropriately. */ + return x; +} diff --git a/gcc/c/c-lang.c b/gcc/c/c-lang.c deleted file mode 100644 index eecc0a0..0000000 --- a/gcc/c/c-lang.c +++ /dev/null @@ -1,72 +0,0 @@ -/* Language-specific hook definitions for C front end. - Copyright (C) 1991-2022 Free Software Foundation, Inc. - -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 -. */ - - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "c-tree.h" -#include "langhooks.h" -#include "langhooks-def.h" -#include "c-objc-common.h" - -enum c_language_kind c_language = clk_c; - -/* Lang hooks common to C and ObjC are declared in c-objc-common.h; - consequently, there should be very few hooks below. */ - -#undef LANG_HOOKS_NAME -#define LANG_HOOKS_NAME "GNU C" -#undef LANG_HOOKS_INIT -#define LANG_HOOKS_INIT c_objc_common_init -#undef LANG_HOOKS_INIT_TS -#define LANG_HOOKS_INIT_TS c_common_init_ts - -#if CHECKING_P -#undef LANG_HOOKS_RUN_LANG_SELFTESTS -#define LANG_HOOKS_RUN_LANG_SELFTESTS selftest::run_c_tests -#endif /* #if CHECKING_P */ - -#undef LANG_HOOKS_GET_SUBSTRING_LOCATION -#define LANG_HOOKS_GET_SUBSTRING_LOCATION c_get_substring_location - -/* Each front end provides its own lang hook initializer. */ -struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; - -#if CHECKING_P - -namespace selftest { - -/* Implementation of LANG_HOOKS_RUN_LANG_SELFTESTS for the C frontend. */ - -void -run_c_tests (void) -{ - /* Run selftests shared within the C family. */ - c_family_tests (); - - /* Additional C-specific tests. */ -} - -} // namespace selftest - -#endif /* #if CHECKING_P */ - - -#include "gtype-c.h" diff --git a/gcc/c/c-lang.cc b/gcc/c/c-lang.cc new file mode 100644 index 0000000..eecc0a0 --- /dev/null +++ b/gcc/c/c-lang.cc @@ -0,0 +1,72 @@ +/* Language-specific hook definitions for C front end. + Copyright (C) 1991-2022 Free Software Foundation, Inc. + +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 +. */ + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "c-tree.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "c-objc-common.h" + +enum c_language_kind c_language = clk_c; + +/* Lang hooks common to C and ObjC are declared in c-objc-common.h; + consequently, there should be very few hooks below. */ + +#undef LANG_HOOKS_NAME +#define LANG_HOOKS_NAME "GNU C" +#undef LANG_HOOKS_INIT +#define LANG_HOOKS_INIT c_objc_common_init +#undef LANG_HOOKS_INIT_TS +#define LANG_HOOKS_INIT_TS c_common_init_ts + +#if CHECKING_P +#undef LANG_HOOKS_RUN_LANG_SELFTESTS +#define LANG_HOOKS_RUN_LANG_SELFTESTS selftest::run_c_tests +#endif /* #if CHECKING_P */ + +#undef LANG_HOOKS_GET_SUBSTRING_LOCATION +#define LANG_HOOKS_GET_SUBSTRING_LOCATION c_get_substring_location + +/* Each front end provides its own lang hook initializer. */ +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +#if CHECKING_P + +namespace selftest { + +/* Implementation of LANG_HOOKS_RUN_LANG_SELFTESTS for the C frontend. */ + +void +run_c_tests (void) +{ + /* Run selftests shared within the C family. */ + c_family_tests (); + + /* Additional C-specific tests. */ +} + +} // namespace selftest + +#endif /* #if CHECKING_P */ + + +#include "gtype-c.h" diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c deleted file mode 100644 index 97850ad..0000000 --- a/gcc/c/c-objc-common.c +++ /dev/null @@ -1,396 +0,0 @@ -/* Some code common to C and ObjC front ends. - Copyright (C) 2001-2022 Free Software Foundation, Inc. - -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 -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "c-tree.h" -#include "intl.h" -#include "c-family/c-pretty-print.h" -#include "tree-pretty-print.h" -#include "gimple-pretty-print.h" -#include "langhooks.h" -#include "c-objc-common.h" -#include "gcc-rich-location.h" -#include "stringpool.h" -#include "attribs.h" - -static bool c_tree_printer (pretty_printer *, text_info *, const char *, - int, bool, bool, bool, bool *, const char **); - -bool -c_missing_noreturn_ok_p (tree decl) -{ - /* A missing noreturn is not ok for freestanding implementations and - ok for the `main' function in hosted implementations. */ - return flag_hosted && MAIN_NAME_P (DECL_ASSEMBLER_NAME (decl)); -} - -/* Called from check_global_declaration. */ - -bool -c_warn_unused_global_decl (const_tree decl) -{ - if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)) - return false; - if (DECL_IN_SYSTEM_HEADER (decl)) - return false; - - return true; -} - -/* Initialization common to C and Objective-C front ends. */ -bool -c_objc_common_init (void) -{ - c_init_decl_processing (); - - return c_common_init (); -} - -/* Decide whether it's worth saying that TYPE is also known as some other - type. Return the other type if so, otherwise return TYPE. */ - -static tree -get_aka_type (tree type) -{ - if (type == error_mark_node) - return type; - - tree result; - if (typedef_variant_p (type)) - { - /* Saying that "foo" is also known as "struct foo" or - "struct " is unlikely to be useful, since users of - structure-like types would already know that they're structures. - The same applies to unions and enums; in general, printing the - tag is only useful if it has a different name. */ - tree orig_type = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); - tree_code code = TREE_CODE (orig_type); - tree orig_id = TYPE_IDENTIFIER (orig_type); - if ((code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) - && (!orig_id || TYPE_IDENTIFIER (type) == orig_id)) - return type; - - if (!user_facing_original_type_p (type)) - return type; - - result = get_aka_type (orig_type); - } - else - { - tree canonical = TYPE_CANONICAL (type); - if (canonical && TREE_CODE (type) != TREE_CODE (canonical)) - return canonical; - - /* Recursive calls might choose a middle ground between TYPE - (which has no typedefs stripped) and CANONICAL (which has - all typedefs stripped). So try to reuse TYPE or CANONICAL if - convenient, but be prepared to create a new type if necessary. */ - switch (TREE_CODE (type)) - { - case POINTER_TYPE: - case REFERENCE_TYPE: - { - tree target_type = get_aka_type (TREE_TYPE (type)); - - if (target_type == TREE_TYPE (type)) - return type; - - if (canonical && target_type == TREE_TYPE (canonical)) - return canonical; - - result = (TREE_CODE (type) == POINTER_TYPE - ? build_pointer_type (target_type) - : build_reference_type (target_type)); - break; - } - - case ARRAY_TYPE: - { - tree element_type = get_aka_type (TREE_TYPE (type)); - tree index_type = (TYPE_DOMAIN (type) - ? get_aka_type (TYPE_DOMAIN (type)) - : NULL_TREE); - - if (element_type == TREE_TYPE (type) - && index_type == TYPE_DOMAIN (type)) - return type; - - if (canonical - && element_type == TREE_TYPE (canonical) - && index_type == TYPE_DOMAIN (canonical)) - return canonical; - - result = build_array_type (element_type, index_type, - TYPE_TYPELESS_STORAGE (type)); - break; - } - - case FUNCTION_TYPE: - { - tree return_type = get_aka_type (TREE_TYPE (type)); - - tree args = TYPE_ARG_TYPES (type); - if (args == error_mark_node) - return type; - - auto_vec arg_types; - bool type_ok_p = true; - while (args && args != void_list_node) - { - tree arg_type = get_aka_type (TREE_VALUE (args)); - arg_types.safe_push (arg_type); - type_ok_p &= (arg_type == TREE_VALUE (args)); - args = TREE_CHAIN (args); - } - - if (type_ok_p && return_type == TREE_TYPE (type)) - return type; - - unsigned int i; - tree arg_type; - FOR_EACH_VEC_ELT_REVERSE (arg_types, i, arg_type) - args = tree_cons (NULL_TREE, arg_type, args); - result = build_function_type (return_type, args); - break; - } - - default: - return canonical ? canonical : type; - } - } - return build_type_attribute_qual_variant (result, TYPE_ATTRIBUTES (type), - TYPE_QUALS (type)); -} - -/* Print T to CPP. */ - -static void -print_type (c_pretty_printer *cpp, tree t, bool *quoted) -{ - if (t == error_mark_node) - { - pp_string (cpp, _("{erroneous}")); - return; - } - - gcc_assert (TYPE_P (t)); - struct obstack *ob = pp_buffer (cpp)->obstack; - char *p = (char *) obstack_base (ob); - /* Remember the end of the initial dump. */ - int len = obstack_object_size (ob); - - tree name = TYPE_NAME (t); - if (name && TREE_CODE (name) == TYPE_DECL && DECL_NAME (name)) - pp_identifier (cpp, lang_hooks.decl_printable_name (name, 2)); - else - cpp->type_id (t); - - /* If we're printing a type that involves typedefs, also print the - stripped version. But sometimes the stripped version looks - exactly the same, so we don't want it after all. To avoid - printing it in that case, we play ugly obstack games. */ - tree aka_type = get_aka_type (t); - if (aka_type != t) - { - c_pretty_printer cpp2; - /* Print the stripped version into a temporary printer. */ - cpp2.type_id (aka_type); - struct obstack *ob2 = cpp2.buffer->obstack; - /* Get the stripped version from the temporary printer. */ - const char *aka = (char *) obstack_base (ob2); - int aka_len = obstack_object_size (ob2); - int type1_len = obstack_object_size (ob) - len; - - /* If they are identical, bail out. */ - if (aka_len == type1_len && memcmp (p + len, aka, aka_len) == 0) - return; - - /* They're not, print the stripped version now. */ - if (*quoted) - pp_end_quote (cpp, pp_show_color (cpp)); - pp_c_whitespace (cpp); - pp_left_brace (cpp); - pp_c_ws_string (cpp, _("aka")); - pp_c_whitespace (cpp); - if (*quoted) - pp_begin_quote (cpp, pp_show_color (cpp)); - cpp->type_id (aka_type); - if (*quoted) - pp_end_quote (cpp, pp_show_color (cpp)); - pp_right_brace (cpp); - /* No further closing quotes are needed. */ - *quoted = false; - } -} - -/* Called during diagnostic message formatting process to print a - source-level entity onto BUFFER. The meaning of the format specifiers - is as follows: - %D: a general decl, - %E: an identifier or expression, - %F: a function declaration, - %T: a type. - %V: a list of type qualifiers from a tree. - %v: an explicit list of type qualifiers - %#v: an explicit list of type qualifiers of a function type. - - Please notice when called, the `%' part was already skipped by the - diagnostic machinery. */ -static bool -c_tree_printer (pretty_printer *pp, text_info *text, const char *spec, - int precision, bool wide, bool set_locus, bool hash, - bool *quoted, const char **) -{ - tree t = NULL_TREE; - // FIXME: the next cast should be a dynamic_cast, when it is permitted. - c_pretty_printer *cpp = (c_pretty_printer *) pp; - pp->padding = pp_none; - - if (precision != 0 || wide) - return false; - - if (*spec != 'v') - { - t = va_arg (*text->args_ptr, tree); - if (set_locus) - text->set_location (0, DECL_SOURCE_LOCATION (t), - SHOW_RANGE_WITH_CARET); - } - - switch (*spec) - { - case 'D': - if (VAR_P (t) && DECL_HAS_DEBUG_EXPR_P (t)) - { - t = DECL_DEBUG_EXPR (t); - if (!DECL_P (t)) - { - cpp->expression (t); - return true; - } - } - /* FALLTHRU */ - - case 'F': - if (DECL_NAME (t)) - { - pp_identifier (cpp, lang_hooks.decl_printable_name (t, 2)); - return true; - } - break; - - case 'T': - print_type (cpp, t, quoted); - return true; - - case 'E': - if (TREE_CODE (t) == IDENTIFIER_NODE) - pp_identifier (cpp, IDENTIFIER_POINTER (t)); - else - cpp->expression (t); - return true; - - case 'V': - pp_c_type_qualifier_list (cpp, t); - return true; - - case 'v': - pp_c_cv_qualifiers (cpp, va_arg (*text->args_ptr, int), hash); - return true; - - default: - return false; - } - - pp_string (cpp, _("({anonymous})")); - return true; -} - -/* C-specific implementation of range_label::get_text () vfunc for - range_label_for_type_mismatch. */ - -label_text -range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const -{ - if (m_labelled_type == NULL_TREE) - return label_text::borrow (NULL); - - c_pretty_printer cpp; - bool quoted = false; - print_type (&cpp, m_labelled_type, "ed); - return label_text::take (xstrdup (pp_formatted_text (&cpp))); -} - - -/* In C and ObjC, all decls have "C" linkage. */ -bool -has_c_linkage (const_tree decl ATTRIBUTE_UNUSED) -{ - return true; -} - -void -c_initialize_diagnostics (diagnostic_context *context) -{ - pretty_printer *base = context->printer; - c_pretty_printer *pp = XNEW (c_pretty_printer); - context->printer = new (pp) c_pretty_printer (); - - /* It is safe to free this object because it was previously XNEW()'d. */ - base->~pretty_printer (); - XDELETE (base); - - c_common_diagnostics_set_defaults (context); - diagnostic_format_decoder (context) = &c_tree_printer; -} - -int -c_types_compatible_p (tree x, tree y) -{ - return comptypes (TYPE_MAIN_VARIANT (x), TYPE_MAIN_VARIANT (y)); -} - -/* Determine if the type is a vla type for the backend. */ - -bool -c_vla_unspec_p (tree x, tree fn ATTRIBUTE_UNUSED) -{ - return c_vla_type_p (x); -} - -/* Special routine to get the alias set of T for C. */ - -alias_set_type -c_get_alias_set (tree t) -{ - /* Allow aliasing between enumeral types and the underlying - integer type. This is required since those are compatible types. */ - if (TREE_CODE (t) == ENUMERAL_TYPE) - { - tree t1 = c_common_type_for_size (tree_to_uhwi (TYPE_SIZE (t)), - /* short-cut commoning to signed - type. */ - false); - return get_alias_set (t1); - } - - return c_common_get_alias_set (t); -} diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc new file mode 100644 index 0000000..97850ad --- /dev/null +++ b/gcc/c/c-objc-common.cc @@ -0,0 +1,396 @@ +/* Some code common to C and ObjC front ends. + Copyright (C) 2001-2022 Free Software Foundation, Inc. + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "c-tree.h" +#include "intl.h" +#include "c-family/c-pretty-print.h" +#include "tree-pretty-print.h" +#include "gimple-pretty-print.h" +#include "langhooks.h" +#include "c-objc-common.h" +#include "gcc-rich-location.h" +#include "stringpool.h" +#include "attribs.h" + +static bool c_tree_printer (pretty_printer *, text_info *, const char *, + int, bool, bool, bool, bool *, const char **); + +bool +c_missing_noreturn_ok_p (tree decl) +{ + /* A missing noreturn is not ok for freestanding implementations and + ok for the `main' function in hosted implementations. */ + return flag_hosted && MAIN_NAME_P (DECL_ASSEMBLER_NAME (decl)); +} + +/* Called from check_global_declaration. */ + +bool +c_warn_unused_global_decl (const_tree decl) +{ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)) + return false; + if (DECL_IN_SYSTEM_HEADER (decl)) + return false; + + return true; +} + +/* Initialization common to C and Objective-C front ends. */ +bool +c_objc_common_init (void) +{ + c_init_decl_processing (); + + return c_common_init (); +} + +/* Decide whether it's worth saying that TYPE is also known as some other + type. Return the other type if so, otherwise return TYPE. */ + +static tree +get_aka_type (tree type) +{ + if (type == error_mark_node) + return type; + + tree result; + if (typedef_variant_p (type)) + { + /* Saying that "foo" is also known as "struct foo" or + "struct " is unlikely to be useful, since users of + structure-like types would already know that they're structures. + The same applies to unions and enums; in general, printing the + tag is only useful if it has a different name. */ + tree orig_type = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); + tree_code code = TREE_CODE (orig_type); + tree orig_id = TYPE_IDENTIFIER (orig_type); + if ((code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) + && (!orig_id || TYPE_IDENTIFIER (type) == orig_id)) + return type; + + if (!user_facing_original_type_p (type)) + return type; + + result = get_aka_type (orig_type); + } + else + { + tree canonical = TYPE_CANONICAL (type); + if (canonical && TREE_CODE (type) != TREE_CODE (canonical)) + return canonical; + + /* Recursive calls might choose a middle ground between TYPE + (which has no typedefs stripped) and CANONICAL (which has + all typedefs stripped). So try to reuse TYPE or CANONICAL if + convenient, but be prepared to create a new type if necessary. */ + switch (TREE_CODE (type)) + { + case POINTER_TYPE: + case REFERENCE_TYPE: + { + tree target_type = get_aka_type (TREE_TYPE (type)); + + if (target_type == TREE_TYPE (type)) + return type; + + if (canonical && target_type == TREE_TYPE (canonical)) + return canonical; + + result = (TREE_CODE (type) == POINTER_TYPE + ? build_pointer_type (target_type) + : build_reference_type (target_type)); + break; + } + + case ARRAY_TYPE: + { + tree element_type = get_aka_type (TREE_TYPE (type)); + tree index_type = (TYPE_DOMAIN (type) + ? get_aka_type (TYPE_DOMAIN (type)) + : NULL_TREE); + + if (element_type == TREE_TYPE (type) + && index_type == TYPE_DOMAIN (type)) + return type; + + if (canonical + && element_type == TREE_TYPE (canonical) + && index_type == TYPE_DOMAIN (canonical)) + return canonical; + + result = build_array_type (element_type, index_type, + TYPE_TYPELESS_STORAGE (type)); + break; + } + + case FUNCTION_TYPE: + { + tree return_type = get_aka_type (TREE_TYPE (type)); + + tree args = TYPE_ARG_TYPES (type); + if (args == error_mark_node) + return type; + + auto_vec arg_types; + bool type_ok_p = true; + while (args && args != void_list_node) + { + tree arg_type = get_aka_type (TREE_VALUE (args)); + arg_types.safe_push (arg_type); + type_ok_p &= (arg_type == TREE_VALUE (args)); + args = TREE_CHAIN (args); + } + + if (type_ok_p && return_type == TREE_TYPE (type)) + return type; + + unsigned int i; + tree arg_type; + FOR_EACH_VEC_ELT_REVERSE (arg_types, i, arg_type) + args = tree_cons (NULL_TREE, arg_type, args); + result = build_function_type (return_type, args); + break; + } + + default: + return canonical ? canonical : type; + } + } + return build_type_attribute_qual_variant (result, TYPE_ATTRIBUTES (type), + TYPE_QUALS (type)); +} + +/* Print T to CPP. */ + +static void +print_type (c_pretty_printer *cpp, tree t, bool *quoted) +{ + if (t == error_mark_node) + { + pp_string (cpp, _("{erroneous}")); + return; + } + + gcc_assert (TYPE_P (t)); + struct obstack *ob = pp_buffer (cpp)->obstack; + char *p = (char *) obstack_base (ob); + /* Remember the end of the initial dump. */ + int len = obstack_object_size (ob); + + tree name = TYPE_NAME (t); + if (name && TREE_CODE (name) == TYPE_DECL && DECL_NAME (name)) + pp_identifier (cpp, lang_hooks.decl_printable_name (name, 2)); + else + cpp->type_id (t); + + /* If we're printing a type that involves typedefs, also print the + stripped version. But sometimes the stripped version looks + exactly the same, so we don't want it after all. To avoid + printing it in that case, we play ugly obstack games. */ + tree aka_type = get_aka_type (t); + if (aka_type != t) + { + c_pretty_printer cpp2; + /* Print the stripped version into a temporary printer. */ + cpp2.type_id (aka_type); + struct obstack *ob2 = cpp2.buffer->obstack; + /* Get the stripped version from the temporary printer. */ + const char *aka = (char *) obstack_base (ob2); + int aka_len = obstack_object_size (ob2); + int type1_len = obstack_object_size (ob) - len; + + /* If they are identical, bail out. */ + if (aka_len == type1_len && memcmp (p + len, aka, aka_len) == 0) + return; + + /* They're not, print the stripped version now. */ + if (*quoted) + pp_end_quote (cpp, pp_show_color (cpp)); + pp_c_whitespace (cpp); + pp_left_brace (cpp); + pp_c_ws_string (cpp, _("aka")); + pp_c_whitespace (cpp); + if (*quoted) + pp_begin_quote (cpp, pp_show_color (cpp)); + cpp->type_id (aka_type); + if (*quoted) + pp_end_quote (cpp, pp_show_color (cpp)); + pp_right_brace (cpp); + /* No further closing quotes are needed. */ + *quoted = false; + } +} + +/* Called during diagnostic message formatting process to print a + source-level entity onto BUFFER. The meaning of the format specifiers + is as follows: + %D: a general decl, + %E: an identifier or expression, + %F: a function declaration, + %T: a type. + %V: a list of type qualifiers from a tree. + %v: an explicit list of type qualifiers + %#v: an explicit list of type qualifiers of a function type. + + Please notice when called, the `%' part was already skipped by the + diagnostic machinery. */ +static bool +c_tree_printer (pretty_printer *pp, text_info *text, const char *spec, + int precision, bool wide, bool set_locus, bool hash, + bool *quoted, const char **) +{ + tree t = NULL_TREE; + // FIXME: the next cast should be a dynamic_cast, when it is permitted. + c_pretty_printer *cpp = (c_pretty_printer *) pp; + pp->padding = pp_none; + + if (precision != 0 || wide) + return false; + + if (*spec != 'v') + { + t = va_arg (*text->args_ptr, tree); + if (set_locus) + text->set_location (0, DECL_SOURCE_LOCATION (t), + SHOW_RANGE_WITH_CARET); + } + + switch (*spec) + { + case 'D': + if (VAR_P (t) && DECL_HAS_DEBUG_EXPR_P (t)) + { + t = DECL_DEBUG_EXPR (t); + if (!DECL_P (t)) + { + cpp->expression (t); + return true; + } + } + /* FALLTHRU */ + + case 'F': + if (DECL_NAME (t)) + { + pp_identifier (cpp, lang_hooks.decl_printable_name (t, 2)); + return true; + } + break; + + case 'T': + print_type (cpp, t, quoted); + return true; + + case 'E': + if (TREE_CODE (t) == IDENTIFIER_NODE) + pp_identifier (cpp, IDENTIFIER_POINTER (t)); + else + cpp->expression (t); + return true; + + case 'V': + pp_c_type_qualifier_list (cpp, t); + return true; + + case 'v': + pp_c_cv_qualifiers (cpp, va_arg (*text->args_ptr, int), hash); + return true; + + default: + return false; + } + + pp_string (cpp, _("({anonymous})")); + return true; +} + +/* C-specific implementation of range_label::get_text () vfunc for + range_label_for_type_mismatch. */ + +label_text +range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const +{ + if (m_labelled_type == NULL_TREE) + return label_text::borrow (NULL); + + c_pretty_printer cpp; + bool quoted = false; + print_type (&cpp, m_labelled_type, "ed); + return label_text::take (xstrdup (pp_formatted_text (&cpp))); +} + + +/* In C and ObjC, all decls have "C" linkage. */ +bool +has_c_linkage (const_tree decl ATTRIBUTE_UNUSED) +{ + return true; +} + +void +c_initialize_diagnostics (diagnostic_context *context) +{ + pretty_printer *base = context->printer; + c_pretty_printer *pp = XNEW (c_pretty_printer); + context->printer = new (pp) c_pretty_printer (); + + /* It is safe to free this object because it was previously XNEW()'d. */ + base->~pretty_printer (); + XDELETE (base); + + c_common_diagnostics_set_defaults (context); + diagnostic_format_decoder (context) = &c_tree_printer; +} + +int +c_types_compatible_p (tree x, tree y) +{ + return comptypes (TYPE_MAIN_VARIANT (x), TYPE_MAIN_VARIANT (y)); +} + +/* Determine if the type is a vla type for the backend. */ + +bool +c_vla_unspec_p (tree x, tree fn ATTRIBUTE_UNUSED) +{ + return c_vla_type_p (x); +} + +/* Special routine to get the alias set of T for C. */ + +alias_set_type +c_get_alias_set (tree t) +{ + /* Allow aliasing between enumeral types and the underlying + integer type. This is required since those are compatible types. */ + if (TREE_CODE (t) == ENUMERAL_TYPE) + { + tree t1 = c_common_type_for_size (tree_to_uhwi (TYPE_SIZE (t)), + /* short-cut commoning to signed + type. */ + false); + return get_alias_set (t1); + } + + return c_common_get_alias_set (t); +} diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c deleted file mode 100644 index 20774f7..0000000 --- a/gcc/c/c-parser.c +++ /dev/null @@ -1,23404 +0,0 @@ -/* Parser for C and Objective-C. - Copyright (C) 1987-2022 Free Software Foundation, Inc. - - Parser actions based on the old Bison parser; structure somewhat - influenced by and fragments based on the C++ parser. - -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 -. */ - -/* TODO: - - Make sure all relevant comments, and all relevant code from all - actions, brought over from old parser. Verify exact correspondence - of syntax accepted. - - Add testcases covering every input symbol in every state in old and - new parsers. - - Include full syntax for GNU C, including erroneous cases accepted - with error messages, in syntax productions in comments. - - Make more diagnostics in the front end generally take an explicit - location rather than implicitly using input_location. */ - -#include "config.h" -#define INCLUDE_MEMORY -#include "system.h" -#include "coretypes.h" -#include "target.h" -#include "function.h" -#include "c-tree.h" -#include "timevar.h" -#include "stringpool.h" -#include "cgraph.h" -#include "attribs.h" -#include "stor-layout.h" -#include "varasm.h" -#include "trans-mem.h" -#include "c-family/c-pragma.h" -#include "c-lang.h" -#include "c-family/c-objc.h" -#include "plugin.h" -#include "omp-general.h" -#include "omp-offload.h" -#include "builtins.h" -#include "gomp-constants.h" -#include "c-family/c-indentation.h" -#include "gimple-expr.h" -#include "context.h" -#include "gcc-rich-location.h" -#include "c-parser.h" -#include "gimple-parser.h" -#include "read-rtl-function.h" -#include "run-rtl-passes.h" -#include "intl.h" -#include "c-family/name-hint.h" -#include "tree-iterator.h" -#include "tree-pretty-print.h" -#include "memmodel.h" -#include "c-family/known-headers.h" - -/* We need to walk over decls with incomplete struct/union/enum types - after parsing the whole translation unit. - In finish_decl(), if the decl is static, has incomplete - struct/union/enum type, it is appended to incomplete_record_decls. - In c_parser_translation_unit(), we iterate over incomplete_record_decls - and report error if any of the decls are still incomplete. */ - -vec incomplete_record_decls; - -void -set_c_expr_source_range (c_expr *expr, - location_t start, location_t finish) -{ - expr->src_range.m_start = start; - expr->src_range.m_finish = finish; - if (expr->value) - set_source_range (expr->value, start, finish); -} - -void -set_c_expr_source_range (c_expr *expr, - source_range src_range) -{ - expr->src_range = src_range; - if (expr->value) - set_source_range (expr->value, src_range); -} - - -/* Initialization routine for this file. */ - -void -c_parse_init (void) -{ - /* The only initialization required is of the reserved word - identifiers. */ - unsigned int i; - tree id; - int mask = 0; - - /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in - the c_token structure. */ - gcc_assert (RID_MAX <= 255); - - mask |= D_CXXONLY; - if (!flag_isoc99) - mask |= D_C99; - if (flag_no_asm) - { - mask |= D_ASM | D_EXT; - if (!flag_isoc99) - mask |= D_EXT89; - } - if (!c_dialect_objc ()) - mask |= D_OBJC | D_CXX_OBJC; - - ridpointers = ggc_cleared_vec_alloc ((int) RID_MAX); - for (i = 0; i < num_c_common_reswords; i++) - { - /* If a keyword is disabled, do not enter it into the table - and so create a canonical spelling that isn't a keyword. */ - if (c_common_reswords[i].disable & mask) - { - if (warn_cxx_compat - && (c_common_reswords[i].disable & D_CXXWARN)) - { - id = get_identifier (c_common_reswords[i].word); - C_SET_RID_CODE (id, RID_CXX_COMPAT_WARN); - C_IS_RESERVED_WORD (id) = 1; - } - continue; - } - - id = get_identifier (c_common_reswords[i].word); - C_SET_RID_CODE (id, c_common_reswords[i].rid); - C_IS_RESERVED_WORD (id) = 1; - ridpointers [(int) c_common_reswords[i].rid] = id; - } - - for (i = 0; i < NUM_INT_N_ENTS; i++) - { - /* We always create the symbols but they aren't always supported. */ - char name[50]; - sprintf (name, "__int%d", int_n_data[i].bitsize); - id = get_identifier (name); - C_SET_RID_CODE (id, RID_FIRST_INT_N + i); - C_IS_RESERVED_WORD (id) = 1; - - sprintf (name, "__int%d__", int_n_data[i].bitsize); - id = get_identifier (name); - C_SET_RID_CODE (id, RID_FIRST_INT_N + i); - C_IS_RESERVED_WORD (id) = 1; - } -} - -/* A parser structure recording information about the state and - context of parsing. Includes lexer information with up to two - tokens of look-ahead; more are not needed for C. */ -struct GTY(()) c_parser { - /* The look-ahead tokens. */ - c_token * GTY((skip)) tokens; - /* Buffer for look-ahead tokens. */ - c_token tokens_buf[4]; - /* How many look-ahead tokens are available (0 - 4, or - more if parsing from pre-lexed tokens). */ - unsigned int tokens_avail; - /* Raw look-ahead tokens, used only for checking in Objective-C - whether '[[' starts attributes. */ - vec *raw_tokens; - /* The number of raw look-ahead tokens that have since been fully - lexed. */ - unsigned int raw_tokens_used; - /* True if a syntax error is being recovered from; false otherwise. - c_parser_error sets this flag. It should clear this flag when - enough tokens have been consumed to recover from the error. */ - BOOL_BITFIELD error : 1; - /* True if we're processing a pragma, and shouldn't automatically - consume CPP_PRAGMA_EOL. */ - BOOL_BITFIELD in_pragma : 1; - /* True if we're parsing the outermost block of an if statement. */ - BOOL_BITFIELD in_if_block : 1; - /* True if we want to lex a translated, joined string (for an - initial #pragma pch_preprocess). Otherwise the parser is - responsible for concatenating strings and translating to the - execution character set as needed. */ - BOOL_BITFIELD lex_joined_string : 1; - /* True if, when the parser is concatenating string literals, it - should translate them to the execution character set (false - inside attributes). */ - BOOL_BITFIELD translate_strings_p : 1; - - /* Objective-C specific parser/lexer information. */ - - /* True if we are in a context where the Objective-C "PQ" keywords - are considered keywords. */ - BOOL_BITFIELD objc_pq_context : 1; - /* True if we are parsing a (potential) Objective-C foreach - statement. This is set to true after we parsed 'for (' and while - we wait for 'in' or ';' to decide if it's a standard C for loop or an - Objective-C foreach loop. */ - BOOL_BITFIELD objc_could_be_foreach_context : 1; - /* The following flag is needed to contextualize Objective-C lexical - analysis. In some cases (e.g., 'int NSObject;'), it is - undesirable to bind an identifier to an Objective-C class, even - if a class with that name exists. */ - BOOL_BITFIELD objc_need_raw_identifier : 1; - /* Nonzero if we're processing a __transaction statement. The value - is 1 | TM_STMT_ATTR_*. */ - unsigned int in_transaction : 4; - /* True if we are in a context where the Objective-C "Property attribute" - keywords are valid. */ - BOOL_BITFIELD objc_property_attr_context : 1; - - /* Whether we have just seen/constructed a string-literal. Set when - returning a string-literal from c_parser_string_literal. Reset - in consume_token. Useful when we get a parse error and see an - unknown token, which could have been a string-literal constant - macro. */ - BOOL_BITFIELD seen_string_literal : 1; - - /* Location of the last consumed token. */ - location_t last_token_location; -}; - -/* Return a pointer to the Nth token in PARSERs tokens_buf. */ - -c_token * -c_parser_tokens_buf (c_parser *parser, unsigned n) -{ - return &parser->tokens_buf[n]; -} - -/* Return the error state of PARSER. */ - -bool -c_parser_error (c_parser *parser) -{ - return parser->error; -} - -/* Set the error state of PARSER to ERR. */ - -void -c_parser_set_error (c_parser *parser, bool err) -{ - parser->error = err; -} - - -/* The actual parser and external interface. ??? Does this need to be - garbage-collected? */ - -static GTY (()) c_parser *the_parser; - -/* Read in and lex a single token, storing it in *TOKEN. If RAW, - context-sensitive postprocessing of the token is not done. */ - -static void -c_lex_one_token (c_parser *parser, c_token *token, bool raw = false) -{ - timevar_push (TV_LEX); - - if (raw || vec_safe_length (parser->raw_tokens) == 0) - { - token->type = c_lex_with_flags (&token->value, &token->location, - &token->flags, - (parser->lex_joined_string - ? 0 : C_LEX_STRING_NO_JOIN)); - token->id_kind = C_ID_NONE; - token->keyword = RID_MAX; - token->pragma_kind = PRAGMA_NONE; - } - else - { - /* Use a token previously lexed as a raw look-ahead token, and - complete the processing on it. */ - *token = (*parser->raw_tokens)[parser->raw_tokens_used]; - ++parser->raw_tokens_used; - if (parser->raw_tokens_used == vec_safe_length (parser->raw_tokens)) - { - vec_free (parser->raw_tokens); - parser->raw_tokens_used = 0; - } - } - - if (raw) - goto out; - - switch (token->type) - { - case CPP_NAME: - { - tree decl; - - bool objc_force_identifier = parser->objc_need_raw_identifier; - if (c_dialect_objc ()) - parser->objc_need_raw_identifier = false; - - if (C_IS_RESERVED_WORD (token->value)) - { - enum rid rid_code = C_RID_CODE (token->value); - - if (rid_code == RID_CXX_COMPAT_WARN) - { - warning_at (token->location, - OPT_Wc___compat, - "identifier %qE conflicts with C++ keyword", - token->value); - } - else if (rid_code >= RID_FIRST_ADDR_SPACE - && rid_code <= RID_LAST_ADDR_SPACE) - { - addr_space_t as; - as = (addr_space_t) (rid_code - RID_FIRST_ADDR_SPACE); - targetm.addr_space.diagnose_usage (as, token->location); - token->id_kind = C_ID_ADDRSPACE; - token->keyword = rid_code; - break; - } - else if (c_dialect_objc () && OBJC_IS_PQ_KEYWORD (rid_code)) - { - /* We found an Objective-C "pq" keyword (in, out, - inout, bycopy, byref, oneway). They need special - care because the interpretation depends on the - context. */ - if (parser->objc_pq_context) - { - token->type = CPP_KEYWORD; - token->keyword = rid_code; - break; - } - else if (parser->objc_could_be_foreach_context - && rid_code == RID_IN) - { - /* We are in Objective-C, inside a (potential) - foreach context (which means after having - parsed 'for (', but before having parsed ';'), - and we found 'in'. We consider it the keyword - which terminates the declaration at the - beginning of a foreach-statement. Note that - this means you can't use 'in' for anything else - in that context; in particular, in Objective-C - you can't use 'in' as the name of the running - variable in a C for loop. We could potentially - try to add code here to disambiguate, but it - seems a reasonable limitation. */ - token->type = CPP_KEYWORD; - token->keyword = rid_code; - break; - } - /* Else, "pq" keywords outside of the "pq" context are - not keywords, and we fall through to the code for - normal tokens. */ - } - else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code)) - { - /* We found an Objective-C "property attribute" - keyword (getter, setter, readonly, etc). These are - only valid in the property context. */ - if (parser->objc_property_attr_context) - { - token->type = CPP_KEYWORD; - token->keyword = rid_code; - break; - } - /* Else they are not special keywords. - */ - } - else if (c_dialect_objc () - && (OBJC_IS_AT_KEYWORD (rid_code) - || OBJC_IS_CXX_KEYWORD (rid_code))) - { - /* We found one of the Objective-C "@" keywords (defs, - selector, synchronized, etc) or one of the - Objective-C "cxx" keywords (class, private, - protected, public, try, catch, throw) without a - preceding '@' sign. Do nothing and fall through to - the code for normal tokens (in C++ we would still - consider the CXX ones keywords, but not in C). */ - ; - } - else - { - token->type = CPP_KEYWORD; - token->keyword = rid_code; - break; - } - } - - decl = lookup_name (token->value); - if (decl) - { - if (TREE_CODE (decl) == TYPE_DECL) - { - token->id_kind = C_ID_TYPENAME; - break; - } - } - else if (c_dialect_objc ()) - { - tree objc_interface_decl = objc_is_class_name (token->value); - /* Objective-C class names are in the same namespace as - variables and typedefs, and hence are shadowed by local - declarations. */ - if (objc_interface_decl - && (!objc_force_identifier || global_bindings_p ())) - { - token->value = objc_interface_decl; - token->id_kind = C_ID_CLASSNAME; - break; - } - } - token->id_kind = C_ID_ID; - } - break; - case CPP_AT_NAME: - /* This only happens in Objective-C; it must be a keyword. */ - token->type = CPP_KEYWORD; - switch (C_RID_CODE (token->value)) - { - /* Replace 'class' with '@class', 'private' with '@private', - etc. This prevents confusion with the C++ keyword - 'class', and makes the tokens consistent with other - Objective-C 'AT' keywords. For example '@class' is - reported as RID_AT_CLASS which is consistent with - '@synchronized', which is reported as - RID_AT_SYNCHRONIZED. - */ - case RID_CLASS: token->keyword = RID_AT_CLASS; break; - case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break; - case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break; - case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break; - case RID_THROW: token->keyword = RID_AT_THROW; break; - case RID_TRY: token->keyword = RID_AT_TRY; break; - case RID_CATCH: token->keyword = RID_AT_CATCH; break; - case RID_SYNCHRONIZED: token->keyword = RID_AT_SYNCHRONIZED; break; - default: token->keyword = C_RID_CODE (token->value); - } - break; - case CPP_COLON: - case CPP_COMMA: - case CPP_CLOSE_PAREN: - case CPP_SEMICOLON: - /* These tokens may affect the interpretation of any identifiers - following, if doing Objective-C. */ - if (c_dialect_objc ()) - parser->objc_need_raw_identifier = false; - break; - case CPP_PRAGMA: - /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */ - token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value); - token->value = NULL; - break; - default: - break; - } - out: - timevar_pop (TV_LEX); -} - -/* Return a pointer to the next token from PARSER, reading it in if - necessary. */ - -c_token * -c_parser_peek_token (c_parser *parser) -{ - if (parser->tokens_avail == 0) - { - c_lex_one_token (parser, &parser->tokens[0]); - parser->tokens_avail = 1; - } - return &parser->tokens[0]; -} - -/* Return a pointer to the next-but-one token from PARSER, reading it - in if necessary. The next token is already read in. */ - -c_token * -c_parser_peek_2nd_token (c_parser *parser) -{ - if (parser->tokens_avail >= 2) - return &parser->tokens[1]; - gcc_assert (parser->tokens_avail == 1); - gcc_assert (parser->tokens[0].type != CPP_EOF); - gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL); - c_lex_one_token (parser, &parser->tokens[1]); - parser->tokens_avail = 2; - return &parser->tokens[1]; -} - -/* Return a pointer to the Nth token from PARSER, reading it - in if necessary. The N-1th token is already read in. */ - -c_token * -c_parser_peek_nth_token (c_parser *parser, unsigned int n) -{ - /* N is 1-based, not zero-based. */ - gcc_assert (n > 0); - - if (parser->tokens_avail >= n) - return &parser->tokens[n - 1]; - gcc_assert (parser->tokens_avail == n - 1); - c_lex_one_token (parser, &parser->tokens[n - 1]); - parser->tokens_avail = n; - return &parser->tokens[n - 1]; -} - -/* Return a pointer to the Nth token from PARSER, reading it in as a - raw look-ahead token if necessary. The N-1th token is already read - in. Raw look-ahead tokens remain available for when the non-raw - functions above are called. */ - -c_token * -c_parser_peek_nth_token_raw (c_parser *parser, unsigned int n) -{ - /* N is 1-based, not zero-based. */ - gcc_assert (n > 0); - - if (parser->tokens_avail >= n) - return &parser->tokens[n - 1]; - unsigned int raw_len = vec_safe_length (parser->raw_tokens); - unsigned int raw_avail - = parser->tokens_avail + raw_len - parser->raw_tokens_used; - gcc_assert (raw_avail >= n - 1); - if (raw_avail >= n) - return &(*parser->raw_tokens)[parser->raw_tokens_used - + n - 1 - parser->tokens_avail]; - vec_safe_reserve (parser->raw_tokens, 1); - parser->raw_tokens->quick_grow (raw_len + 1); - c_lex_one_token (parser, &(*parser->raw_tokens)[raw_len], true); - return &(*parser->raw_tokens)[raw_len]; -} - -bool -c_keyword_starts_typename (enum rid keyword) -{ - switch (keyword) - { - case RID_UNSIGNED: - case RID_LONG: - case RID_SHORT: - case RID_SIGNED: - case RID_COMPLEX: - case RID_INT: - case RID_CHAR: - case RID_FLOAT: - case RID_DOUBLE: - case RID_VOID: - case RID_DFLOAT32: - case RID_DFLOAT64: - case RID_DFLOAT128: - CASE_RID_FLOATN_NX: - case RID_BOOL: - case RID_ENUM: - case RID_STRUCT: - case RID_UNION: - case RID_TYPEOF: - case RID_CONST: - case RID_ATOMIC: - case RID_VOLATILE: - case RID_RESTRICT: - case RID_ATTRIBUTE: - case RID_FRACT: - case RID_ACCUM: - case RID_SAT: - case RID_AUTO_TYPE: - case RID_ALIGNAS: - return true; - default: - if (keyword >= RID_FIRST_INT_N - && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS - && int_n_enabled_p[keyword - RID_FIRST_INT_N]) - return true; - return false; - } -} - -/* Return true if TOKEN can start a type name, - false otherwise. */ -bool -c_token_starts_typename (c_token *token) -{ - switch (token->type) - { - case CPP_NAME: - switch (token->id_kind) - { - case C_ID_ID: - return false; - case C_ID_ADDRSPACE: - return true; - case C_ID_TYPENAME: - return true; - case C_ID_CLASSNAME: - gcc_assert (c_dialect_objc ()); - return true; - default: - gcc_unreachable (); - } - case CPP_KEYWORD: - return c_keyword_starts_typename (token->keyword); - case CPP_LESS: - if (c_dialect_objc ()) - return true; - return false; - default: - return false; - } -} - -/* Return true if the next token from PARSER can start a type name, - false otherwise. LA specifies how to do lookahead in order to - detect unknown type names. If unsure, pick CLA_PREFER_ID. */ - -static inline bool -c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la) -{ - c_token *token = c_parser_peek_token (parser); - if (c_token_starts_typename (token)) - return true; - - /* Try a bit harder to detect an unknown typename. */ - if (la != cla_prefer_id - && token->type == CPP_NAME - && token->id_kind == C_ID_ID - - /* Do not try too hard when we could have "object in array". */ - && !parser->objc_could_be_foreach_context - - && (la == cla_prefer_type - || c_parser_peek_2nd_token (parser)->type == CPP_NAME - || c_parser_peek_2nd_token (parser)->type == CPP_MULT) - - /* Only unknown identifiers. */ - && !lookup_name (token->value)) - return true; - - return false; -} - -/* Return true if TOKEN is a type qualifier, false otherwise. */ -static bool -c_token_is_qualifier (c_token *token) -{ - switch (token->type) - { - case CPP_NAME: - switch (token->id_kind) - { - case C_ID_ADDRSPACE: - return true; - default: - return false; - } - case CPP_KEYWORD: - switch (token->keyword) - { - case RID_CONST: - case RID_VOLATILE: - case RID_RESTRICT: - case RID_ATTRIBUTE: - case RID_ATOMIC: - return true; - default: - return false; - } - case CPP_LESS: - return false; - default: - gcc_unreachable (); - } -} - -/* Return true if the next token from PARSER is a type qualifier, - false otherwise. */ -static inline bool -c_parser_next_token_is_qualifier (c_parser *parser) -{ - c_token *token = c_parser_peek_token (parser); - return c_token_is_qualifier (token); -} - -/* Return true if TOKEN can start declaration specifiers (not - including standard attributes), false otherwise. */ -static bool -c_token_starts_declspecs (c_token *token) -{ - switch (token->type) - { - case CPP_NAME: - switch (token->id_kind) - { - case C_ID_ID: - return false; - case C_ID_ADDRSPACE: - return true; - case C_ID_TYPENAME: - return true; - case C_ID_CLASSNAME: - gcc_assert (c_dialect_objc ()); - return true; - default: - gcc_unreachable (); - } - case CPP_KEYWORD: - switch (token->keyword) - { - case RID_STATIC: - case RID_EXTERN: - case RID_REGISTER: - case RID_TYPEDEF: - case RID_INLINE: - case RID_NORETURN: - case RID_AUTO: - case RID_THREAD: - case RID_UNSIGNED: - case RID_LONG: - case RID_SHORT: - case RID_SIGNED: - case RID_COMPLEX: - case RID_INT: - case RID_CHAR: - case RID_FLOAT: - case RID_DOUBLE: - case RID_VOID: - case RID_DFLOAT32: - case RID_DFLOAT64: - case RID_DFLOAT128: - CASE_RID_FLOATN_NX: - case RID_BOOL: - case RID_ENUM: - case RID_STRUCT: - case RID_UNION: - case RID_TYPEOF: - case RID_CONST: - case RID_VOLATILE: - case RID_RESTRICT: - case RID_ATTRIBUTE: - case RID_FRACT: - case RID_ACCUM: - case RID_SAT: - case RID_ALIGNAS: - case RID_ATOMIC: - case RID_AUTO_TYPE: - return true; - default: - if (token->keyword >= RID_FIRST_INT_N - && token->keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS - && int_n_enabled_p[token->keyword - RID_FIRST_INT_N]) - return true; - return false; - } - case CPP_LESS: - if (c_dialect_objc ()) - return true; - return false; - default: - return false; - } -} - - -/* Return true if TOKEN can start declaration specifiers (not - including standard attributes) or a static assertion, false - otherwise. */ -static bool -c_token_starts_declaration (c_token *token) -{ - if (c_token_starts_declspecs (token) - || token->keyword == RID_STATIC_ASSERT) - return true; - else - return false; -} - -/* Return true if the next token from PARSER can start declaration - specifiers (not including standard attributes), false - otherwise. */ -bool -c_parser_next_token_starts_declspecs (c_parser *parser) -{ - c_token *token = c_parser_peek_token (parser); - - /* In Objective-C, a classname normally starts a declspecs unless it - is immediately followed by a dot. In that case, it is the - Objective-C 2.0 "dot-syntax" for class objects, ie, calls the - setter/getter on the class. c_token_starts_declspecs() can't - differentiate between the two cases because it only checks the - current token, so we have a special check here. */ - if (c_dialect_objc () - && token->type == CPP_NAME - && token->id_kind == C_ID_CLASSNAME - && c_parser_peek_2nd_token (parser)->type == CPP_DOT) - return false; - - return c_token_starts_declspecs (token); -} - -/* Return true if the next tokens from PARSER can start declaration - specifiers (not including standard attributes) or a static - assertion, false otherwise. */ -bool -c_parser_next_tokens_start_declaration (c_parser *parser) -{ - c_token *token = c_parser_peek_token (parser); - - /* Same as above. */ - if (c_dialect_objc () - && token->type == CPP_NAME - && token->id_kind == C_ID_CLASSNAME - && c_parser_peek_2nd_token (parser)->type == CPP_DOT) - return false; - - /* Labels do not start declarations. */ - if (token->type == CPP_NAME - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) - return false; - - if (c_token_starts_declaration (token)) - return true; - - if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl)) - return true; - - return false; -} - -/* Consume the next token from PARSER. */ - -void -c_parser_consume_token (c_parser *parser) -{ - gcc_assert (parser->tokens_avail >= 1); - gcc_assert (parser->tokens[0].type != CPP_EOF); - gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL); - gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA); - parser->last_token_location = parser->tokens[0].location; - if (parser->tokens != &parser->tokens_buf[0]) - parser->tokens++; - else if (parser->tokens_avail >= 2) - { - parser->tokens[0] = parser->tokens[1]; - if (parser->tokens_avail >= 3) - { - parser->tokens[1] = parser->tokens[2]; - if (parser->tokens_avail >= 4) - parser->tokens[2] = parser->tokens[3]; - } - } - parser->tokens_avail--; - parser->seen_string_literal = false; -} - -/* Expect the current token to be a #pragma. Consume it and remember - that we've begun parsing a pragma. */ - -static void -c_parser_consume_pragma (c_parser *parser) -{ - gcc_assert (!parser->in_pragma); - gcc_assert (parser->tokens_avail >= 1); - gcc_assert (parser->tokens[0].type == CPP_PRAGMA); - if (parser->tokens != &parser->tokens_buf[0]) - parser->tokens++; - else if (parser->tokens_avail >= 2) - { - parser->tokens[0] = parser->tokens[1]; - if (parser->tokens_avail >= 3) - parser->tokens[1] = parser->tokens[2]; - } - parser->tokens_avail--; - parser->in_pragma = true; -} - -/* Update the global input_location from TOKEN. */ -static inline void -c_parser_set_source_position_from_token (c_token *token) -{ - if (token->type != CPP_EOF) - { - input_location = token->location; - } -} - -/* Helper function for c_parser_error. - Having peeked a token of kind TOK1_KIND that might signify - a conflict marker, peek successor tokens to determine - if we actually do have a conflict marker. - Specifically, we consider a run of 7 '<', '=' or '>' characters - at the start of a line as a conflict marker. - These come through the lexer as three pairs and a single, - e.g. three CPP_LSHIFT ("<<") and a CPP_LESS ('<'). - If it returns true, *OUT_LOC is written to with the location/range - of the marker. */ - -static bool -c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind, - location_t *out_loc) -{ - c_token *token2 = c_parser_peek_2nd_token (parser); - if (token2->type != tok1_kind) - return false; - c_token *token3 = c_parser_peek_nth_token (parser, 3); - if (token3->type != tok1_kind) - return false; - c_token *token4 = c_parser_peek_nth_token (parser, 4); - if (token4->type != conflict_marker_get_final_tok_kind (tok1_kind)) - return false; - - /* It must be at the start of the line. */ - location_t start_loc = c_parser_peek_token (parser)->location; - if (LOCATION_COLUMN (start_loc) != 1) - return false; - - /* We have a conflict marker. Construct a location of the form: - <<<<<<< - ^~~~~~~ - with start == caret, finishing at the end of the marker. */ - location_t finish_loc = get_finish (token4->location); - *out_loc = make_location (start_loc, start_loc, finish_loc); - - return true; -} - -/* Issue a diagnostic of the form - FILE:LINE: MESSAGE before TOKEN - where TOKEN is the next token in the input stream of PARSER. - MESSAGE (specified by the caller) is usually of the form "expected - OTHER-TOKEN". - - Use RICHLOC as the location of the diagnostic. - - Do not issue a diagnostic if still recovering from an error. - - Return true iff an error was actually emitted. - - ??? This is taken from the C++ parser, but building up messages in - this way is not i18n-friendly and some other approach should be - used. */ - -static bool -c_parser_error_richloc (c_parser *parser, const char *gmsgid, - rich_location *richloc) -{ - c_token *token = c_parser_peek_token (parser); - if (parser->error) - return false; - parser->error = true; - if (!gmsgid) - return false; - - /* If this is actually a conflict marker, report it as such. */ - if (token->type == CPP_LSHIFT - || token->type == CPP_RSHIFT - || token->type == CPP_EQ_EQ) - { - location_t loc; - if (c_parser_peek_conflict_marker (parser, token->type, &loc)) - { - error_at (loc, "version control conflict marker in file"); - return true; - } - } - - /* If we were parsing a string-literal and there is an unknown name - token right after, then check to see if that could also have been - a literal string by checking the name against a list of known - standard string literal constants defined in header files. If - there is one, then add that as an hint to the error message. */ - auto_diagnostic_group d; - name_hint h; - if (parser->seen_string_literal && token->type == CPP_NAME) - { - tree name = token->value; - const char *token_name = IDENTIFIER_POINTER (name); - const char *header_hint - = get_c_stdlib_header_for_string_macro_name (token_name); - if (header_hint != NULL) - h = name_hint (NULL, new suggest_missing_header (token->location, - token_name, - header_hint)); - } - - c_parse_error (gmsgid, - /* Because c_parse_error does not understand - CPP_KEYWORD, keywords are treated like - identifiers. */ - (token->type == CPP_KEYWORD ? CPP_NAME : token->type), - /* ??? The C parser does not save the cpp flags of a - token, we need to pass 0 here and we will not get - the source spelling of some tokens but rather the - canonical spelling. */ - token->value, /*flags=*/0, richloc); - return true; -} - -/* As c_parser_error_richloc, but issue the message at the - location of PARSER's next token, or at input_location - if the next token is EOF. */ - -bool -c_parser_error (c_parser *parser, const char *gmsgid) -{ - c_token *token = c_parser_peek_token (parser); - c_parser_set_source_position_from_token (token); - rich_location richloc (line_table, input_location); - return c_parser_error_richloc (parser, gmsgid, &richloc); -} - -/* Some tokens naturally come in pairs e.g.'(' and ')'. - This class is for tracking such a matching pair of symbols. - In particular, it tracks the location of the first token, - so that if the second token is missing, we can highlight the - location of the first token when notifying the user about the - problem. */ - -template -class token_pair -{ - public: - /* token_pair's ctor. */ - token_pair () : m_open_loc (UNKNOWN_LOCATION) {} - - /* If the next token is the opening symbol for this pair, consume it and - return true. - Otherwise, issue an error and return false. - In either case, record the location of the opening token. */ - - bool require_open (c_parser *parser) - { - c_token *token = c_parser_peek_token (parser); - if (token) - m_open_loc = token->location; - - return c_parser_require (parser, traits_t::open_token_type, - traits_t::open_gmsgid); - } - - /* Consume the next token from PARSER, recording its location as - that of the opening token within the pair. */ - - void consume_open (c_parser *parser) - { - c_token *token = c_parser_peek_token (parser); - gcc_assert (token->type == traits_t::open_token_type); - m_open_loc = token->location; - c_parser_consume_token (parser); - } - - /* If the next token is the closing symbol for this pair, consume it - and return true. - Otherwise, issue an error, highlighting the location of the - corresponding opening token, and return false. */ - - bool require_close (c_parser *parser) const - { - return c_parser_require (parser, traits_t::close_token_type, - traits_t::close_gmsgid, m_open_loc); - } - - /* Like token_pair::require_close, except that tokens will be skipped - until the desired token is found. An error message is still produced - if the next token is not as expected. */ - - void skip_until_found_close (c_parser *parser) const - { - c_parser_skip_until_found (parser, traits_t::close_token_type, - traits_t::close_gmsgid, m_open_loc); - } - - private: - location_t m_open_loc; -}; - -/* Traits for token_pair for tracking matching pairs of parentheses. */ - -struct matching_paren_traits -{ - static const enum cpp_ttype open_token_type = CPP_OPEN_PAREN; - static const char * const open_gmsgid; - static const enum cpp_ttype close_token_type = CPP_CLOSE_PAREN; - static const char * const close_gmsgid; -}; - -const char * const matching_paren_traits::open_gmsgid = "expected %<(%>"; -const char * const matching_paren_traits::close_gmsgid = "expected %<)%>"; - -/* "matching_parens" is a token_pair class for tracking matching - pairs of parentheses. */ - -typedef token_pair matching_parens; - -/* Traits for token_pair for tracking matching pairs of braces. */ - -struct matching_brace_traits -{ - static const enum cpp_ttype open_token_type = CPP_OPEN_BRACE; - static const char * const open_gmsgid; - static const enum cpp_ttype close_token_type = CPP_CLOSE_BRACE; - static const char * const close_gmsgid; -}; - -const char * const matching_brace_traits::open_gmsgid = "expected %<{%>"; -const char * const matching_brace_traits::close_gmsgid = "expected %<}%>"; - -/* "matching_braces" is a token_pair class for tracking matching - pairs of braces. */ - -typedef token_pair matching_braces; - -/* Get a description of the matching symbol to TYPE e.g. "(" for - CPP_CLOSE_PAREN. */ - -static const char * -get_matching_symbol (enum cpp_ttype type) -{ - switch (type) - { - default: - gcc_unreachable (); - case CPP_CLOSE_PAREN: - return "("; - case CPP_CLOSE_BRACE: - return "{"; - } -} - -/* If the next token is of the indicated TYPE, consume it. Otherwise, - issue the error MSGID. If MSGID is NULL then a message has already - been produced and no message will be produced this time. Returns - true if found, false otherwise. - - If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it - within any error as the location of an "opening" token matching - the close token TYPE (e.g. the location of the '(' when TYPE is - CPP_CLOSE_PAREN). - - If TYPE_IS_UNIQUE is true (the default) then msgid describes exactly - one type (e.g. "expected %<)%>") and thus it may be reasonable to - attempt to generate a fix-it hint for the problem. - Otherwise msgid describes multiple token types (e.g. - "expected %<;%>, %<,%> or %<)%>"), and thus we shouldn't attempt to - generate a fix-it hint. */ - -bool -c_parser_require (c_parser *parser, - enum cpp_ttype type, - const char *msgid, - location_t matching_location, - bool type_is_unique) -{ - if (c_parser_next_token_is (parser, type)) - { - c_parser_consume_token (parser); - return true; - } - else - { - location_t next_token_loc = c_parser_peek_token (parser)->location; - gcc_rich_location richloc (next_token_loc); - - /* Potentially supply a fix-it hint, suggesting to add the - missing token immediately after the *previous* token. - This may move the primary location within richloc. */ - if (!parser->error && type_is_unique) - maybe_suggest_missing_token_insertion (&richloc, type, - parser->last_token_location); - - /* If matching_location != UNKNOWN_LOCATION, highlight it. - Attempt to consolidate diagnostics by printing it as a - secondary range within the main diagnostic. */ - bool added_matching_location = false; - if (matching_location != UNKNOWN_LOCATION) - added_matching_location - = richloc.add_location_if_nearby (matching_location); - - if (c_parser_error_richloc (parser, msgid, &richloc)) - /* If we weren't able to consolidate matching_location, then - print it as a secondary diagnostic. */ - if (matching_location != UNKNOWN_LOCATION && !added_matching_location) - inform (matching_location, "to match this %qs", - get_matching_symbol (type)); - - return false; - } -} - -/* If the next token is the indicated keyword, consume it. Otherwise, - issue the error MSGID. Returns true if found, false otherwise. */ - -static bool -c_parser_require_keyword (c_parser *parser, - enum rid keyword, - const char *msgid) -{ - if (c_parser_next_token_is_keyword (parser, keyword)) - { - c_parser_consume_token (parser); - return true; - } - else - { - c_parser_error (parser, msgid); - return false; - } -} - -/* Like c_parser_require, except that tokens will be skipped until the - desired token is found. An error message is still produced if the - next token is not as expected. If MSGID is NULL then a message has - already been produced and no message will be produced this - time. - - If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it - within any error as the location of an "opening" token matching - the close token TYPE (e.g. the location of the '(' when TYPE is - CPP_CLOSE_PAREN). */ - -void -c_parser_skip_until_found (c_parser *parser, - enum cpp_ttype type, - const char *msgid, - location_t matching_location) -{ - unsigned nesting_depth = 0; - - if (c_parser_require (parser, type, msgid, matching_location)) - return; - - /* Skip tokens until the desired token is found. */ - while (true) - { - /* Peek at the next token. */ - c_token *token = c_parser_peek_token (parser); - /* If we've reached the token we want, consume it and stop. */ - if (token->type == type && !nesting_depth) - { - c_parser_consume_token (parser); - break; - } - - /* If we've run out of tokens, stop. */ - if (token->type == CPP_EOF) - return; - if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) - return; - if (token->type == CPP_OPEN_BRACE - || token->type == CPP_OPEN_PAREN - || token->type == CPP_OPEN_SQUARE) - ++nesting_depth; - else if (token->type == CPP_CLOSE_BRACE - || token->type == CPP_CLOSE_PAREN - || token->type == CPP_CLOSE_SQUARE) - { - if (nesting_depth-- == 0) - break; - } - /* Consume this token. */ - c_parser_consume_token (parser); - } - parser->error = false; -} - -/* Skip tokens until the end of a parameter is found, but do not - consume the comma, semicolon or closing delimiter. */ - -static void -c_parser_skip_to_end_of_parameter (c_parser *parser) -{ - unsigned nesting_depth = 0; - - while (true) - { - c_token *token = c_parser_peek_token (parser); - if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON) - && !nesting_depth) - break; - /* If we've run out of tokens, stop. */ - if (token->type == CPP_EOF) - return; - if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) - return; - if (token->type == CPP_OPEN_BRACE - || token->type == CPP_OPEN_PAREN - || token->type == CPP_OPEN_SQUARE) - ++nesting_depth; - else if (token->type == CPP_CLOSE_BRACE - || token->type == CPP_CLOSE_PAREN - || token->type == CPP_CLOSE_SQUARE) - { - if (nesting_depth-- == 0) - break; - } - /* Consume this token. */ - c_parser_consume_token (parser); - } - parser->error = false; -} - -/* Expect to be at the end of the pragma directive and consume an - end of line marker. */ - -static void -c_parser_skip_to_pragma_eol (c_parser *parser, bool error_if_not_eol = true) -{ - gcc_assert (parser->in_pragma); - parser->in_pragma = false; - - if (error_if_not_eol && c_parser_peek_token (parser)->type != CPP_PRAGMA_EOL) - c_parser_error (parser, "expected end of line"); - - cpp_ttype token_type; - do - { - c_token *token = c_parser_peek_token (parser); - token_type = token->type; - if (token_type == CPP_EOF) - break; - c_parser_consume_token (parser); - } - while (token_type != CPP_PRAGMA_EOL); - - parser->error = false; -} - -/* Skip tokens until we have consumed an entire block, or until we - have consumed a non-nested ';'. */ - -static void -c_parser_skip_to_end_of_block_or_statement (c_parser *parser) -{ - unsigned nesting_depth = 0; - bool save_error = parser->error; - - while (true) - { - c_token *token; - - /* Peek at the next token. */ - token = c_parser_peek_token (parser); - - switch (token->type) - { - case CPP_EOF: - return; - - case CPP_PRAGMA_EOL: - if (parser->in_pragma) - return; - break; - - case CPP_SEMICOLON: - /* If the next token is a ';', we have reached the - end of the statement. */ - if (!nesting_depth) - { - /* Consume the ';'. */ - c_parser_consume_token (parser); - goto finished; - } - break; - - case CPP_CLOSE_BRACE: - /* If the next token is a non-nested '}', then we have - reached the end of the current block. */ - if (nesting_depth == 0 || --nesting_depth == 0) - { - c_parser_consume_token (parser); - goto finished; - } - break; - - case CPP_OPEN_BRACE: - /* If it the next token is a '{', then we are entering a new - block. Consume the entire block. */ - ++nesting_depth; - break; - - case CPP_PRAGMA: - /* If we see a pragma, consume the whole thing at once. We - have some safeguards against consuming pragmas willy-nilly. - Normally, we'd expect to be here with parser->error set, - which disables these safeguards. But it's possible to get - here for secondary error recovery, after parser->error has - been cleared. */ - c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); - parser->error = save_error; - continue; - - default: - break; - } - - c_parser_consume_token (parser); - } - - finished: - parser->error = false; -} - -/* CPP's options (initialized by c-opts.c). */ -extern cpp_options *cpp_opts; - -/* Save the warning flags which are controlled by __extension__. */ - -static inline int -disable_extension_diagnostics (void) -{ - int ret = (pedantic - | (warn_pointer_arith << 1) - | (warn_traditional << 2) - | (flag_iso << 3) - | (warn_long_long << 4) - | (warn_cxx_compat << 5) - | (warn_overlength_strings << 6) - /* warn_c90_c99_compat has three states: -1/0/1, so we must - play tricks to properly restore it. */ - | ((warn_c90_c99_compat == 1) << 7) - | ((warn_c90_c99_compat == -1) << 8) - /* Similarly for warn_c99_c11_compat. */ - | ((warn_c99_c11_compat == 1) << 9) - | ((warn_c99_c11_compat == -1) << 10) - /* Similarly for warn_c11_c2x_compat. */ - | ((warn_c11_c2x_compat == 1) << 11) - | ((warn_c11_c2x_compat == -1) << 12) - ); - cpp_opts->cpp_pedantic = pedantic = 0; - warn_pointer_arith = 0; - cpp_opts->cpp_warn_traditional = warn_traditional = 0; - flag_iso = 0; - cpp_opts->cpp_warn_long_long = warn_long_long = 0; - warn_cxx_compat = 0; - warn_overlength_strings = 0; - warn_c90_c99_compat = 0; - warn_c99_c11_compat = 0; - warn_c11_c2x_compat = 0; - return ret; -} - -/* Restore the warning flags which are controlled by __extension__. - FLAGS is the return value from disable_extension_diagnostics. */ - -static inline void -restore_extension_diagnostics (int flags) -{ - cpp_opts->cpp_pedantic = pedantic = flags & 1; - warn_pointer_arith = (flags >> 1) & 1; - cpp_opts->cpp_warn_traditional = warn_traditional = (flags >> 2) & 1; - flag_iso = (flags >> 3) & 1; - cpp_opts->cpp_warn_long_long = warn_long_long = (flags >> 4) & 1; - warn_cxx_compat = (flags >> 5) & 1; - warn_overlength_strings = (flags >> 6) & 1; - /* See above for why is this needed. */ - warn_c90_c99_compat = (flags >> 7) & 1 ? 1 : ((flags >> 8) & 1 ? -1 : 0); - warn_c99_c11_compat = (flags >> 9) & 1 ? 1 : ((flags >> 10) & 1 ? -1 : 0); - warn_c11_c2x_compat = (flags >> 11) & 1 ? 1 : ((flags >> 12) & 1 ? -1 : 0); -} - -/* Helper data structure for parsing #pragma acc routine. */ -struct oacc_routine_data { - bool error_seen; /* Set if error has been reported. */ - bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ - tree clauses; - location_t loc; -}; - -/* Used for parsing objc foreach statements. */ -static tree objc_foreach_break_label, objc_foreach_continue_label; - -static bool c_parser_nth_token_starts_std_attributes (c_parser *, - unsigned int); -static tree c_parser_std_attribute_specifier_sequence (c_parser *); -static void c_parser_external_declaration (c_parser *); -static void c_parser_asm_definition (c_parser *); -static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, - bool, bool, tree * = NULL, - vec * = NULL, - bool have_attrs = false, - tree attrs = NULL, - struct oacc_routine_data * = NULL, - bool * = NULL); -static void c_parser_static_assert_declaration_no_semi (c_parser *); -static void c_parser_static_assert_declaration (c_parser *); -static struct c_typespec c_parser_enum_specifier (c_parser *); -static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); -static tree c_parser_struct_declaration (c_parser *); -static struct c_typespec c_parser_typeof_specifier (c_parser *); -static tree c_parser_alignas_specifier (c_parser *); -static struct c_declarator *c_parser_direct_declarator (c_parser *, bool, - c_dtr_syn, bool *); -static struct c_declarator *c_parser_direct_declarator_inner (c_parser *, - bool, - struct c_declarator *); -static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree, - bool); -static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree, - tree, bool); -static struct c_parm *c_parser_parameter_declaration (c_parser *, tree, bool); -static tree c_parser_simple_asm_expr (c_parser *); -static tree c_parser_gnu_attributes (c_parser *); -static struct c_expr c_parser_initializer (c_parser *); -static struct c_expr c_parser_braced_init (c_parser *, tree, bool, - struct obstack *); -static void c_parser_initelt (c_parser *, struct obstack *); -static void c_parser_initval (c_parser *, struct c_expr *, - struct obstack *); -static tree c_parser_compound_statement (c_parser *, location_t * = NULL); -static location_t c_parser_compound_statement_nostart (c_parser *); -static void c_parser_label (c_parser *, tree); -static void c_parser_statement (c_parser *, bool *, location_t * = NULL); -static void c_parser_statement_after_labels (c_parser *, bool *, - vec * = NULL); -static tree c_parser_c99_block_statement (c_parser *, bool *, - location_t * = NULL); -static void c_parser_if_statement (c_parser *, bool *, vec *); -static void c_parser_switch_statement (c_parser *, bool *); -static void c_parser_while_statement (c_parser *, bool, unsigned short, bool *); -static void c_parser_do_statement (c_parser *, bool, unsigned short); -static void c_parser_for_statement (c_parser *, bool, unsigned short, bool *); -static tree c_parser_asm_statement (c_parser *); -static tree c_parser_asm_operands (c_parser *); -static tree c_parser_asm_goto_operands (c_parser *); -static tree c_parser_asm_clobbers (c_parser *); -static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *, - tree = NULL_TREE); -static struct c_expr c_parser_conditional_expression (c_parser *, - struct c_expr *, tree); -static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, - tree); -static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); -static struct c_expr c_parser_unary_expression (c_parser *); -static struct c_expr c_parser_sizeof_expression (c_parser *); -static struct c_expr c_parser_alignof_expression (c_parser *); -static struct c_expr c_parser_postfix_expression (c_parser *); -static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *, - struct c_type_name *, - location_t); -static struct c_expr c_parser_postfix_expression_after_primary (c_parser *, - location_t loc, - struct c_expr); -static tree c_parser_transaction (c_parser *, enum rid); -static struct c_expr c_parser_transaction_expression (c_parser *, enum rid); -static tree c_parser_transaction_cancel (c_parser *); -static struct c_expr c_parser_expression (c_parser *); -static struct c_expr c_parser_expression_conv (c_parser *); -static vec *c_parser_expr_list (c_parser *, bool, bool, - vec **, location_t *, - tree *, vec *, - unsigned int * = NULL); -static struct c_expr c_parser_has_attribute_expression (c_parser *); - -static void c_parser_oacc_declare (c_parser *); -static void c_parser_oacc_enter_exit_data (c_parser *, bool); -static void c_parser_oacc_update (c_parser *); -static void c_parser_omp_construct (c_parser *, bool *); -static void c_parser_omp_threadprivate (c_parser *); -static void c_parser_omp_barrier (c_parser *); -static void c_parser_omp_depobj (c_parser *); -static void c_parser_omp_flush (c_parser *); -static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, - tree, tree *, bool *); -static void c_parser_omp_taskwait (c_parser *); -static void c_parser_omp_taskyield (c_parser *); -static void c_parser_omp_cancel (c_parser *); -static void c_parser_omp_nothing (c_parser *); - -enum pragma_context { pragma_external, pragma_struct, pragma_param, - pragma_stmt, pragma_compound }; -static bool c_parser_pragma (c_parser *, enum pragma_context, bool *); -static bool c_parser_omp_cancellation_point (c_parser *, enum pragma_context); -static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *); -static void c_parser_omp_end_declare_target (c_parser *); -static bool c_parser_omp_declare (c_parser *, enum pragma_context); -static void c_parser_omp_requires (c_parser *); -static bool c_parser_omp_error (c_parser *, enum pragma_context); -static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *); -static void c_parser_oacc_routine (c_parser *, enum pragma_context); - -/* These Objective-C parser functions are only ever called when - compiling Objective-C. */ -static void c_parser_objc_class_definition (c_parser *, tree); -static void c_parser_objc_class_instance_variables (c_parser *); -static void c_parser_objc_class_declaration (c_parser *); -static void c_parser_objc_alias_declaration (c_parser *); -static void c_parser_objc_protocol_definition (c_parser *, tree); -static bool c_parser_objc_method_type (c_parser *); -static void c_parser_objc_method_definition (c_parser *); -static void c_parser_objc_methodprotolist (c_parser *); -static void c_parser_objc_methodproto (c_parser *); -static tree c_parser_objc_method_decl (c_parser *, bool, tree *, tree *); -static tree c_parser_objc_type_name (c_parser *); -static tree c_parser_objc_protocol_refs (c_parser *); -static void c_parser_objc_try_catch_finally_statement (c_parser *); -static void c_parser_objc_synchronized_statement (c_parser *); -static tree c_parser_objc_selector (c_parser *); -static tree c_parser_objc_selector_arg (c_parser *); -static tree c_parser_objc_receiver (c_parser *); -static tree c_parser_objc_message_args (c_parser *); -static tree c_parser_objc_keywordexpr (c_parser *); -static void c_parser_objc_at_property_declaration (c_parser *); -static void c_parser_objc_at_synthesize_declaration (c_parser *); -static void c_parser_objc_at_dynamic_declaration (c_parser *); -static bool c_parser_objc_diagnose_bad_element_prefix - (c_parser *, struct c_declspecs *); -static location_t c_parser_parse_rtl_body (c_parser *, char *); - -/* Parse a translation unit (C90 6.7, C99 6.9, C11 6.9). - - translation-unit: - external-declarations - - external-declarations: - external-declaration - external-declarations external-declaration - - GNU extensions: - - translation-unit: - empty -*/ - -static void -c_parser_translation_unit (c_parser *parser) -{ - if (c_parser_next_token_is (parser, CPP_EOF)) - { - pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, - "ISO C forbids an empty translation unit"); - } - else - { - void *obstack_position = obstack_alloc (&parser_obstack, 0); - mark_valid_location_for_stdc_pragma (false); - do - { - ggc_collect (); - c_parser_external_declaration (parser); - obstack_free (&parser_obstack, obstack_position); - } - while (c_parser_next_token_is_not (parser, CPP_EOF)); - } - - unsigned int i; - tree decl; - FOR_EACH_VEC_ELT (incomplete_record_decls, i, decl) - if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node) - error ("storage size of %q+D isn%'t known", decl); - - if (current_omp_declare_target_attribute) - { - if (!errorcount) - error ("%<#pragma omp declare target%> without corresponding " - "%<#pragma omp end declare target%>"); - current_omp_declare_target_attribute = 0; - } -} - -/* Parse an external declaration (C90 6.7, C99 6.9, C11 6.9). - - external-declaration: - function-definition - declaration - - GNU extensions: - - external-declaration: - asm-definition - ; - __extension__ external-declaration - - Objective-C: - - external-declaration: - objc-class-definition - objc-class-declaration - objc-alias-declaration - objc-protocol-definition - objc-method-definition - @end -*/ - -static void -c_parser_external_declaration (c_parser *parser) -{ - int ext; - switch (c_parser_peek_token (parser)->type) - { - case CPP_KEYWORD: - switch (c_parser_peek_token (parser)->keyword) - { - case RID_EXTENSION: - ext = disable_extension_diagnostics (); - c_parser_consume_token (parser); - c_parser_external_declaration (parser); - restore_extension_diagnostics (ext); - break; - case RID_ASM: - c_parser_asm_definition (parser); - break; - case RID_AT_INTERFACE: - case RID_AT_IMPLEMENTATION: - gcc_assert (c_dialect_objc ()); - c_parser_objc_class_definition (parser, NULL_TREE); - break; - case RID_AT_CLASS: - gcc_assert (c_dialect_objc ()); - c_parser_objc_class_declaration (parser); - break; - case RID_AT_ALIAS: - gcc_assert (c_dialect_objc ()); - c_parser_objc_alias_declaration (parser); - break; - case RID_AT_PROTOCOL: - gcc_assert (c_dialect_objc ()); - c_parser_objc_protocol_definition (parser, NULL_TREE); - break; - case RID_AT_PROPERTY: - gcc_assert (c_dialect_objc ()); - c_parser_objc_at_property_declaration (parser); - break; - case RID_AT_SYNTHESIZE: - gcc_assert (c_dialect_objc ()); - c_parser_objc_at_synthesize_declaration (parser); - break; - case RID_AT_DYNAMIC: - gcc_assert (c_dialect_objc ()); - c_parser_objc_at_dynamic_declaration (parser); - break; - case RID_AT_END: - gcc_assert (c_dialect_objc ()); - c_parser_consume_token (parser); - objc_finish_implementation (); - break; - default: - goto decl_or_fndef; - } - break; - case CPP_SEMICOLON: - pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, - "ISO C does not allow extra %<;%> outside of a function"); - c_parser_consume_token (parser); - break; - case CPP_PRAGMA: - mark_valid_location_for_stdc_pragma (true); - c_parser_pragma (parser, pragma_external, NULL); - mark_valid_location_for_stdc_pragma (false); - break; - case CPP_PLUS: - case CPP_MINUS: - if (c_dialect_objc ()) - { - c_parser_objc_method_definition (parser); - break; - } - /* Else fall through, and yield a syntax error trying to parse - as a declaration or function definition. */ - /* FALLTHRU */ - default: - decl_or_fndef: - /* A declaration or a function definition (or, in Objective-C, - an @interface or @protocol with prefix attributes). We can - only tell which after parsing the declaration specifiers, if - any, and the first declarator. */ - c_parser_declaration_or_fndef (parser, true, true, true, false, true); - break; - } -} - -static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec *); -static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool); - -/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */ - -static void -add_debug_begin_stmt (location_t loc) -{ - /* Don't add DEBUG_BEGIN_STMTs outside of functions, see PR84721. */ - if (!MAY_HAVE_DEBUG_MARKER_STMTS || !building_stmt_list_p ()) - return; - - tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node); - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); -} - -/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 - 6.7, 6.9.1, C11 6.7, 6.9.1). If FNDEF_OK is true, a function definition - is accepted; otherwise (old-style parameter declarations) only other - declarations are accepted. If STATIC_ASSERT_OK is true, a static - assertion is accepted; otherwise (old-style parameter declarations) - it is not. If NESTED is true, we are inside a function or parsing - old-style parameter declarations; any functions encountered are - nested functions and declaration specifiers are required; otherwise - we are at top level and functions are normal functions and - declaration specifiers may be optional. If EMPTY_OK is true, empty - declarations are OK (subject to all other constraints); otherwise - (old-style parameter declarations) they are diagnosed. If - START_ATTR_OK is true, the declaration specifiers may start with - attributes (GNU or standard); otherwise they may not. - OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed - declaration when parsing an Objective-C foreach statement. - FALLTHRU_ATTR_P is used to signal whether this function parsed - "__attribute__((fallthrough));". ATTRS are any standard attributes - parsed in the caller (in contexts where such attributes had to be - parsed to determine whether what follows is a declaration or a - statement); HAVE_ATTRS says whether there were any such attributes - (even empty). - - declaration: - declaration-specifiers init-declarator-list[opt] ; - static_assert-declaration - - function-definition: - declaration-specifiers[opt] declarator declaration-list[opt] - compound-statement - - declaration-list: - declaration - declaration-list declaration - - init-declarator-list: - init-declarator - init-declarator-list , init-declarator - - init-declarator: - declarator simple-asm-expr[opt] gnu-attributes[opt] - declarator simple-asm-expr[opt] gnu-attributes[opt] = initializer - - GNU extensions: - - nested-function-definition: - declaration-specifiers declarator declaration-list[opt] - compound-statement - - attribute ; - - Objective-C: - gnu-attributes objc-class-definition - gnu-attributes objc-category-definition - gnu-attributes objc-protocol-definition - - The simple-asm-expr and gnu-attributes are GNU extensions. - - This function does not handle __extension__; that is handled in its - callers. ??? Following the old parser, __extension__ may start - external declarations, declarations in functions and declarations - at the start of "for" loops, but not old-style parameter - declarations. - - C99 requires declaration specifiers in a function definition; the - absence is diagnosed through the diagnosis of implicit int. In GNU - C we also allow but diagnose declarations without declaration - specifiers, but only at top level (elsewhere they conflict with - other syntax). - - In Objective-C, declarations of the looping variable in a foreach - statement are exceptionally terminated by 'in' (for example, 'for - (NSObject *object in array) { ... }'). - - OpenMP: - - declaration: - threadprivate-directive - - GIMPLE: - - gimple-function-definition: - declaration-specifiers[opt] __GIMPLE (gimple-or-rtl-pass-list) declarator - declaration-list[opt] compound-statement - - rtl-function-definition: - declaration-specifiers[opt] __RTL (gimple-or-rtl-pass-list) declarator - declaration-list[opt] compound-statement */ - -static void -c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, - bool static_assert_ok, bool empty_ok, - bool nested, bool start_attr_ok, - tree *objc_foreach_object_declaration - /* = NULL */, - vec *omp_declare_simd_clauses - /* = NULL */, - bool have_attrs /* = false */, - tree attrs /* = NULL_TREE */, - struct oacc_routine_data *oacc_routine_data - /* = NULL */, - bool *fallthru_attr_p /* = NULL */) -{ - struct c_declspecs *specs; - tree prefix_attrs; - tree all_prefix_attrs; - bool diagnosed_no_specs = false; - location_t here = c_parser_peek_token (parser)->location; - - add_debug_begin_stmt (c_parser_peek_token (parser)->location); - - if (static_assert_ok - && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) - { - c_parser_static_assert_declaration (parser); - return; - } - specs = build_null_declspecs (); - - /* Handle any standard attributes parsed in the caller. */ - if (have_attrs) - { - declspecs_add_attrs (here, specs, attrs); - specs->non_std_attrs_seen_p = false; - } - - /* Try to detect an unknown type name when we have "A B" or "A *B". */ - if (c_parser_peek_token (parser)->type == CPP_NAME - && c_parser_peek_token (parser)->id_kind == C_ID_ID - && (c_parser_peek_2nd_token (parser)->type == CPP_NAME - || c_parser_peek_2nd_token (parser)->type == CPP_MULT) - && (!nested || !lookup_name (c_parser_peek_token (parser)->value))) - { - tree name = c_parser_peek_token (parser)->value; - - /* Issue a warning about NAME being an unknown type name, perhaps - with some kind of hint. - If the user forgot a "struct" etc, suggest inserting - it. Otherwise, attempt to look for misspellings. */ - gcc_rich_location richloc (here); - if (tag_exists_p (RECORD_TYPE, name)) - { - /* This is not C++ with its implicit typedef. */ - richloc.add_fixit_insert_before ("struct "); - error_at (&richloc, - "unknown type name %qE;" - " use % keyword to refer to the type", - name); - } - else if (tag_exists_p (UNION_TYPE, name)) - { - richloc.add_fixit_insert_before ("union "); - error_at (&richloc, - "unknown type name %qE;" - " use % keyword to refer to the type", - name); - } - else if (tag_exists_p (ENUMERAL_TYPE, name)) - { - richloc.add_fixit_insert_before ("enum "); - error_at (&richloc, - "unknown type name %qE;" - " use % keyword to refer to the type", - name); - } - else - { - auto_diagnostic_group d; - name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME, - here); - if (const char *suggestion = hint.suggestion ()) - { - richloc.add_fixit_replace (suggestion); - error_at (&richloc, - "unknown type name %qE; did you mean %qs?", - name, suggestion); - } - else - error_at (here, "unknown type name %qE", name); - } - - /* Parse declspecs normally to get a correct pointer type, but avoid - a further "fails to be a type name" error. Refuse nested functions - since it is not how the user likely wants us to recover. */ - c_parser_peek_token (parser)->type = CPP_KEYWORD; - c_parser_peek_token (parser)->keyword = RID_VOID; - c_parser_peek_token (parser)->value = error_mark_node; - fndef_ok = !nested; - } - - /* When there are standard attributes at the start of the - declaration (to apply to the entity being declared), an - init-declarator-list or function definition must be present. */ - if (c_parser_nth_token_starts_std_attributes (parser, 1)) - have_attrs = true; - - c_parser_declspecs (parser, specs, true, true, start_attr_ok, - true, true, start_attr_ok, true, cla_nonabstract_decl); - if (parser->error) - { - c_parser_skip_to_end_of_block_or_statement (parser); - return; - } - if (nested && !specs->declspecs_seen_p) - { - c_parser_error (parser, "expected declaration specifiers"); - c_parser_skip_to_end_of_block_or_statement (parser); - return; - } - - finish_declspecs (specs); - bool auto_type_p = specs->typespec_word == cts_auto_type; - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - if (auto_type_p) - error_at (here, "%<__auto_type%> in empty declaration"); - else if (specs->typespec_kind == ctsk_none - && attribute_fallthrough_p (specs->attrs)) - { - if (fallthru_attr_p != NULL) - *fallthru_attr_p = true; - if (nested) - { - tree fn = build_call_expr_internal_loc (here, IFN_FALLTHROUGH, - void_type_node, 0); - add_stmt (fn); - } - else - pedwarn (here, OPT_Wattributes, - "% attribute at top level"); - } - else if (empty_ok && !(have_attrs - && specs->non_std_attrs_seen_p)) - shadow_tag (specs); - else - { - shadow_tag_warned (specs, 1); - pedwarn (here, 0, "empty declaration"); - } - c_parser_consume_token (parser); - if (oacc_routine_data) - c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); - return; - } - - /* Provide better error recovery. Note that a type name here is usually - better diagnosed as a redeclaration. */ - if (empty_ok - && specs->typespec_kind == ctsk_tagdef - && c_parser_next_token_starts_declspecs (parser) - && !c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected %<;%>, identifier or %<(%>"); - parser->error = false; - shadow_tag_warned (specs, 1); - return; - } - else if (c_dialect_objc () && !auto_type_p) - { - /* Prefix attributes are an error on method decls. */ - switch (c_parser_peek_token (parser)->type) - { - case CPP_PLUS: - case CPP_MINUS: - if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) - return; - if (specs->attrs) - { - warning_at (c_parser_peek_token (parser)->location, - OPT_Wattributes, - "prefix attributes are ignored for methods"); - specs->attrs = NULL_TREE; - } - if (fndef_ok) - c_parser_objc_method_definition (parser); - else - c_parser_objc_methodproto (parser); - return; - break; - default: - break; - } - /* This is where we parse 'attributes @interface ...', - 'attributes @implementation ...', 'attributes @protocol ...' - (where attributes could be, for example, __attribute__ - ((deprecated)). - */ - switch (c_parser_peek_token (parser)->keyword) - { - case RID_AT_INTERFACE: - { - if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) - return; - c_parser_objc_class_definition (parser, specs->attrs); - return; - } - break; - case RID_AT_IMPLEMENTATION: - { - if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) - return; - if (specs->attrs) - { - warning_at (c_parser_peek_token (parser)->location, - OPT_Wattributes, - "prefix attributes are ignored for implementations"); - specs->attrs = NULL_TREE; - } - c_parser_objc_class_definition (parser, NULL_TREE); - return; - } - break; - case RID_AT_PROTOCOL: - { - if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) - return; - c_parser_objc_protocol_definition (parser, specs->attrs); - return; - } - break; - case RID_AT_ALIAS: - case RID_AT_CLASS: - case RID_AT_END: - case RID_AT_PROPERTY: - if (specs->attrs) - { - c_parser_error (parser, "unexpected attribute"); - specs->attrs = NULL; - } - break; - default: - break; - } - } - else if (attribute_fallthrough_p (specs->attrs)) - warning_at (here, OPT_Wattributes, - "% attribute not followed by %<;%>"); - - pending_xref_error (); - prefix_attrs = specs->attrs; - all_prefix_attrs = prefix_attrs; - specs->attrs = NULL_TREE; - while (true) - { - struct c_declarator *declarator; - bool dummy = false; - timevar_id_t tv; - tree fnbody = NULL_TREE; - /* Declaring either one or more declarators (in which case we - should diagnose if there were no declaration specifiers) or a - function definition (in which case the diagnostic for - implicit int suffices). */ - declarator = c_parser_declarator (parser, - specs->typespec_kind != ctsk_none, - C_DTR_NORMAL, &dummy); - if (declarator == NULL) - { - if (omp_declare_simd_clauses) - c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE, - omp_declare_simd_clauses); - if (oacc_routine_data) - c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); - c_parser_skip_to_end_of_block_or_statement (parser); - return; - } - if (auto_type_p && declarator->kind != cdk_id) - { - error_at (here, - "%<__auto_type%> requires a plain identifier" - " as declarator"); - c_parser_skip_to_end_of_block_or_statement (parser); - return; - } - if (c_parser_next_token_is (parser, CPP_EQ) - || c_parser_next_token_is (parser, CPP_COMMA) - || c_parser_next_token_is (parser, CPP_SEMICOLON) - || c_parser_next_token_is_keyword (parser, RID_ASM) - || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE) - || c_parser_next_token_is_keyword (parser, RID_IN)) - { - tree asm_name = NULL_TREE; - tree postfix_attrs = NULL_TREE; - if (!diagnosed_no_specs && !specs->declspecs_seen_p) - { - diagnosed_no_specs = true; - pedwarn (here, 0, "data definition has no type or storage class"); - } - /* Having seen a data definition, there cannot now be a - function definition. */ - fndef_ok = false; - if (c_parser_next_token_is_keyword (parser, RID_ASM)) - asm_name = c_parser_simple_asm_expr (parser); - if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - { - postfix_attrs = c_parser_gnu_attributes (parser); - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - { - /* This means there is an attribute specifier after - the declarator in a function definition. Provide - some more information for the user. */ - error_at (here, "attributes should be specified before the " - "declarator in a function definition"); - c_parser_skip_to_end_of_block_or_statement (parser); - return; - } - } - if (c_parser_next_token_is (parser, CPP_EQ)) - { - tree d; - struct c_expr init; - location_t init_loc; - c_parser_consume_token (parser); - if (auto_type_p) - { - init_loc = c_parser_peek_token (parser)->location; - rich_location richloc (line_table, init_loc); - start_init (NULL_TREE, asm_name, global_bindings_p (), &richloc); - /* A parameter is initialized, which is invalid. Don't - attempt to instrument the initializer. */ - int flag_sanitize_save = flag_sanitize; - if (nested && !empty_ok) - flag_sanitize = 0; - init = c_parser_expr_no_commas (parser, NULL); - flag_sanitize = flag_sanitize_save; - if (TREE_CODE (init.value) == COMPONENT_REF - && DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1))) - error_at (here, - "%<__auto_type%> used with a bit-field" - " initializer"); - init = convert_lvalue_to_rvalue (init_loc, init, true, true); - tree init_type = TREE_TYPE (init.value); - bool vm_type = variably_modified_type_p (init_type, - NULL_TREE); - if (vm_type) - init.value = save_expr (init.value); - finish_init (); - specs->typespec_kind = ctsk_typeof; - specs->locations[cdw_typedef] = init_loc; - specs->typedef_p = true; - specs->type = init_type; - if (vm_type) - { - bool maybe_const = true; - tree type_expr = c_fully_fold (init.value, false, - &maybe_const); - specs->expr_const_operands &= maybe_const; - if (specs->expr) - specs->expr = build2 (COMPOUND_EXPR, - TREE_TYPE (type_expr), - specs->expr, type_expr); - else - specs->expr = type_expr; - } - d = start_decl (declarator, specs, true, - chainon (postfix_attrs, all_prefix_attrs)); - if (!d) - d = error_mark_node; - if (omp_declare_simd_clauses) - c_finish_omp_declare_simd (parser, d, NULL_TREE, - omp_declare_simd_clauses); - } - else - { - /* The declaration of the variable is in effect while - its initializer is parsed. */ - d = start_decl (declarator, specs, true, - chainon (postfix_attrs, all_prefix_attrs)); - if (!d) - d = error_mark_node; - if (omp_declare_simd_clauses) - c_finish_omp_declare_simd (parser, d, NULL_TREE, - omp_declare_simd_clauses); - init_loc = c_parser_peek_token (parser)->location; - rich_location richloc (line_table, init_loc); - start_init (d, asm_name, global_bindings_p (), &richloc); - /* A parameter is initialized, which is invalid. Don't - attempt to instrument the initializer. */ - int flag_sanitize_save = flag_sanitize; - if (TREE_CODE (d) == PARM_DECL) - flag_sanitize = 0; - init = c_parser_initializer (parser); - flag_sanitize = flag_sanitize_save; - finish_init (); - } - if (oacc_routine_data) - c_finish_oacc_routine (oacc_routine_data, d, false); - if (d != error_mark_node) - { - maybe_warn_string_init (init_loc, TREE_TYPE (d), init); - finish_decl (d, init_loc, init.value, - init.original_type, asm_name); - } - } - else - { - if (auto_type_p) - { - error_at (here, - "%<__auto_type%> requires an initialized " - "data declaration"); - c_parser_skip_to_end_of_block_or_statement (parser); - return; - } - - location_t lastloc = UNKNOWN_LOCATION; - tree attrs = chainon (postfix_attrs, all_prefix_attrs); - tree d = start_decl (declarator, specs, false, attrs, &lastloc); - if (d && TREE_CODE (d) == FUNCTION_DECL) - { - /* Find the innermost declarator that is neither cdk_id - nor cdk_attrs. */ - const struct c_declarator *decl = declarator; - const struct c_declarator *last_non_id_attrs = NULL; - - while (decl) - switch (decl->kind) - { - case cdk_array: - case cdk_function: - case cdk_pointer: - last_non_id_attrs = decl; - decl = decl->declarator; - break; - - case cdk_attrs: - decl = decl->declarator; - break; - - case cdk_id: - decl = 0; - break; - - default: - gcc_unreachable (); - } - - /* If it exists and is cdk_function declaration whose - arguments have not been set yet, use its arguments. */ - if (last_non_id_attrs - && last_non_id_attrs->kind == cdk_function) - { - tree parms = last_non_id_attrs->u.arg_info->parms; - if (DECL_ARGUMENTS (d) == NULL_TREE - && DECL_INITIAL (d) == NULL_TREE) - DECL_ARGUMENTS (d) = parms; - - warn_parm_array_mismatch (lastloc, d, parms); - } - } - if (omp_declare_simd_clauses) - { - tree parms = NULL_TREE; - if (d && TREE_CODE (d) == FUNCTION_DECL) - { - struct c_declarator *ce = declarator; - while (ce != NULL) - if (ce->kind == cdk_function) - { - parms = ce->u.arg_info->parms; - break; - } - else - ce = ce->declarator; - } - if (parms) - temp_store_parm_decls (d, parms); - c_finish_omp_declare_simd (parser, d, parms, - omp_declare_simd_clauses); - if (parms) - temp_pop_parm_decls (); - } - if (oacc_routine_data) - c_finish_oacc_routine (oacc_routine_data, d, false); - if (d) - finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, - NULL_TREE, asm_name); - - if (c_parser_next_token_is_keyword (parser, RID_IN)) - { - if (d) - *objc_foreach_object_declaration = d; - else - *objc_foreach_object_declaration = error_mark_node; - } - } - if (c_parser_next_token_is (parser, CPP_COMMA)) - { - if (auto_type_p) - { - error_at (here, - "%<__auto_type%> may only be used with" - " a single declarator"); - c_parser_skip_to_end_of_block_or_statement (parser); - return; - } - c_parser_consume_token (parser); - if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - all_prefix_attrs = chainon (c_parser_gnu_attributes (parser), - prefix_attrs); - else - all_prefix_attrs = prefix_attrs; - continue; - } - else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - c_parser_consume_token (parser); - return; - } - else if (c_parser_next_token_is_keyword (parser, RID_IN)) - { - /* This can only happen in Objective-C: we found the - 'in' that terminates the declaration inside an - Objective-C foreach statement. Do not consume the - token, so that the caller can use it to determine - that this indeed is a foreach context. */ - return; - } - else - { - c_parser_error (parser, "expected %<,%> or %<;%>"); - c_parser_skip_to_end_of_block_or_statement (parser); - return; - } - } - else if (auto_type_p) - { - error_at (here, - "%<__auto_type%> requires an initialized data declaration"); - c_parser_skip_to_end_of_block_or_statement (parser); - return; - } - else if (!fndef_ok) - { - c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, " - "% or %<__attribute__%>"); - c_parser_skip_to_end_of_block_or_statement (parser); - return; - } - /* Function definition (nested or otherwise). */ - if (nested) - { - pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions"); - c_push_function_context (); - } - if (!start_function (specs, declarator, all_prefix_attrs)) - { - /* At this point we've consumed: - declaration-specifiers declarator - and the next token isn't CPP_EQ, CPP_COMMA, CPP_SEMICOLON, - RID_ASM, RID_ATTRIBUTE, or RID_IN, - but the - declaration-specifiers declarator - aren't grokkable as a function definition, so we have - an error. */ - gcc_assert (!c_parser_next_token_is (parser, CPP_SEMICOLON)); - if (c_parser_next_token_starts_declspecs (parser)) - { - /* If we have - declaration-specifiers declarator decl-specs - then assume we have a missing semicolon, which would - give us: - declaration-specifiers declarator decl-specs - ^ - ; - <~~~~~~~~~ declaration ~~~~~~~~~~> - Use c_parser_require to get an error with a fix-it hint. */ - c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"); - parser->error = false; - } - else - { - /* This can appear in many cases looking nothing like a - function definition, so we don't give a more specific - error suggesting there was one. */ - c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, % " - "or %<__attribute__%>"); - } - if (nested) - c_pop_function_context (); - break; - } - - if (DECL_DECLARED_INLINE_P (current_function_decl)) - tv = TV_PARSE_INLINE; - else - tv = TV_PARSE_FUNC; - auto_timevar at (g_timer, tv); - - /* Parse old-style parameter declarations. ??? Attributes are - not allowed to start declaration specifiers here because of a - syntax conflict between a function declaration with attribute - suffix and a function definition with an attribute prefix on - first old-style parameter declaration. Following the old - parser, they are not accepted on subsequent old-style - parameter declarations either. However, there is no - ambiguity after the first declaration, nor indeed on the - first as long as we don't allow postfix attributes after a - declarator with a nonempty identifier list in a definition; - and postfix attributes have never been accepted here in - function definitions either. */ - while (c_parser_next_token_is_not (parser, CPP_EOF) - && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE)) - c_parser_declaration_or_fndef (parser, false, false, false, - true, false); - store_parm_decls (); - if (omp_declare_simd_clauses) - c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE, - omp_declare_simd_clauses); - if (oacc_routine_data) - c_finish_oacc_routine (oacc_routine_data, current_function_decl, true); - location_t startloc = c_parser_peek_token (parser)->location; - DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus - = startloc; - location_t endloc = startloc; - - /* If the definition was marked with __RTL, use the RTL parser now, - consuming the function body. */ - if (specs->declspec_il == cdil_rtl) - { - endloc = c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass); - - /* Normally, store_parm_decls sets next_is_function_body, - anticipating a function body. We need a push_scope/pop_scope - pair to flush out this state, or subsequent function parsing - will go wrong. */ - push_scope (); - pop_scope (); - - finish_function (endloc); - return; - } - /* If the definition was marked with __GIMPLE then parse the - function body as GIMPLE. */ - else if (specs->declspec_il != cdil_none) - { - bool saved = in_late_binary_op; - in_late_binary_op = true; - c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass, - specs->declspec_il, - specs->entry_bb_count); - in_late_binary_op = saved; - } - else - fnbody = c_parser_compound_statement (parser, &endloc); - tree fndecl = current_function_decl; - if (nested) - { - tree decl = current_function_decl; - /* Mark nested functions as needing static-chain initially. - lower_nested_functions will recompute it but the - DECL_STATIC_CHAIN flag is also used before that happens, - by initializer_constant_valid_p. See gcc.dg/nested-fn-2.c. */ - DECL_STATIC_CHAIN (decl) = 1; - add_stmt (fnbody); - finish_function (endloc); - c_pop_function_context (); - add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); - } - else - { - if (fnbody) - add_stmt (fnbody); - finish_function (endloc); - } - /* Get rid of the empty stmt list for GIMPLE/RTL. */ - if (specs->declspec_il != cdil_none) - DECL_SAVED_TREE (fndecl) = NULL_TREE; - - break; - } -} - -/* Parse an asm-definition (asm() outside a function body). This is a - GNU extension. - - asm-definition: - simple-asm-expr ; -*/ - -static void -c_parser_asm_definition (c_parser *parser) -{ - tree asm_str = c_parser_simple_asm_expr (parser); - if (asm_str) - symtab->finalize_toplevel_asm (asm_str); - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); -} - -/* Parse a static assertion (C11 6.7.10). - - static_assert-declaration: - static_assert-declaration-no-semi ; -*/ - -static void -c_parser_static_assert_declaration (c_parser *parser) -{ - c_parser_static_assert_declaration_no_semi (parser); - if (parser->error - || !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) - c_parser_skip_to_end_of_block_or_statement (parser); -} - -/* Parse a static assertion (C11 6.7.10), without the trailing - semicolon. - - static_assert-declaration-no-semi: - _Static_assert ( constant-expression , string-literal ) - - C2X: - static_assert-declaration-no-semi: - _Static_assert ( constant-expression ) -*/ - -static void -c_parser_static_assert_declaration_no_semi (c_parser *parser) -{ - location_t assert_loc, value_loc; - tree value; - tree string = NULL_TREE; - - gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)); - assert_loc = c_parser_peek_token (parser)->location; - if (flag_isoc99) - pedwarn_c99 (assert_loc, OPT_Wpedantic, - "ISO C99 does not support %<_Static_assert%>"); - else - pedwarn_c99 (assert_loc, OPT_Wpedantic, - "ISO C90 does not support %<_Static_assert%>"); - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - return; - location_t value_tok_loc = c_parser_peek_token (parser)->location; - value = c_parser_expr_no_commas (parser, NULL).value; - value_loc = EXPR_LOC_OR_LOC (value, value_tok_loc); - if (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - switch (c_parser_peek_token (parser)->type) - { - case CPP_STRING: - case CPP_STRING16: - case CPP_STRING32: - case CPP_WSTRING: - case CPP_UTF8STRING: - string = c_parser_string_literal (parser, false, true).value; - break; - default: - c_parser_error (parser, "expected string literal"); - return; - } - } - else if (flag_isoc11) - /* If pedantic for pre-C11, the use of _Static_assert itself will - have been diagnosed, so do not also diagnose the use of this - new C2X feature of _Static_assert. */ - pedwarn_c11 (assert_loc, OPT_Wpedantic, - "ISO C11 does not support omitting the string in " - "%<_Static_assert%>"); - parens.require_close (parser); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (value))) - { - error_at (value_loc, "expression in static assertion is not an integer"); - return; - } - if (TREE_CODE (value) != INTEGER_CST) - { - value = c_fully_fold (value, false, NULL); - /* Strip no-op conversions. */ - STRIP_TYPE_NOPS (value); - if (TREE_CODE (value) == INTEGER_CST) - pedwarn (value_loc, OPT_Wpedantic, "expression in static assertion " - "is not an integer constant expression"); - } - if (TREE_CODE (value) != INTEGER_CST) - { - error_at (value_loc, "expression in static assertion is not constant"); - return; - } - constant_expression_warning (value); - if (integer_zerop (value)) - { - if (string) - error_at (assert_loc, "static assertion failed: %E", string); - else - error_at (assert_loc, "static assertion failed"); - } -} - -/* Parse some declaration specifiers (possibly none) (C90 6.5, C99 - 6.7, C11 6.7), adding them to SPECS (which may already include some). - Storage class specifiers are accepted iff SCSPEC_OK; type - specifiers are accepted iff TYPESPEC_OK; alignment specifiers are - accepted iff ALIGNSPEC_OK; gnu-attributes are accepted at the start - iff START_ATTR_OK; __auto_type is accepted iff AUTO_TYPE_OK. In - addition to the syntax shown, standard attributes are accepted at - the start iff START_STD_ATTR_OK and at the end iff END_STD_ATTR_OK; - unlike gnu-attributes, they are not accepted in the middle of the - list. (This combines various different syntax productions in the C - standard, and in some cases gnu-attributes and standard attributes - at the start may already have been parsed before this function is - called.) - - declaration-specifiers: - storage-class-specifier declaration-specifiers[opt] - type-specifier declaration-specifiers[opt] - type-qualifier declaration-specifiers[opt] - function-specifier declaration-specifiers[opt] - alignment-specifier declaration-specifiers[opt] - - Function specifiers (inline) are from C99, and are currently - handled as storage class specifiers, as is __thread. Alignment - specifiers are from C11. - - C90 6.5.1, C99 6.7.1, C11 6.7.1: - storage-class-specifier: - typedef - extern - static - auto - register - _Thread_local - - (_Thread_local is new in C11.) - - C99 6.7.4, C11 6.7.4: - function-specifier: - inline - _Noreturn - - (_Noreturn is new in C11.) - - C90 6.5.2, C99 6.7.2, C11 6.7.2: - type-specifier: - void - char - short - int - long - float - double - signed - unsigned - _Bool - _Complex - [_Imaginary removed in C99 TC2] - struct-or-union-specifier - enum-specifier - typedef-name - atomic-type-specifier - - (_Bool and _Complex are new in C99.) - (atomic-type-specifier is new in C11.) - - C90 6.5.3, C99 6.7.3, C11 6.7.3: - - type-qualifier: - const - restrict - volatile - address-space-qualifier - _Atomic - - (restrict is new in C99.) - (_Atomic is new in C11.) - - GNU extensions: - - declaration-specifiers: - gnu-attributes declaration-specifiers[opt] - - type-qualifier: - address-space - - address-space: - identifier recognized by the target - - storage-class-specifier: - __thread - - type-specifier: - typeof-specifier - __auto_type - __intN - _Decimal32 - _Decimal64 - _Decimal128 - _Fract - _Accum - _Sat - - (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037: - http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf) - - atomic-type-specifier - _Atomic ( type-name ) - - Objective-C: - - type-specifier: - class-name objc-protocol-refs[opt] - typedef-name objc-protocol-refs - objc-protocol-refs -*/ - -void -c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, - bool scspec_ok, bool typespec_ok, bool start_attr_ok, - bool alignspec_ok, bool auto_type_ok, - bool start_std_attr_ok, bool end_std_attr_ok, - enum c_lookahead_kind la) -{ - bool attrs_ok = start_attr_ok; - bool seen_type = specs->typespec_kind != ctsk_none; - - if (!typespec_ok) - gcc_assert (la == cla_prefer_id); - - if (start_std_attr_ok - && c_parser_nth_token_starts_std_attributes (parser, 1)) - { - gcc_assert (!specs->non_std_attrs_seen_p); - location_t loc = c_parser_peek_token (parser)->location; - tree attrs = c_parser_std_attribute_specifier_sequence (parser); - declspecs_add_attrs (loc, specs, attrs); - specs->non_std_attrs_seen_p = false; - } - - while (c_parser_next_token_is (parser, CPP_NAME) - || c_parser_next_token_is (parser, CPP_KEYWORD) - || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS))) - { - struct c_typespec t; - tree attrs; - tree align; - location_t loc = c_parser_peek_token (parser)->location; - - /* If we cannot accept a type, exit if the next token must start - one. Also, if we already have seen a tagged definition, - a typename would be an error anyway and likely the user - has simply forgotten a semicolon, so we exit. */ - if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef) - && c_parser_next_tokens_start_typename (parser, la) - && !c_parser_next_token_is_qualifier (parser) - && !c_parser_next_token_is_keyword (parser, RID_ALIGNAS)) - break; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - c_token *name_token = c_parser_peek_token (parser); - tree value = name_token->value; - c_id_kind kind = name_token->id_kind; - - if (kind == C_ID_ADDRSPACE) - { - addr_space_t as - = name_token->keyword - RID_FIRST_ADDR_SPACE; - declspecs_add_addrspace (name_token->location, specs, as); - c_parser_consume_token (parser); - attrs_ok = true; - continue; - } - - gcc_assert (!c_parser_next_token_is_qualifier (parser)); - - /* If we cannot accept a type, and the next token must start one, - exit. Do the same if we already have seen a tagged definition, - since it would be an error anyway and likely the user has simply - forgotten a semicolon. */ - if (seen_type || !c_parser_next_tokens_start_typename (parser, la)) - break; - - /* Now at an unknown typename (C_ID_ID), a C_ID_TYPENAME or - a C_ID_CLASSNAME. */ - c_parser_consume_token (parser); - seen_type = true; - attrs_ok = true; - if (kind == C_ID_ID) - { - error_at (loc, "unknown type name %qE", value); - t.kind = ctsk_typedef; - t.spec = error_mark_node; - } - else if (kind == C_ID_TYPENAME - && (!c_dialect_objc () - || c_parser_next_token_is_not (parser, CPP_LESS))) - { - t.kind = ctsk_typedef; - /* For a typedef name, record the meaning, not the name. - In case of 'foo foo, bar;'. */ - t.spec = lookup_name (value); - } - else - { - tree proto = NULL_TREE; - gcc_assert (c_dialect_objc ()); - t.kind = ctsk_objc; - if (c_parser_next_token_is (parser, CPP_LESS)) - proto = c_parser_objc_protocol_refs (parser); - t.spec = objc_get_protocol_qualified_type (value, proto); - } - t.expr = NULL_TREE; - t.expr_const_operands = true; - declspecs_add_type (name_token->location, specs, t); - continue; - } - if (c_parser_next_token_is (parser, CPP_LESS)) - { - /* Make "" equivalent to "id " - - nisse@lysator.liu.se. */ - tree proto; - gcc_assert (c_dialect_objc ()); - if (!typespec_ok || seen_type) - break; - proto = c_parser_objc_protocol_refs (parser); - t.kind = ctsk_objc; - t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto); - t.expr = NULL_TREE; - t.expr_const_operands = true; - declspecs_add_type (loc, specs, t); - continue; - } - gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD)); - switch (c_parser_peek_token (parser)->keyword) - { - case RID_STATIC: - case RID_EXTERN: - case RID_REGISTER: - case RID_TYPEDEF: - case RID_INLINE: - case RID_NORETURN: - case RID_AUTO: - case RID_THREAD: - if (!scspec_ok) - goto out; - attrs_ok = true; - /* TODO: Distinguish between function specifiers (inline, noreturn) - and storage class specifiers, either here or in - declspecs_add_scspec. */ - declspecs_add_scspec (loc, specs, - c_parser_peek_token (parser)->value); - c_parser_consume_token (parser); - break; - case RID_AUTO_TYPE: - if (!auto_type_ok) - goto out; - /* Fall through. */ - case RID_UNSIGNED: - case RID_LONG: - case RID_SHORT: - case RID_SIGNED: - case RID_COMPLEX: - case RID_INT: - case RID_CHAR: - case RID_FLOAT: - case RID_DOUBLE: - case RID_VOID: - case RID_DFLOAT32: - case RID_DFLOAT64: - case RID_DFLOAT128: - CASE_RID_FLOATN_NX: - case RID_BOOL: - case RID_FRACT: - case RID_ACCUM: - case RID_SAT: - case RID_INT_N_0: - case RID_INT_N_1: - case RID_INT_N_2: - case RID_INT_N_3: - if (!typespec_ok) - goto out; - attrs_ok = true; - seen_type = true; - if (c_dialect_objc ()) - parser->objc_need_raw_identifier = true; - t.kind = ctsk_resword; - t.spec = c_parser_peek_token (parser)->value; - t.expr = NULL_TREE; - t.expr_const_operands = true; - declspecs_add_type (loc, specs, t); - c_parser_consume_token (parser); - break; - case RID_ENUM: - if (!typespec_ok) - goto out; - attrs_ok = true; - seen_type = true; - t = c_parser_enum_specifier (parser); - invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec); - declspecs_add_type (loc, specs, t); - break; - case RID_STRUCT: - case RID_UNION: - if (!typespec_ok) - goto out; - attrs_ok = true; - seen_type = true; - t = c_parser_struct_or_union_specifier (parser); - invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec); - declspecs_add_type (loc, specs, t); - break; - case RID_TYPEOF: - /* ??? The old parser rejected typeof after other type - specifiers, but is a syntax error the best way of - handling this? */ - if (!typespec_ok || seen_type) - goto out; - attrs_ok = true; - seen_type = true; - t = c_parser_typeof_specifier (parser); - declspecs_add_type (loc, specs, t); - break; - case RID_ATOMIC: - /* C parser handling of Objective-C constructs needs - checking for correct lvalue-to-rvalue conversions, and - the code in build_modify_expr handling various - Objective-C cases, and that in build_unary_op handling - Objective-C cases for increment / decrement, also needs - updating; uses of TYPE_MAIN_VARIANT in objc_compare_types - and objc_types_are_equivalent may also need updates. */ - if (c_dialect_objc ()) - sorry ("%<_Atomic%> in Objective-C"); - if (flag_isoc99) - pedwarn_c99 (loc, OPT_Wpedantic, - "ISO C99 does not support the %<_Atomic%> qualifier"); - else - pedwarn_c99 (loc, OPT_Wpedantic, - "ISO C90 does not support the %<_Atomic%> qualifier"); - attrs_ok = true; - tree value; - value = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - if (typespec_ok && c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - /* _Atomic ( type-name ). */ - seen_type = true; - c_parser_consume_token (parser); - struct c_type_name *type = c_parser_type_name (parser); - t.kind = ctsk_typeof; - t.spec = error_mark_node; - t.expr = NULL_TREE; - t.expr_const_operands = true; - if (type != NULL) - t.spec = groktypename (type, &t.expr, - &t.expr_const_operands); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - if (t.spec != error_mark_node) - { - if (TREE_CODE (t.spec) == ARRAY_TYPE) - error_at (loc, "%<_Atomic%>-qualified array type"); - else if (TREE_CODE (t.spec) == FUNCTION_TYPE) - error_at (loc, "%<_Atomic%>-qualified function type"); - else if (TYPE_QUALS (t.spec) != TYPE_UNQUALIFIED) - error_at (loc, "%<_Atomic%> applied to a qualified type"); - else - t.spec = c_build_qualified_type (t.spec, TYPE_QUAL_ATOMIC); - } - declspecs_add_type (loc, specs, t); - } - else - declspecs_add_qual (loc, specs, value); - break; - case RID_CONST: - case RID_VOLATILE: - case RID_RESTRICT: - attrs_ok = true; - declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value); - c_parser_consume_token (parser); - break; - case RID_ATTRIBUTE: - if (!attrs_ok) - goto out; - attrs = c_parser_gnu_attributes (parser); - declspecs_add_attrs (loc, specs, attrs); - break; - case RID_ALIGNAS: - if (!alignspec_ok) - goto out; - align = c_parser_alignas_specifier (parser); - declspecs_add_alignas (loc, specs, align); - break; - case RID_GIMPLE: - if (! flag_gimple) - error_at (loc, "%<__GIMPLE%> only valid with %<-fgimple%>"); - c_parser_consume_token (parser); - specs->declspec_il = cdil_gimple; - specs->locations[cdw_gimple] = loc; - c_parser_gimple_or_rtl_pass_list (parser, specs); - break; - case RID_RTL: - c_parser_consume_token (parser); - specs->declspec_il = cdil_rtl; - specs->locations[cdw_rtl] = loc; - c_parser_gimple_or_rtl_pass_list (parser, specs); - break; - default: - goto out; - } - } - out: - if (end_std_attr_ok - && c_parser_nth_token_starts_std_attributes (parser, 1)) - specs->postfix_attrs = c_parser_std_attribute_specifier_sequence (parser); -} - -/* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2, C11 6.7.2.2). - - enum-specifier: - enum gnu-attributes[opt] identifier[opt] { enumerator-list } - gnu-attributes[opt] - enum gnu-attributes[opt] identifier[opt] { enumerator-list , } - gnu-attributes[opt] - enum gnu-attributes[opt] identifier - - The form with trailing comma is new in C99. The forms with - gnu-attributes are GNU extensions. In GNU C, we accept any expression - without commas in the syntax (assignment expressions, not just - conditional expressions); assignment expressions will be diagnosed - as non-constant. - - enumerator-list: - enumerator - enumerator-list , enumerator - - enumerator: - enumeration-constant attribute-specifier-sequence[opt] - enumeration-constant attribute-specifier-sequence[opt] - = constant-expression - - GNU Extensions: - - enumerator: - enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt] - enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt] - = constant-expression - -*/ - -static struct c_typespec -c_parser_enum_specifier (c_parser *parser) -{ - struct c_typespec ret; - bool have_std_attrs; - tree std_attrs = NULL_TREE; - tree attrs; - tree ident = NULL_TREE; - location_t enum_loc; - location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */ - gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); - c_parser_consume_token (parser); - have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); - if (have_std_attrs) - std_attrs = c_parser_std_attribute_specifier_sequence (parser); - attrs = c_parser_gnu_attributes (parser); - enum_loc = c_parser_peek_token (parser)->location; - /* Set the location in case we create a decl now. */ - c_parser_set_source_position_from_token (c_parser_peek_token (parser)); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - ident = c_parser_peek_token (parser)->value; - ident_loc = c_parser_peek_token (parser)->location; - enum_loc = ident_loc; - c_parser_consume_token (parser); - } - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - { - /* Parse an enum definition. */ - struct c_enum_contents the_enum; - tree type; - tree postfix_attrs; - /* We chain the enumerators in reverse order, then put them in - forward order at the end. */ - tree values; - timevar_push (TV_PARSE_ENUM); - type = start_enum (enum_loc, &the_enum, ident); - values = NULL_TREE; - c_parser_consume_token (parser); - while (true) - { - tree enum_id; - tree enum_value; - tree enum_decl; - bool seen_comma; - c_token *token; - location_t comma_loc = UNKNOWN_LOCATION; /* Quiet warning. */ - location_t decl_loc, value_loc; - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - /* Give a nicer error for "enum {}". */ - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE) - && !parser->error) - { - error_at (c_parser_peek_token (parser)->location, - "empty enum is invalid"); - parser->error = true; - } - else - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); - values = error_mark_node; - break; - } - token = c_parser_peek_token (parser); - enum_id = token->value; - /* Set the location in case we create a decl now. */ - c_parser_set_source_position_from_token (token); - decl_loc = value_loc = token->location; - c_parser_consume_token (parser); - /* Parse any specified attributes. */ - tree std_attrs = NULL_TREE; - if (c_parser_nth_token_starts_std_attributes (parser, 1)) - std_attrs = c_parser_std_attribute_specifier_sequence (parser); - tree enum_attrs = chainon (std_attrs, - c_parser_gnu_attributes (parser)); - if (c_parser_next_token_is (parser, CPP_EQ)) - { - c_parser_consume_token (parser); - value_loc = c_parser_peek_token (parser)->location; - enum_value = c_parser_expr_no_commas (parser, NULL).value; - } - else - enum_value = NULL_TREE; - enum_decl = build_enumerator (decl_loc, value_loc, - &the_enum, enum_id, enum_value); - if (enum_attrs) - decl_attributes (&TREE_PURPOSE (enum_decl), enum_attrs, 0); - TREE_CHAIN (enum_decl) = values; - values = enum_decl; - seen_comma = false; - if (c_parser_next_token_is (parser, CPP_COMMA)) - { - comma_loc = c_parser_peek_token (parser)->location; - seen_comma = true; - c_parser_consume_token (parser); - } - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - if (seen_comma) - pedwarn_c90 (comma_loc, OPT_Wpedantic, - "comma at end of enumerator list"); - c_parser_consume_token (parser); - break; - } - if (!seen_comma) - { - c_parser_error (parser, "expected %<,%> or %<}%>"); - c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); - values = error_mark_node; - break; - } - } - postfix_attrs = c_parser_gnu_attributes (parser); - ret.spec = finish_enum (type, nreverse (values), - chainon (std_attrs, - chainon (attrs, postfix_attrs))); - ret.kind = ctsk_tagdef; - ret.expr = NULL_TREE; - ret.expr_const_operands = true; - timevar_pop (TV_PARSE_ENUM); - return ret; - } - else if (!ident) - { - c_parser_error (parser, "expected %<{%>"); - ret.spec = error_mark_node; - ret.kind = ctsk_tagref; - ret.expr = NULL_TREE; - ret.expr_const_operands = true; - return ret; - } - /* Attributes may only appear when the members are defined or in - certain forward declarations (treat enum forward declarations in - GNU C analogously to struct and union forward declarations in - standard C). */ - if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON)) - c_parser_error (parser, "expected %<;%>"); - ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs, - std_attrs); - /* In ISO C, enumerated types can be referred to only if already - defined. */ - if (pedantic && !COMPLETE_TYPE_P (ret.spec)) - { - gcc_assert (ident); - pedwarn (enum_loc, OPT_Wpedantic, - "ISO C forbids forward references to % types"); - } - return ret; -} - -/* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1, C11 6.7.2.1). - - struct-or-union-specifier: - struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt] - identifier[opt] { struct-contents } gnu-attributes[opt] - struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt] - identifier - - struct-contents: - struct-declaration-list - - struct-declaration-list: - struct-declaration ; - struct-declaration-list struct-declaration ; - - GNU extensions: - - struct-contents: - empty - struct-declaration - struct-declaration-list struct-declaration - - struct-declaration-list: - struct-declaration-list ; - ; - - (Note that in the syntax here, unlike that in ISO C, the semicolons - are included here rather than in struct-declaration, in order to - describe the syntax with extra semicolons and missing semicolon at - end.) - - Objective-C: - - struct-declaration-list: - @defs ( class-name ) - - (Note this does not include a trailing semicolon, but can be - followed by further declarations, and gets a pedwarn-if-pedantic - when followed by a semicolon.) */ - -static struct c_typespec -c_parser_struct_or_union_specifier (c_parser *parser) -{ - struct c_typespec ret; - bool have_std_attrs; - tree std_attrs = NULL_TREE; - tree attrs; - tree ident = NULL_TREE; - location_t struct_loc; - location_t ident_loc = UNKNOWN_LOCATION; - enum tree_code code; - switch (c_parser_peek_token (parser)->keyword) - { - case RID_STRUCT: - code = RECORD_TYPE; - break; - case RID_UNION: - code = UNION_TYPE; - break; - default: - gcc_unreachable (); - } - struct_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); - if (have_std_attrs) - std_attrs = c_parser_std_attribute_specifier_sequence (parser); - attrs = c_parser_gnu_attributes (parser); - - /* Set the location in case we create a decl now. */ - c_parser_set_source_position_from_token (c_parser_peek_token (parser)); - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - ident = c_parser_peek_token (parser)->value; - ident_loc = c_parser_peek_token (parser)->location; - struct_loc = ident_loc; - c_parser_consume_token (parser); - } - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - { - /* Parse a struct or union definition. Start the scope of the - tag before parsing components. */ - class c_struct_parse_info *struct_info; - tree type = start_struct (struct_loc, code, ident, &struct_info); - tree postfix_attrs; - /* We chain the components in reverse order, then put them in - forward order at the end. Each struct-declaration may - declare multiple components (comma-separated), so we must use - chainon to join them, although when parsing each - struct-declaration we can use TREE_CHAIN directly. - - The theory behind all this is that there will be more - semicolon separated fields than comma separated fields, and - so we'll be minimizing the number of node traversals required - by chainon. */ - tree contents; - timevar_push (TV_PARSE_STRUCT); - contents = NULL_TREE; - c_parser_consume_token (parser); - /* Handle the Objective-C @defs construct, - e.g. foo(sizeof(struct{ @defs(ClassName) }));. */ - if (c_parser_next_token_is_keyword (parser, RID_AT_DEFS)) - { - tree name; - gcc_assert (c_dialect_objc ()); - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - goto end_at_defs; - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME) - { - name = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - } - else - { - c_parser_error (parser, "expected class name"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - goto end_at_defs; - } - parens.skip_until_found_close (parser); - contents = nreverse (objc_get_class_ivars (name)); - } - end_at_defs: - /* Parse the struct-declarations and semicolons. Problems with - semicolons are diagnosed here; empty structures are diagnosed - elsewhere. */ - while (true) - { - tree decls; - /* Parse any stray semicolon. */ - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - location_t semicolon_loc - = c_parser_peek_token (parser)->location; - gcc_rich_location richloc (semicolon_loc); - richloc.add_fixit_remove (); - pedwarn (&richloc, OPT_Wpedantic, - "extra semicolon in struct or union specified"); - c_parser_consume_token (parser); - continue; - } - /* Stop if at the end of the struct or union contents. */ - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - c_parser_consume_token (parser); - break; - } - /* Accept #pragmas at struct scope. */ - if (c_parser_next_token_is (parser, CPP_PRAGMA)) - { - c_parser_pragma (parser, pragma_struct, NULL); - continue; - } - /* Parse some comma-separated declarations, but not the - trailing semicolon if any. */ - decls = c_parser_struct_declaration (parser); - contents = chainon (decls, contents); - /* If no semicolon follows, either we have a parse error or - are at the end of the struct or union and should - pedwarn. */ - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - c_parser_consume_token (parser); - else - { - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - pedwarn (c_parser_peek_token (parser)->location, 0, - "no semicolon at end of struct or union"); - else if (parser->error - || !c_parser_next_token_starts_declspecs (parser)) - { - c_parser_error (parser, "expected %<;%>"); - c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); - break; - } - - /* If we come here, we have already emitted an error - for an expected `;', identifier or `(', and we also - recovered already. Go on with the next field. */ - } - } - postfix_attrs = c_parser_gnu_attributes (parser); - ret.spec = finish_struct (struct_loc, type, nreverse (contents), - chainon (std_attrs, - chainon (attrs, postfix_attrs)), - struct_info); - ret.kind = ctsk_tagdef; - ret.expr = NULL_TREE; - ret.expr_const_operands = true; - timevar_pop (TV_PARSE_STRUCT); - return ret; - } - else if (!ident) - { - c_parser_error (parser, "expected %<{%>"); - ret.spec = error_mark_node; - ret.kind = ctsk_tagref; - ret.expr = NULL_TREE; - ret.expr_const_operands = true; - return ret; - } - /* Attributes may only appear when the members are defined or in - certain forward declarations. */ - if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON)) - c_parser_error (parser, "expected %<;%>"); - /* ??? Existing practice is that GNU attributes are ignored after - the struct or union keyword when not defining the members. */ - ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs); - return ret; -} - -/* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1, C11 6.7.2.1), - *without* the trailing semicolon. - - struct-declaration: - attribute-specifier-sequence[opt] specifier-qualifier-list - attribute-specifier-sequence[opt] struct-declarator-list - static_assert-declaration-no-semi - - specifier-qualifier-list: - type-specifier specifier-qualifier-list[opt] - type-qualifier specifier-qualifier-list[opt] - alignment-specifier specifier-qualifier-list[opt] - gnu-attributes specifier-qualifier-list[opt] - - struct-declarator-list: - struct-declarator - struct-declarator-list , gnu-attributes[opt] struct-declarator - - struct-declarator: - declarator gnu-attributes[opt] - declarator[opt] : constant-expression gnu-attributes[opt] - - GNU extensions: - - struct-declaration: - __extension__ struct-declaration - specifier-qualifier-list - - Unlike the ISO C syntax, semicolons are handled elsewhere. The use - of gnu-attributes where shown is a GNU extension. In GNU C, we accept - any expression without commas in the syntax (assignment - expressions, not just conditional expressions); assignment - expressions will be diagnosed as non-constant. */ - -static tree -c_parser_struct_declaration (c_parser *parser) -{ - struct c_declspecs *specs; - tree prefix_attrs; - tree all_prefix_attrs; - tree decls; - location_t decl_loc; - if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) - { - int ext; - tree decl; - ext = disable_extension_diagnostics (); - c_parser_consume_token (parser); - decl = c_parser_struct_declaration (parser); - restore_extension_diagnostics (ext); - return decl; - } - if (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) - { - c_parser_static_assert_declaration_no_semi (parser); - return NULL_TREE; - } - specs = build_null_declspecs (); - decl_loc = c_parser_peek_token (parser)->location; - /* Strictly by the standard, we shouldn't allow _Alignas here, - but it appears to have been intended to allow it there, so - we're keeping it as it is until WG14 reaches a conclusion - of N1731. - */ - c_parser_declspecs (parser, specs, false, true, true, - true, false, true, true, cla_nonabstract_decl); - if (parser->error) - return NULL_TREE; - if (!specs->declspecs_seen_p) - { - c_parser_error (parser, "expected specifier-qualifier-list"); - return NULL_TREE; - } - finish_declspecs (specs); - if (c_parser_next_token_is (parser, CPP_SEMICOLON) - || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - tree ret; - if (specs->typespec_kind == ctsk_none) - { - pedwarn (decl_loc, OPT_Wpedantic, - "ISO C forbids member declarations with no members"); - shadow_tag_warned (specs, pedantic); - ret = NULL_TREE; - } - else - { - /* Support for unnamed structs or unions as members of - structs or unions (which is [a] useful and [b] supports - MS P-SDK). */ - tree attrs = NULL; - - ret = grokfield (c_parser_peek_token (parser)->location, - build_id_declarator (NULL_TREE), specs, - NULL_TREE, &attrs); - if (ret) - decl_attributes (&ret, attrs, 0); - } - return ret; - } - - /* Provide better error recovery. Note that a type name here is valid, - and will be treated as a field name. */ - if (specs->typespec_kind == ctsk_tagdef - && TREE_CODE (specs->type) != ENUMERAL_TYPE - && c_parser_next_token_starts_declspecs (parser) - && !c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected %<;%>, identifier or %<(%>"); - parser->error = false; - return NULL_TREE; - } - - pending_xref_error (); - prefix_attrs = specs->attrs; - all_prefix_attrs = prefix_attrs; - specs->attrs = NULL_TREE; - decls = NULL_TREE; - while (true) - { - /* Declaring one or more declarators or un-named bit-fields. */ - struct c_declarator *declarator; - bool dummy = false; - if (c_parser_next_token_is (parser, CPP_COLON)) - declarator = build_id_declarator (NULL_TREE); - else - declarator = c_parser_declarator (parser, - specs->typespec_kind != ctsk_none, - C_DTR_NORMAL, &dummy); - if (declarator == NULL) - { - c_parser_skip_to_end_of_block_or_statement (parser); - break; - } - if (c_parser_next_token_is (parser, CPP_COLON) - || c_parser_next_token_is (parser, CPP_COMMA) - || c_parser_next_token_is (parser, CPP_SEMICOLON) - || c_parser_next_token_is (parser, CPP_CLOSE_BRACE) - || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - { - tree postfix_attrs = NULL_TREE; - tree width = NULL_TREE; - tree d; - if (c_parser_next_token_is (parser, CPP_COLON)) - { - c_parser_consume_token (parser); - width = c_parser_expr_no_commas (parser, NULL).value; - } - if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - postfix_attrs = c_parser_gnu_attributes (parser); - d = grokfield (c_parser_peek_token (parser)->location, - declarator, specs, width, &all_prefix_attrs); - decl_attributes (&d, chainon (postfix_attrs, - all_prefix_attrs), 0); - DECL_CHAIN (d) = decls; - decls = d; - if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - all_prefix_attrs = chainon (c_parser_gnu_attributes (parser), - prefix_attrs); - else - all_prefix_attrs = prefix_attrs; - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else if (c_parser_next_token_is (parser, CPP_SEMICOLON) - || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - /* Semicolon consumed in caller. */ - break; - } - else - { - c_parser_error (parser, "expected %<,%>, %<;%> or %<}%>"); - break; - } - } - else - { - c_parser_error (parser, - "expected %<:%>, %<,%>, %<;%>, %<}%> or " - "%<__attribute__%>"); - break; - } - } - return decls; -} - -/* Parse a typeof specifier (a GNU extension). - - typeof-specifier: - typeof ( expression ) - typeof ( type-name ) -*/ - -static struct c_typespec -c_parser_typeof_specifier (c_parser *parser) -{ - struct c_typespec ret; - ret.kind = ctsk_typeof; - ret.spec = error_mark_node; - ret.expr = NULL_TREE; - ret.expr_const_operands = true; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF)); - c_parser_consume_token (parser); - c_inhibit_evaluation_warnings++; - in_typeof++; - matching_parens parens; - if (!parens.require_open (parser)) - { - c_inhibit_evaluation_warnings--; - in_typeof--; - return ret; - } - if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) - { - struct c_type_name *type = c_parser_type_name (parser); - c_inhibit_evaluation_warnings--; - in_typeof--; - if (type != NULL) - { - ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands); - pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE)); - } - } - else - { - bool was_vm; - location_t here = c_parser_peek_token (parser)->location; - struct c_expr expr = c_parser_expression (parser); - c_inhibit_evaluation_warnings--; - in_typeof--; - if (TREE_CODE (expr.value) == COMPONENT_REF - && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) - error_at (here, "% applied to a bit-field"); - mark_exp_read (expr.value); - ret.spec = TREE_TYPE (expr.value); - was_vm = variably_modified_type_p (ret.spec, NULL_TREE); - /* This is returned with the type so that when the type is - evaluated, this can be evaluated. */ - if (was_vm) - ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands); - pop_maybe_used (was_vm); - } - parens.skip_until_found_close (parser); - return ret; -} - -/* Parse an alignment-specifier. - - C11 6.7.5: - - alignment-specifier: - _Alignas ( type-name ) - _Alignas ( constant-expression ) -*/ - -static tree -c_parser_alignas_specifier (c_parser * parser) -{ - tree ret = error_mark_node; - location_t loc = c_parser_peek_token (parser)->location; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNAS)); - c_parser_consume_token (parser); - if (flag_isoc99) - pedwarn_c99 (loc, OPT_Wpedantic, - "ISO C99 does not support %<_Alignas%>"); - else - pedwarn_c99 (loc, OPT_Wpedantic, - "ISO C90 does not support %<_Alignas%>"); - matching_parens parens; - if (!parens.require_open (parser)) - return ret; - if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) - { - struct c_type_name *type = c_parser_type_name (parser); - if (type != NULL) - ret = c_sizeof_or_alignof_type (loc, groktypename (type, NULL, NULL), - false, true, 1); - } - else - ret = c_parser_expr_no_commas (parser, NULL).value; - parens.skip_until_found_close (parser); - return ret; -} - -/* Parse a declarator, possibly an abstract declarator (C90 6.5.4, - 6.5.5, C99 6.7.5, 6.7.6, C11 6.7.6, 6.7.7). If TYPE_SEEN_P then - a typedef name may be redeclared; otherwise it may not. KIND - indicates which kind of declarator is wanted. Returns a valid - declarator except in the case of a syntax error in which case NULL is - returned. *SEEN_ID is set to true if an identifier being declared is - seen; this is used to diagnose bad forms of abstract array declarators - and to determine whether an identifier list is syntactically permitted. - - declarator: - pointer[opt] direct-declarator - - direct-declarator: - identifier - ( gnu-attributes[opt] declarator ) - direct-declarator array-declarator - direct-declarator ( parameter-type-list ) - direct-declarator ( identifier-list[opt] ) - - pointer: - * type-qualifier-list[opt] - * type-qualifier-list[opt] pointer - - type-qualifier-list: - type-qualifier - gnu-attributes - type-qualifier-list type-qualifier - type-qualifier-list gnu-attributes - - array-declarator: - [ type-qualifier-list[opt] assignment-expression[opt] ] - [ static type-qualifier-list[opt] assignment-expression ] - [ type-qualifier-list static assignment-expression ] - [ type-qualifier-list[opt] * ] - - parameter-type-list: - parameter-list - parameter-list , ... - - parameter-list: - parameter-declaration - parameter-list , parameter-declaration - - parameter-declaration: - declaration-specifiers declarator gnu-attributes[opt] - declaration-specifiers abstract-declarator[opt] gnu-attributes[opt] - - identifier-list: - identifier - identifier-list , identifier - - abstract-declarator: - pointer - pointer[opt] direct-abstract-declarator - - direct-abstract-declarator: - ( gnu-attributes[opt] abstract-declarator ) - direct-abstract-declarator[opt] array-declarator - direct-abstract-declarator[opt] ( parameter-type-list[opt] ) - - GNU extensions: - - direct-declarator: - direct-declarator ( parameter-forward-declarations - parameter-type-list[opt] ) - - direct-abstract-declarator: - direct-abstract-declarator[opt] ( parameter-forward-declarations - parameter-type-list[opt] ) - - parameter-forward-declarations: - parameter-list ; - parameter-forward-declarations parameter-list ; - - The uses of gnu-attributes shown above are GNU extensions. - - Some forms of array declarator are not included in C99 in the - syntax for abstract declarators; these are disallowed elsewhere. - This may be a defect (DR#289). - - This function also accepts an omitted abstract declarator as being - an abstract declarator, although not part of the formal syntax. */ - -struct c_declarator * -c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, - bool *seen_id) -{ - /* Parse any initial pointer part. */ - if (c_parser_next_token_is (parser, CPP_MULT)) - { - struct c_declspecs *quals_attrs = build_null_declspecs (); - struct c_declarator *inner; - c_parser_consume_token (parser); - c_parser_declspecs (parser, quals_attrs, false, false, true, - false, false, true, false, cla_prefer_id); - inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); - if (inner == NULL) - return NULL; - else - return make_pointer_declarator (quals_attrs, inner); - } - /* Now we have a direct declarator, direct abstract declarator or - nothing (which counts as a direct abstract declarator here). */ - return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id); -} - -/* Parse a direct declarator or direct abstract declarator; arguments - as c_parser_declarator. */ - -static struct c_declarator * -c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, - bool *seen_id) -{ - /* The direct declarator must start with an identifier (possibly - omitted) or a parenthesized declarator (possibly abstract). In - an ordinary declarator, initial parentheses must start a - parenthesized declarator. In an abstract declarator or parameter - declarator, they could start a parenthesized declarator or a - parameter list. To tell which, the open parenthesis and any - following gnu-attributes must be read. If a declaration - specifier or standard attributes follow, then it is a parameter - list; if the specifier is a typedef name, there might be an - ambiguity about redeclaring it, which is resolved in the - direction of treating it as a typedef name. If a close - parenthesis follows, it is also an empty parameter list, as the - syntax does not permit empty abstract declarators. Otherwise, it - is a parenthesized declarator (in which case the analysis may be - repeated inside it, recursively). - - ??? There is an ambiguity in a parameter declaration "int - (__attribute__((foo)) x)", where x is not a typedef name: it - could be an abstract declarator for a function, or declare x with - parentheses. The proper resolution of this ambiguity needs - documenting. At present we follow an accident of the old - parser's implementation, whereby the first parameter must have - some declaration specifiers other than just gnu-attributes. Thus as - a parameter declaration it is treated as a parenthesized - parameter named x, and as an abstract declarator it is - rejected. - - ??? Also following the old parser, gnu-attributes inside an empty - parameter list are ignored, making it a list not yielding a - prototype, rather than giving an error or making it have one - parameter with implicit type int. - - ??? Also following the old parser, typedef names may be - redeclared in declarators, but not Objective-C class names. */ - - if (kind != C_DTR_ABSTRACT - && c_parser_next_token_is (parser, CPP_NAME) - && ((type_seen_p - && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME - || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) - || c_parser_peek_token (parser)->id_kind == C_ID_ID)) - { - struct c_declarator *inner - = build_id_declarator (c_parser_peek_token (parser)->value); - *seen_id = true; - inner->id_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - if (c_parser_nth_token_starts_std_attributes (parser, 1)) - inner->u.id.attrs = c_parser_std_attribute_specifier_sequence (parser); - return c_parser_direct_declarator_inner (parser, *seen_id, inner); - } - - if (kind != C_DTR_NORMAL - && c_parser_next_token_is (parser, CPP_OPEN_SQUARE) - && !c_parser_nth_token_starts_std_attributes (parser, 1)) - { - struct c_declarator *inner = build_id_declarator (NULL_TREE); - inner->id_loc = c_parser_peek_token (parser)->location; - return c_parser_direct_declarator_inner (parser, *seen_id, inner); - } - - /* Either we are at the end of an abstract declarator, or we have - parentheses. */ - - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - tree attrs; - struct c_declarator *inner; - c_parser_consume_token (parser); - bool have_gnu_attrs = c_parser_next_token_is_keyword (parser, - RID_ATTRIBUTE); - attrs = c_parser_gnu_attributes (parser); - if (kind != C_DTR_NORMAL - && (c_parser_next_token_starts_declspecs (parser) - || (!have_gnu_attrs - && c_parser_nth_token_starts_std_attributes (parser, 1)) - || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) - { - struct c_arg_info *args - = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL, - attrs, have_gnu_attrs); - if (args == NULL) - return NULL; - else - { - inner = build_id_declarator (NULL_TREE); - if (!(args->types - && args->types != error_mark_node - && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE) - && c_parser_nth_token_starts_std_attributes (parser, 1)) - { - tree std_attrs - = c_parser_std_attribute_specifier_sequence (parser); - if (std_attrs) - inner = build_attrs_declarator (std_attrs, inner); - } - inner = build_function_declarator (args, inner); - return c_parser_direct_declarator_inner (parser, *seen_id, - inner); - } - } - /* A parenthesized declarator. */ - inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); - if (inner != NULL && attrs != NULL) - inner = build_attrs_declarator (attrs, inner); - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - c_parser_consume_token (parser); - if (inner == NULL) - return NULL; - else - return c_parser_direct_declarator_inner (parser, *seen_id, inner); - } - else - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return NULL; - } - } - else - { - if (kind == C_DTR_NORMAL) - { - c_parser_error (parser, "expected identifier or %<(%>"); - return NULL; - } - else - return build_id_declarator (NULL_TREE); - } -} - -/* Parse part of a direct declarator or direct abstract declarator, - given that some (in INNER) has already been parsed; ID_PRESENT is - true if an identifier is present, false for an abstract - declarator. */ - -static struct c_declarator * -c_parser_direct_declarator_inner (c_parser *parser, bool id_present, - struct c_declarator *inner) -{ - /* Parse a sequence of array declarators and parameter lists. */ - if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE) - && !c_parser_nth_token_starts_std_attributes (parser, 1)) - { - location_t brace_loc = c_parser_peek_token (parser)->location; - struct c_declarator *declarator; - struct c_declspecs *quals_attrs = build_null_declspecs (); - bool static_seen; - bool star_seen; - struct c_expr dimen; - dimen.value = NULL_TREE; - dimen.original_code = ERROR_MARK; - dimen.original_type = NULL_TREE; - c_parser_consume_token (parser); - c_parser_declspecs (parser, quals_attrs, false, false, true, - false, false, false, false, cla_prefer_id); - static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC); - if (static_seen) - c_parser_consume_token (parser); - if (static_seen && !quals_attrs->declspecs_seen_p) - c_parser_declspecs (parser, quals_attrs, false, false, true, - false, false, false, false, cla_prefer_id); - if (!quals_attrs->declspecs_seen_p) - quals_attrs = NULL; - /* If "static" is present, there must be an array dimension. - Otherwise, there may be a dimension, "*", or no - dimension. */ - if (static_seen) - { - star_seen = false; - dimen = c_parser_expr_no_commas (parser, NULL); - } - else - { - if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) - { - dimen.value = NULL_TREE; - star_seen = false; - } - else if (c_parser_next_token_is (parser, CPP_MULT)) - { - if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE) - { - dimen.value = NULL_TREE; - star_seen = true; - c_parser_consume_token (parser); - } - else - { - star_seen = false; - dimen = c_parser_expr_no_commas (parser, NULL); - } - } - else - { - star_seen = false; - dimen = c_parser_expr_no_commas (parser, NULL); - } - } - if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) - c_parser_consume_token (parser); - else - { - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, - "expected %<]%>"); - return NULL; - } - if (dimen.value) - dimen = convert_lvalue_to_rvalue (brace_loc, dimen, true, true); - declarator = build_array_declarator (brace_loc, dimen.value, quals_attrs, - static_seen, star_seen); - if (declarator == NULL) - return NULL; - if (c_parser_nth_token_starts_std_attributes (parser, 1)) - { - tree std_attrs - = c_parser_std_attribute_specifier_sequence (parser); - if (std_attrs) - inner = build_attrs_declarator (std_attrs, inner); - } - inner = set_array_declarator_inner (declarator, inner); - return c_parser_direct_declarator_inner (parser, id_present, inner); - } - else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - tree attrs; - struct c_arg_info *args; - c_parser_consume_token (parser); - bool have_gnu_attrs = c_parser_next_token_is_keyword (parser, - RID_ATTRIBUTE); - attrs = c_parser_gnu_attributes (parser); - args = c_parser_parms_declarator (parser, id_present, attrs, - have_gnu_attrs); - if (args == NULL) - return NULL; - else - { - if (!(args->types - && args->types != error_mark_node - && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE) - && c_parser_nth_token_starts_std_attributes (parser, 1)) - { - tree std_attrs - = c_parser_std_attribute_specifier_sequence (parser); - if (std_attrs) - inner = build_attrs_declarator (std_attrs, inner); - } - inner = build_function_declarator (args, inner); - return c_parser_direct_declarator_inner (parser, id_present, inner); - } - } - return inner; -} - -/* Parse a parameter list or identifier list, including the closing - parenthesis but not the opening one. ATTRS are the gnu-attributes - at the start of the list. ID_LIST_OK is true if an identifier list - is acceptable; such a list must not have attributes at the start. - HAVE_GNU_ATTRS says whether any gnu-attributes (including empty - attributes) were present (in which case standard attributes cannot - occur). */ - -static struct c_arg_info * -c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs, - bool have_gnu_attrs) -{ - push_scope (); - declare_parm_level (); - /* If the list starts with an identifier, it is an identifier list. - Otherwise, it is either a prototype list or an empty list. */ - if (id_list_ok - && !attrs - && c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_ID - - /* Look ahead to detect typos in type names. */ - && c_parser_peek_2nd_token (parser)->type != CPP_NAME - && c_parser_peek_2nd_token (parser)->type != CPP_MULT - && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN - && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE - && c_parser_peek_2nd_token (parser)->type != CPP_KEYWORD) - { - tree list = NULL_TREE, *nextp = &list; - while (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_ID) - { - *nextp = build_tree_list (NULL_TREE, - c_parser_peek_token (parser)->value); - nextp = & TREE_CHAIN (*nextp); - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_COMMA)) - break; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - c_parser_error (parser, "expected identifier"); - break; - } - } - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - struct c_arg_info *ret = build_arg_info (); - ret->types = list; - c_parser_consume_token (parser); - pop_scope (); - return ret; - } - else - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - pop_scope (); - return NULL; - } - } - else - { - struct c_arg_info *ret - = c_parser_parms_list_declarator (parser, attrs, NULL, have_gnu_attrs); - pop_scope (); - return ret; - } -} - -/* Parse a parameter list (possibly empty), including the closing - parenthesis but not the opening one. ATTRS are the gnu-attributes - at the start of the list; if HAVE_GNU_ATTRS, there were some such - attributes (possibly empty, in which case ATTRS is NULL_TREE), - which means standard attributes cannot start the list. EXPR is - NULL or an expression that needs to be evaluated for the side - effects of array size expressions in the parameters. */ - -static struct c_arg_info * -c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr, - bool have_gnu_attrs) -{ - bool bad_parm = false; - - /* ??? Following the old parser, forward parameter declarations may - use abstract declarators, and if no real parameter declarations - follow the forward declarations then this is not diagnosed. Also - note as above that gnu-attributes are ignored as the only contents of - the parentheses, or as the only contents after forward - declarations. */ - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - struct c_arg_info *ret = build_arg_info (); - c_parser_consume_token (parser); - return ret; - } - if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) - { - struct c_arg_info *ret = build_arg_info (); - - if (flag_allow_parameterless_variadic_functions) - { - /* F (...) is allowed. */ - ret->types = NULL_TREE; - } - else - { - /* Suppress -Wold-style-definition for this case. */ - ret->types = error_mark_node; - error_at (c_parser_peek_token (parser)->location, - "ISO C requires a named argument before %<...%>"); - } - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - c_parser_consume_token (parser); - return ret; - } - else - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return NULL; - } - } - /* Nonempty list of parameters, either terminated with semicolon - (forward declarations; recurse) or with close parenthesis (normal - function) or with ", ... )" (variadic function). */ - while (true) - { - /* Parse a parameter. */ - struct c_parm *parm = c_parser_parameter_declaration (parser, attrs, - have_gnu_attrs); - attrs = NULL_TREE; - have_gnu_attrs = false; - if (parm == NULL) - bad_parm = true; - else - push_parm_decl (parm, &expr); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - tree new_attrs; - c_parser_consume_token (parser); - mark_forward_parm_decls (); - bool new_have_gnu_attrs - = c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE); - new_attrs = c_parser_gnu_attributes (parser); - return c_parser_parms_list_declarator (parser, new_attrs, expr, - new_have_gnu_attrs); - } - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - c_parser_consume_token (parser); - if (bad_parm) - return NULL; - else - return get_parm_info (false, expr); - } - if (!c_parser_require (parser, CPP_COMMA, - "expected %<;%>, %<,%> or %<)%>", - UNKNOWN_LOCATION, false)) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return NULL; - } - if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) - { - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - c_parser_consume_token (parser); - if (bad_parm) - return NULL; - else - return get_parm_info (true, expr); - } - else - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return NULL; - } - } - } -} - -/* Parse a parameter declaration. ATTRS are the gnu-attributes at the - start of the declaration if it is the first parameter; - HAVE_GNU_ATTRS is true if there were any gnu-attributes there (even - empty) there. */ - -static struct c_parm * -c_parser_parameter_declaration (c_parser *parser, tree attrs, - bool have_gnu_attrs) -{ - struct c_declspecs *specs; - struct c_declarator *declarator; - tree prefix_attrs; - tree postfix_attrs = NULL_TREE; - bool dummy = false; - - /* Accept #pragmas between parameter declarations. */ - while (c_parser_next_token_is (parser, CPP_PRAGMA)) - c_parser_pragma (parser, pragma_param, NULL); - - if (!c_parser_next_token_starts_declspecs (parser) - && !c_parser_nth_token_starts_std_attributes (parser, 1)) - { - c_token *token = c_parser_peek_token (parser); - if (parser->error) - return NULL; - c_parser_set_source_position_from_token (token); - if (c_parser_next_tokens_start_typename (parser, cla_prefer_type)) - { - auto_diagnostic_group d; - name_hint hint = lookup_name_fuzzy (token->value, - FUZZY_LOOKUP_TYPENAME, - token->location); - if (const char *suggestion = hint.suggestion ()) - { - gcc_rich_location richloc (token->location); - richloc.add_fixit_replace (suggestion); - error_at (&richloc, - "unknown type name %qE; did you mean %qs?", - token->value, suggestion); - } - else - error_at (token->location, "unknown type name %qE", token->value); - parser->error = true; - } - /* ??? In some Objective-C cases '...' isn't applicable so there - should be a different message. */ - else - c_parser_error (parser, - "expected declaration specifiers or %<...%>"); - c_parser_skip_to_end_of_parameter (parser); - return NULL; - } - - location_t start_loc = c_parser_peek_token (parser)->location; - - specs = build_null_declspecs (); - if (attrs) - { - declspecs_add_attrs (input_location, specs, attrs); - attrs = NULL_TREE; - } - c_parser_declspecs (parser, specs, true, true, true, true, false, - !have_gnu_attrs, true, cla_nonabstract_decl); - finish_declspecs (specs); - pending_xref_error (); - prefix_attrs = specs->attrs; - specs->attrs = NULL_TREE; - declarator = c_parser_declarator (parser, - specs->typespec_kind != ctsk_none, - C_DTR_PARM, &dummy); - if (declarator == NULL) - { - c_parser_skip_until_found (parser, CPP_COMMA, NULL); - return NULL; - } - if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - postfix_attrs = c_parser_gnu_attributes (parser); - - /* Generate a location for the parameter, ranging from the start of the - initial token to the end of the final token. - - If we have a identifier, then use it for the caret location, e.g. - - extern int callee (int one, int (*two)(int, int), float three); - ~~~~~~^~~~~~~~~~~~~~ - - otherwise, reuse the start location for the caret location e.g.: - - extern int callee (int one, int (*)(int, int), float three); - ^~~~~~~~~~~~~~~~~ - */ - location_t end_loc = parser->last_token_location; - - /* Find any cdk_id declarator; determine if we have an identifier. */ - c_declarator *id_declarator = declarator; - while (id_declarator && id_declarator->kind != cdk_id) - id_declarator = id_declarator->declarator; - location_t caret_loc = (id_declarator->u.id.id - ? id_declarator->id_loc - : start_loc); - location_t param_loc = make_location (caret_loc, start_loc, end_loc); - - return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs), - declarator, param_loc); -} - -/* Parse a string literal in an asm expression. It should not be - translated, and wide string literals are an error although - permitted by the syntax. This is a GNU extension. - - asm-string-literal: - string-literal -*/ - -static tree -c_parser_asm_string_literal (c_parser *parser) -{ - tree str; - int save_flag = warn_overlength_strings; - warn_overlength_strings = 0; - str = c_parser_string_literal (parser, false, false).value; - warn_overlength_strings = save_flag; - return str; -} - -/* Parse a simple asm expression. This is used in restricted - contexts, where a full expression with inputs and outputs does not - make sense. This is a GNU extension. - - simple-asm-expr: - asm ( asm-string-literal ) -*/ - -static tree -c_parser_simple_asm_expr (c_parser *parser) -{ - tree str; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - return NULL_TREE; - str = c_parser_asm_string_literal (parser); - if (!parens.require_close (parser)) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return NULL_TREE; - } - return str; -} - -static tree -c_parser_gnu_attribute_any_word (c_parser *parser) -{ - tree attr_name = NULL_TREE; - - if (c_parser_next_token_is (parser, CPP_KEYWORD)) - { - /* ??? See comment above about what keywords are accepted here. */ - bool ok; - switch (c_parser_peek_token (parser)->keyword) - { - case RID_STATIC: - case RID_UNSIGNED: - case RID_LONG: - case RID_CONST: - case RID_EXTERN: - case RID_REGISTER: - case RID_TYPEDEF: - case RID_SHORT: - case RID_INLINE: - case RID_NORETURN: - case RID_VOLATILE: - case RID_SIGNED: - case RID_AUTO: - case RID_RESTRICT: - case RID_COMPLEX: - case RID_THREAD: - case RID_INT: - case RID_CHAR: - case RID_FLOAT: - case RID_DOUBLE: - case RID_VOID: - case RID_DFLOAT32: - case RID_DFLOAT64: - case RID_DFLOAT128: - CASE_RID_FLOATN_NX: - case RID_BOOL: - case RID_FRACT: - case RID_ACCUM: - case RID_SAT: - case RID_TRANSACTION_ATOMIC: - case RID_TRANSACTION_CANCEL: - case RID_ATOMIC: - case RID_AUTO_TYPE: - case RID_INT_N_0: - case RID_INT_N_1: - case RID_INT_N_2: - case RID_INT_N_3: - ok = true; - break; - default: - ok = false; - break; - } - if (!ok) - return NULL_TREE; - - /* Accept __attribute__((__const)) as __attribute__((const)) etc. */ - attr_name = ridpointers[(int) c_parser_peek_token (parser)->keyword]; - } - else if (c_parser_next_token_is (parser, CPP_NAME)) - attr_name = c_parser_peek_token (parser)->value; - - return attr_name; -} - -/* Parse attribute arguments. This is a common form of syntax - covering all currently valid GNU and standard attributes. - - gnu-attribute-arguments: - identifier - identifier , nonempty-expr-list - expr-list - - where the "identifier" must not be declared as a type. ??? Why not - allow identifiers declared as types to start the arguments? */ - -static tree -c_parser_attribute_arguments (c_parser *parser, bool takes_identifier, - bool require_string, bool allow_empty_args) -{ - vec *expr_list; - tree attr_args; - /* Parse the attribute contents. If they start with an - identifier which is followed by a comma or close - parenthesis, then the arguments start with that - identifier; otherwise they are an expression list. - In objective-c the identifier may be a classname. */ - if (c_parser_next_token_is (parser, CPP_NAME) - && (c_parser_peek_token (parser)->id_kind == C_ID_ID - || (c_dialect_objc () - && c_parser_peek_token (parser)->id_kind - == C_ID_CLASSNAME)) - && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA) - || (c_parser_peek_2nd_token (parser)->type - == CPP_CLOSE_PAREN)) - && (takes_identifier - || (c_dialect_objc () - && c_parser_peek_token (parser)->id_kind - == C_ID_CLASSNAME))) - { - tree arg1 = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - attr_args = build_tree_list (NULL_TREE, arg1); - else - { - tree tree_list; - c_parser_consume_token (parser); - expr_list = c_parser_expr_list (parser, false, true, - NULL, NULL, NULL, NULL); - tree_list = build_tree_list_vec (expr_list); - attr_args = tree_cons (NULL_TREE, arg1, tree_list); - release_tree_vector (expr_list); - } - } - else - { - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - if (!allow_empty_args) - error_at (c_parser_peek_token (parser)->location, - "parentheses must be omitted if " - "attribute argument list is empty"); - attr_args = NULL_TREE; - } - else if (require_string) - { - /* The only valid argument for this attribute is a string - literal. Handle this specially here to avoid accepting - string literals with excess parentheses. */ - tree string = c_parser_string_literal (parser, false, true).value; - attr_args = build_tree_list (NULL_TREE, string); - } - else - { - expr_list = c_parser_expr_list (parser, false, true, - NULL, NULL, NULL, NULL); - attr_args = build_tree_list_vec (expr_list); - release_tree_vector (expr_list); - } - } - return attr_args; -} - -/* Parse (possibly empty) gnu-attributes. This is a GNU extension. - - gnu-attributes: - empty - gnu-attributes gnu-attribute - - gnu-attribute: - __attribute__ ( ( gnu-attribute-list ) ) - - gnu-attribute-list: - gnu-attrib - gnu-attribute_list , gnu-attrib - - gnu-attrib: - empty - any-word - any-word ( gnu-attribute-arguments ) - - where "any-word" may be any identifier (including one declared as a - type), a reserved word storage class specifier, type specifier or - type qualifier. ??? This still leaves out most reserved keywords - (following the old parser), shouldn't we include them? - When EXPECT_COMMA is true, expect the attribute to be preceded - by a comma and fail if it isn't. - When EMPTY_OK is true, allow and consume any number of consecutive - commas with no attributes in between. */ - -static tree -c_parser_gnu_attribute (c_parser *parser, tree attrs, - bool expect_comma = false, bool empty_ok = true) -{ - bool comma_first = c_parser_next_token_is (parser, CPP_COMMA); - if (!comma_first - && !c_parser_next_token_is (parser, CPP_NAME) - && !c_parser_next_token_is (parser, CPP_KEYWORD)) - return NULL_TREE; - - while (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - if (!empty_ok) - return attrs; - } - - tree attr_name = c_parser_gnu_attribute_any_word (parser); - if (attr_name == NULL_TREE) - return NULL_TREE; - - attr_name = canonicalize_attr_name (attr_name); - c_parser_consume_token (parser); - - tree attr; - if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) - { - if (expect_comma && !comma_first) - { - /* A comma is missing between the last attribute on the chain - and this one. */ - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return error_mark_node; - } - attr = build_tree_list (attr_name, NULL_TREE); - /* Add this attribute to the list. */ - attrs = chainon (attrs, attr); - return attrs; - } - c_parser_consume_token (parser); - - tree attr_args - = c_parser_attribute_arguments (parser, - attribute_takes_identifier_p (attr_name), - false, true); - - attr = build_tree_list (attr_name, attr_args); - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - c_parser_consume_token (parser); - else - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return error_mark_node; - } - - if (expect_comma && !comma_first) - { - /* A comma is missing between the last attribute on the chain - and this one. */ - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return error_mark_node; - } - - /* Add this attribute to the list. */ - attrs = chainon (attrs, attr); - return attrs; -} - -static tree -c_parser_gnu_attributes (c_parser *parser) -{ - tree attrs = NULL_TREE; - while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - { - bool save_translate_strings_p = parser->translate_strings_p; - parser->translate_strings_p = false; - /* Consume the `__attribute__' keyword. */ - c_parser_consume_token (parser); - /* Look for the two `(' tokens. */ - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - parser->translate_strings_p = save_translate_strings_p; - return attrs; - } - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - parser->translate_strings_p = save_translate_strings_p; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return attrs; - } - /* Parse the attribute list. Require a comma between successive - (possibly empty) attributes. */ - for (bool expect_comma = false; ; expect_comma = true) - { - /* Parse a single attribute. */ - tree attr = c_parser_gnu_attribute (parser, attrs, expect_comma); - if (attr == error_mark_node) - return attrs; - if (!attr) - break; - attrs = attr; - } - - /* Look for the two `)' tokens. */ - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - c_parser_consume_token (parser); - else - { - parser->translate_strings_p = save_translate_strings_p; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return attrs; - } - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - c_parser_consume_token (parser); - else - { - parser->translate_strings_p = save_translate_strings_p; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return attrs; - } - parser->translate_strings_p = save_translate_strings_p; - } - - return attrs; -} - -/* Parse an optional balanced token sequence. - - balanced-token-sequence: - balanced-token - balanced-token-sequence balanced-token - - balanced-token: - ( balanced-token-sequence[opt] ) - [ balanced-token-sequence[opt] ] - { balanced-token-sequence[opt] } - any token other than ()[]{} -*/ - -static void -c_parser_balanced_token_sequence (c_parser *parser) -{ - while (true) - { - c_token *token = c_parser_peek_token (parser); - switch (token->type) - { - case CPP_OPEN_BRACE: - { - matching_braces braces; - braces.consume_open (parser); - c_parser_balanced_token_sequence (parser); - braces.require_close (parser); - break; - } - - case CPP_OPEN_PAREN: - { - matching_parens parens; - parens.consume_open (parser); - c_parser_balanced_token_sequence (parser); - parens.require_close (parser); - break; - } - - case CPP_OPEN_SQUARE: - c_parser_consume_token (parser); - c_parser_balanced_token_sequence (parser); - c_parser_require (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); - break; - - case CPP_CLOSE_BRACE: - case CPP_CLOSE_PAREN: - case CPP_CLOSE_SQUARE: - case CPP_EOF: - return; - - case CPP_PRAGMA: - c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser, false); - break; - - default: - c_parser_consume_token (parser); - break; - } - } -} - -/* Parse standard (C2X) attributes (including GNU attributes in the - gnu:: namespace). - - attribute-specifier-sequence: - attribute-specifier-sequence[opt] attribute-specifier - - attribute-specifier: - [ [ attribute-list ] ] - - attribute-list: - attribute[opt] - attribute-list, attribute[opt] - - attribute: - attribute-token attribute-argument-clause[opt] - - attribute-token: - standard-attribute - attribute-prefixed-token - - standard-attribute: - identifier - - attribute-prefixed-token: - attribute-prefix :: identifier - - attribute-prefix: - identifier - - attribute-argument-clause: - ( balanced-token-sequence[opt] ) - - Keywords are accepted as identifiers for this purpose. -*/ - -static tree -c_parser_std_attribute (c_parser *parser, bool for_tm) -{ - c_token *token = c_parser_peek_token (parser); - tree ns, name, attribute; - - /* Parse the attribute-token. */ - if (token->type != CPP_NAME && token->type != CPP_KEYWORD) - { - c_parser_error (parser, "expected identifier"); - return error_mark_node; - } - name = canonicalize_attr_name (token->value); - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_SCOPE)) - { - ns = name; - c_parser_consume_token (parser); - token = c_parser_peek_token (parser); - if (token->type != CPP_NAME && token->type != CPP_KEYWORD) - { - c_parser_error (parser, "expected identifier"); - return error_mark_node; - } - name = canonicalize_attr_name (token->value); - c_parser_consume_token (parser); - } - else - ns = NULL_TREE; - attribute = build_tree_list (build_tree_list (ns, name), NULL_TREE); - - /* Parse the arguments, if any. */ - const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (attribute)); - if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) - goto out; - { - location_t open_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - parens.consume_open (parser); - if ((as && as->max_length == 0) - /* Special-case the transactional-memory attribute "outer", - which is specially handled but not registered as an - attribute, to avoid allowing arbitrary balanced token - sequences as arguments. */ - || is_attribute_p ("outer", name)) - { - error_at (open_loc, "%qE attribute does not take any arguments", name); - parens.skip_until_found_close (parser); - return error_mark_node; - } - /* If this is a fake attribute created to handle -Wno-attributes, - we must skip parsing the arguments. */ - if (as && !attribute_ignored_p (as)) - { - bool takes_identifier - = (ns != NULL_TREE - && strcmp (IDENTIFIER_POINTER (ns), "gnu") == 0 - && attribute_takes_identifier_p (name)); - bool require_string - = (ns == NULL_TREE - && (strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0 - || strcmp (IDENTIFIER_POINTER (name), "nodiscard") == 0)); - TREE_VALUE (attribute) - = c_parser_attribute_arguments (parser, takes_identifier, - require_string, false); - } - else - c_parser_balanced_token_sequence (parser); - parens.require_close (parser); - } - out: - if (ns == NULL_TREE && !for_tm && !as) - { - /* An attribute with standard syntax and no namespace specified - is a constraint violation if it is not one of the known - standard attributes. Diagnose it here with a pedwarn and - then discard it to prevent a duplicate warning later. */ - pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", - name); - return error_mark_node; - } - return attribute; -} - -static tree -c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) -{ - location_t loc = c_parser_peek_token (parser)->location; - if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) - return NULL_TREE; - if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); - return NULL_TREE; - } - if (!for_tm) - pedwarn_c11 (loc, OPT_Wpedantic, - "ISO C does not support %<[[]]%> attributes before C2X"); - tree attributes = NULL_TREE; - while (true) - { - c_token *token = c_parser_peek_token (parser); - if (token->type == CPP_CLOSE_SQUARE) - break; - if (token->type == CPP_COMMA) - { - c_parser_consume_token (parser); - continue; - } - tree attribute = c_parser_std_attribute (parser, for_tm); - if (attribute != error_mark_node) - { - TREE_CHAIN (attribute) = attributes; - attributes = attribute; - } - if (c_parser_next_token_is_not (parser, CPP_COMMA)) - break; - } - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); - return nreverse (attributes); -} - -/* Look past an optional balanced token sequence of raw look-ahead - tokens starting with the *Nth token. *N is updated to point to the - following token. Return true if such a sequence was found, false - if the tokens parsed were not balanced. */ - -static bool -c_parser_check_balanced_raw_token_sequence (c_parser *parser, unsigned int *n) -{ - while (true) - { - c_token *token = c_parser_peek_nth_token_raw (parser, *n); - switch (token->type) - { - case CPP_OPEN_BRACE: - { - ++*n; - if (c_parser_check_balanced_raw_token_sequence (parser, n)) - { - token = c_parser_peek_nth_token_raw (parser, *n); - if (token->type == CPP_CLOSE_BRACE) - ++*n; - else - return false; - } - else - return false; - break; - } - - case CPP_OPEN_PAREN: - { - ++*n; - if (c_parser_check_balanced_raw_token_sequence (parser, n)) - { - token = c_parser_peek_nth_token_raw (parser, *n); - if (token->type == CPP_CLOSE_PAREN) - ++*n; - else - return false; - } - else - return false; - break; - } - - case CPP_OPEN_SQUARE: - { - ++*n; - if (c_parser_check_balanced_raw_token_sequence (parser, n)) - { - token = c_parser_peek_nth_token_raw (parser, *n); - if (token->type == CPP_CLOSE_SQUARE) - ++*n; - else - return false; - } - else - return false; - break; - } - - case CPP_CLOSE_BRACE: - case CPP_CLOSE_PAREN: - case CPP_CLOSE_SQUARE: - case CPP_EOF: - return true; - - default: - ++*n; - break; - } - } -} - -/* Return whether standard attributes start with the Nth token. */ - -static bool -c_parser_nth_token_starts_std_attributes (c_parser *parser, unsigned int n) -{ - if (!(c_parser_peek_nth_token (parser, n)->type == CPP_OPEN_SQUARE - && c_parser_peek_nth_token (parser, n + 1)->type == CPP_OPEN_SQUARE)) - return false; - /* In C, '[[' must start attributes. In Objective-C, we need to - check whether '[[' is matched by ']]'. */ - if (!c_dialect_objc ()) - return true; - n += 2; - if (!c_parser_check_balanced_raw_token_sequence (parser, &n)) - return false; - c_token *token = c_parser_peek_nth_token_raw (parser, n); - if (token->type != CPP_CLOSE_SQUARE) - return false; - token = c_parser_peek_nth_token_raw (parser, n + 1); - return token->type == CPP_CLOSE_SQUARE; -} - -static tree -c_parser_std_attribute_specifier_sequence (c_parser *parser) -{ - tree attributes = NULL_TREE; - do - { - tree attrs = c_parser_std_attribute_specifier (parser, false); - attributes = chainon (attributes, attrs); - } - while (c_parser_nth_token_starts_std_attributes (parser, 1)); - return attributes; -} - -/* Parse a type name (C90 6.5.5, C99 6.7.6, C11 6.7.7). ALIGNAS_OK - says whether alignment specifiers are OK (only in cases that might - be the type name of a compound literal). - - type-name: - specifier-qualifier-list abstract-declarator[opt] -*/ - -struct c_type_name * -c_parser_type_name (c_parser *parser, bool alignas_ok) -{ - struct c_declspecs *specs = build_null_declspecs (); - struct c_declarator *declarator; - struct c_type_name *ret; - bool dummy = false; - c_parser_declspecs (parser, specs, false, true, true, alignas_ok, false, - false, true, cla_prefer_type); - if (!specs->declspecs_seen_p) - { - c_parser_error (parser, "expected specifier-qualifier-list"); - return NULL; - } - if (specs->type != error_mark_node) - { - pending_xref_error (); - finish_declspecs (specs); - } - declarator = c_parser_declarator (parser, - specs->typespec_kind != ctsk_none, - C_DTR_ABSTRACT, &dummy); - if (declarator == NULL) - return NULL; - ret = XOBNEW (&parser_obstack, struct c_type_name); - ret->specs = specs; - ret->declarator = declarator; - return ret; -} - -/* Parse an initializer (C90 6.5.7, C99 6.7.8, C11 6.7.9). - - initializer: - assignment-expression - { initializer-list } - { initializer-list , } - - initializer-list: - designation[opt] initializer - initializer-list , designation[opt] initializer - - designation: - designator-list = - - designator-list: - designator - designator-list designator - - designator: - array-designator - . identifier - - array-designator: - [ constant-expression ] - - GNU extensions: - - initializer: - { } - - designation: - array-designator - identifier : - - array-designator: - [ constant-expression ... constant-expression ] - - Any expression without commas is accepted in the syntax for the - constant-expressions, with non-constant expressions rejected later. - - This function is only used for top-level initializers; for nested - ones, see c_parser_initval. */ - -static struct c_expr -c_parser_initializer (c_parser *parser) -{ - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - return c_parser_braced_init (parser, NULL_TREE, false, NULL); - else - { - struct c_expr ret; - location_t loc = c_parser_peek_token (parser)->location; - ret = c_parser_expr_no_commas (parser, NULL); - if (TREE_CODE (ret.value) != STRING_CST - && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR) - ret = convert_lvalue_to_rvalue (loc, ret, true, true); - return ret; - } -} - -/* The location of the last comma within the current initializer list, - or UNKNOWN_LOCATION if not within one. */ - -location_t last_init_list_comma; - -/* Parse a braced initializer list. TYPE is the type specified for a - compound literal, and NULL_TREE for other initializers and for - nested braced lists. NESTED_P is true for nested braced lists, - false for the list of a compound literal or the list that is the - top-level initializer in a declaration. */ - -static struct c_expr -c_parser_braced_init (c_parser *parser, tree type, bool nested_p, - struct obstack *outer_obstack) -{ - struct c_expr ret; - struct obstack braced_init_obstack; - location_t brace_loc = c_parser_peek_token (parser)->location; - gcc_obstack_init (&braced_init_obstack); - gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); - matching_braces braces; - braces.consume_open (parser); - if (nested_p) - { - finish_implicit_inits (brace_loc, outer_obstack); - push_init_level (brace_loc, 0, &braced_init_obstack); - } - else - really_start_incremental_init (type); - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - pedwarn (brace_loc, OPT_Wpedantic, "ISO C forbids empty initializer braces"); - } - else - { - /* Parse a non-empty initializer list, possibly with a trailing - comma. */ - while (true) - { - c_parser_initelt (parser, &braced_init_obstack); - if (parser->error) - break; - if (c_parser_next_token_is (parser, CPP_COMMA)) - { - last_init_list_comma = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - } - else - break; - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - break; - } - } - c_token *next_tok = c_parser_peek_token (parser); - if (next_tok->type != CPP_CLOSE_BRACE) - { - ret.set_error (); - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - braces.skip_until_found_close (parser); - pop_init_level (brace_loc, 0, &braced_init_obstack, last_init_list_comma); - obstack_free (&braced_init_obstack, NULL); - return ret; - } - location_t close_loc = next_tok->location; - c_parser_consume_token (parser); - ret = pop_init_level (brace_loc, 0, &braced_init_obstack, close_loc); - obstack_free (&braced_init_obstack, NULL); - set_c_expr_source_range (&ret, brace_loc, close_loc); - return ret; -} - -/* Parse a nested initializer, including designators. */ - -static void -c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) -{ - /* Parse any designator or designator list. A single array - designator may have the subsequent "=" omitted in GNU C, but a - longer list or a structure member designator may not. */ - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) - { - /* Old-style structure member designator. */ - set_init_label (c_parser_peek_token (parser)->location, - c_parser_peek_token (parser)->value, - c_parser_peek_token (parser)->location, - braced_init_obstack); - /* Use the colon as the error location. */ - pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_Wpedantic, - "obsolete use of designated initializer with %<:%>"); - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - else - { - /* des_seen is 0 if there have been no designators, 1 if there - has been a single array designator and 2 otherwise. */ - int des_seen = 0; - /* Location of a designator. */ - location_t des_loc = UNKNOWN_LOCATION; /* Quiet warning. */ - while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE) - || c_parser_next_token_is (parser, CPP_DOT)) - { - int des_prev = des_seen; - if (!des_seen) - des_loc = c_parser_peek_token (parser)->location; - if (des_seen < 2) - des_seen++; - if (c_parser_next_token_is (parser, CPP_DOT)) - { - des_seen = 2; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - set_init_label (des_loc, c_parser_peek_token (parser)->value, - c_parser_peek_token (parser)->location, - braced_init_obstack); - c_parser_consume_token (parser); - } - else - { - struct c_expr init; - init.set_error (); - init.original_code = ERROR_MARK; - init.original_type = NULL; - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_COMMA, NULL); - process_init_element (input_location, init, false, - braced_init_obstack); - return; - } - } - else - { - tree first, second; - location_t ellipsis_loc = UNKNOWN_LOCATION; /* Quiet warning. */ - location_t array_index_loc = UNKNOWN_LOCATION; - /* ??? Following the old parser, [ objc-receiver - objc-message-args ] is accepted as an initializer, - being distinguished from a designator by what follows - the first assignment expression inside the square - brackets, but after a first array designator a - subsequent square bracket is for Objective-C taken to - start an expression, using the obsolete form of - designated initializer without '=', rather than - possibly being a second level of designation: in LALR - terms, the '[' is shifted rather than reducing - designator to designator-list. */ - if (des_prev == 1 && c_dialect_objc ()) - { - des_seen = des_prev; - break; - } - if (des_prev == 0 && c_dialect_objc ()) - { - /* This might be an array designator or an - Objective-C message expression. If the former, - continue parsing here; if the latter, parse the - remainder of the initializer given the starting - primary-expression. ??? It might make sense to - distinguish when des_prev == 1 as well; see - previous comment. */ - tree rec, args; - struct c_expr mexpr; - c_parser_consume_token (parser); - if (c_parser_peek_token (parser)->type == CPP_NAME - && ((c_parser_peek_token (parser)->id_kind - == C_ID_TYPENAME) - || (c_parser_peek_token (parser)->id_kind - == C_ID_CLASSNAME))) - { - /* Type name receiver. */ - tree id = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - rec = objc_get_class_reference (id); - goto parse_message_args; - } - first = c_parser_expr_no_commas (parser, NULL).value; - mark_exp_read (first); - if (c_parser_next_token_is (parser, CPP_ELLIPSIS) - || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) - goto array_desig_after_first; - /* Expression receiver. So far only one part - without commas has been parsed; there might be - more of the expression. */ - rec = first; - while (c_parser_next_token_is (parser, CPP_COMMA)) - { - struct c_expr next; - location_t comma_loc, exp_loc; - comma_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - next = c_parser_expr_no_commas (parser, NULL); - next = convert_lvalue_to_rvalue (exp_loc, next, - true, true); - rec = build_compound_expr (comma_loc, rec, next.value); - } - parse_message_args: - /* Now parse the objc-message-args. */ - args = c_parser_objc_message_args (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, - "expected %<]%>"); - mexpr.value - = objc_build_message_expr (rec, args); - mexpr.original_code = ERROR_MARK; - mexpr.original_type = NULL; - /* Now parse and process the remainder of the - initializer, starting with this message - expression as a primary-expression. */ - c_parser_initval (parser, &mexpr, braced_init_obstack); - return; - } - c_parser_consume_token (parser); - array_index_loc = c_parser_peek_token (parser)->location; - first = c_parser_expr_no_commas (parser, NULL).value; - mark_exp_read (first); - array_desig_after_first: - if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) - { - ellipsis_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - second = c_parser_expr_no_commas (parser, NULL).value; - mark_exp_read (second); - } - else - second = NULL_TREE; - if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) - { - c_parser_consume_token (parser); - set_init_index (array_index_loc, first, second, - braced_init_obstack); - if (second) - pedwarn (ellipsis_loc, OPT_Wpedantic, - "ISO C forbids specifying range of elements to initialize"); - } - else - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, - "expected %<]%>"); - } - } - if (des_seen >= 1) - { - if (c_parser_next_token_is (parser, CPP_EQ)) - { - pedwarn_c90 (des_loc, OPT_Wpedantic, - "ISO C90 forbids specifying subobject " - "to initialize"); - c_parser_consume_token (parser); - } - else - { - if (des_seen == 1) - pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, - "obsolete use of designated initializer without %<=%>"); - else - { - struct c_expr init; - init.set_error (); - init.original_code = ERROR_MARK; - init.original_type = NULL; - c_parser_error (parser, "expected %<=%>"); - c_parser_skip_until_found (parser, CPP_COMMA, NULL); - process_init_element (input_location, init, false, - braced_init_obstack); - return; - } - } - } - } - c_parser_initval (parser, NULL, braced_init_obstack); -} - -/* Parse a nested initializer; as c_parser_initializer but parses - initializers within braced lists, after any designators have been - applied. If AFTER is not NULL then it is an Objective-C message - expression which is the primary-expression starting the - initializer. */ - -static void -c_parser_initval (c_parser *parser, struct c_expr *after, - struct obstack * braced_init_obstack) -{ - struct c_expr init; - gcc_assert (!after || c_dialect_objc ()); - location_t loc = c_parser_peek_token (parser)->location; - - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after) - init = c_parser_braced_init (parser, NULL_TREE, true, - braced_init_obstack); - else - { - init = c_parser_expr_no_commas (parser, after); - if (init.value != NULL_TREE - && TREE_CODE (init.value) != STRING_CST - && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR) - init = convert_lvalue_to_rvalue (loc, init, true, true); - } - process_init_element (loc, init, false, braced_init_obstack); -} - -/* Parse a compound statement (possibly a function body) (C90 6.6.2, - C99 6.8.2, C11 6.8.2, C2X 6.8.2). - - compound-statement: - { block-item-list[opt] } - { label-declarations block-item-list } - - block-item-list: - block-item - block-item-list block-item - - block-item: - label - nested-declaration - statement - - nested-declaration: - declaration - - GNU extensions: - - compound-statement: - { label-declarations block-item-list } - - nested-declaration: - __extension__ nested-declaration - nested-function-definition - - label-declarations: - label-declaration - label-declarations label-declaration - - label-declaration: - __label__ identifier-list ; - - Allowing the mixing of declarations and code is new in C99. The - GNU syntax also permits (not shown above) labels at the end of - compound statements, which yield an error. We don't allow labels - on declarations; this might seem like a natural extension, but - there would be a conflict between gnu-attributes on the label and - prefix gnu-attributes on the declaration. ??? The syntax follows the - old parser in requiring something after label declarations. - Although they are erroneous if the labels declared aren't defined, - is it useful for the syntax to be this way? - - OpenACC: - - block-item: - openacc-directive - - openacc-directive: - update-directive - - OpenMP: - - block-item: - openmp-directive - - openmp-directive: - barrier-directive - flush-directive - taskwait-directive - taskyield-directive - cancel-directive - cancellation-point-directive */ - -static tree -c_parser_compound_statement (c_parser *parser, location_t *endlocp) -{ - tree stmt; - location_t brace_loc; - brace_loc = c_parser_peek_token (parser)->location; - if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) - { - /* Ensure a scope is entered and left anyway to avoid confusion - if we have just prepared to enter a function body. */ - stmt = c_begin_compound_stmt (true); - c_end_compound_stmt (brace_loc, stmt, true); - return error_mark_node; - } - stmt = c_begin_compound_stmt (true); - location_t end_loc = c_parser_compound_statement_nostart (parser); - if (endlocp) - *endlocp = end_loc; - - return c_end_compound_stmt (brace_loc, stmt, true); -} - -/* Parse a compound statement except for the opening brace. This is - used for parsing both compound statements and statement expressions - (which follow different paths to handling the opening). */ - -static location_t -c_parser_compound_statement_nostart (c_parser *parser) -{ - bool last_stmt = false; - bool last_label = false; - bool save_valid_for_pragma = valid_location_for_stdc_pragma_p (); - location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - location_t endloc = c_parser_peek_token (parser)->location; - add_debug_begin_stmt (endloc); - c_parser_consume_token (parser); - return endloc; - } - mark_valid_location_for_stdc_pragma (true); - if (c_parser_next_token_is_keyword (parser, RID_LABEL)) - { - /* Read zero or more forward-declarations for labels that nested - functions can jump to. */ - mark_valid_location_for_stdc_pragma (false); - while (c_parser_next_token_is_keyword (parser, RID_LABEL)) - { - label_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - /* Any identifiers, including those declared as type names, - are OK here. */ - while (true) - { - tree label; - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - break; - } - label - = declare_label (c_parser_peek_token (parser)->value); - C_DECLARED_LABEL_FLAG (label) = 1; - add_stmt (build_stmt (label_loc, DECL_EXPR, label)); - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - } - pedwarn (label_loc, OPT_Wpedantic, "ISO C forbids label declarations"); - } - /* We must now have at least one statement, label or declaration. */ - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - mark_valid_location_for_stdc_pragma (save_valid_for_pragma); - c_parser_error (parser, "expected declaration or statement"); - location_t endloc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - return endloc; - } - while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) - { - location_t loc = c_parser_peek_token (parser)->location; - loc = expansion_point_location_if_in_system_header (loc); - /* Standard attributes may start a label, statement or declaration. */ - bool have_std_attrs - = c_parser_nth_token_starts_std_attributes (parser, 1); - tree std_attrs = NULL_TREE; - if (have_std_attrs) - std_attrs = c_parser_std_attribute_specifier_sequence (parser); - if (c_parser_next_token_is_keyword (parser, RID_CASE) - || c_parser_next_token_is_keyword (parser, RID_DEFAULT) - || (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) - { - if (c_parser_next_token_is_keyword (parser, RID_CASE)) - label_loc = c_parser_peek_2nd_token (parser)->location; - else - label_loc = c_parser_peek_token (parser)->location; - last_label = true; - last_stmt = false; - mark_valid_location_for_stdc_pragma (false); - c_parser_label (parser, std_attrs); - } - else if (c_parser_next_tokens_start_declaration (parser) - || (have_std_attrs - && c_parser_next_token_is (parser, CPP_SEMICOLON))) - { - if (last_label) - pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic, - "a label can only be part of a statement and " - "a declaration is not a statement"); - - mark_valid_location_for_stdc_pragma (false); - bool fallthru_attr_p = false; - c_parser_declaration_or_fndef (parser, true, !have_std_attrs, - true, true, true, NULL, - NULL, have_std_attrs, std_attrs, - NULL, &fallthru_attr_p); - - if (last_stmt && !fallthru_attr_p) - pedwarn_c90 (loc, OPT_Wdeclaration_after_statement, - "ISO C90 forbids mixed declarations and code"); - last_stmt = fallthru_attr_p; - last_label = false; - } - else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) - { - /* __extension__ can start a declaration, but is also an - unary operator that can start an expression. Consume all - but the last of a possible series of __extension__ to - determine which. If standard attributes have already - been seen, it must start a statement, not a declaration, - but standard attributes starting a declaration may appear - after __extension__. */ - while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD - && (c_parser_peek_2nd_token (parser)->keyword - == RID_EXTENSION)) - c_parser_consume_token (parser); - if (!have_std_attrs - && (c_token_starts_declaration (c_parser_peek_2nd_token (parser)) - || c_parser_nth_token_starts_std_attributes (parser, 2))) - { - int ext; - ext = disable_extension_diagnostics (); - c_parser_consume_token (parser); - last_label = false; - mark_valid_location_for_stdc_pragma (false); - c_parser_declaration_or_fndef (parser, true, true, true, true, - true); - /* Following the old parser, __extension__ does not - disable this diagnostic. */ - restore_extension_diagnostics (ext); - if (last_stmt) - pedwarn_c90 (loc, OPT_Wdeclaration_after_statement, - "ISO C90 forbids mixed declarations and code"); - last_stmt = false; - } - else - goto statement; - } - else if (c_parser_next_token_is (parser, CPP_PRAGMA)) - { - if (have_std_attrs) - c_parser_error (parser, "expected declaration or statement"); - /* External pragmas, and some omp pragmas, are not associated - with regular c code, and so are not to be considered statements - syntactically. This ensures that the user doesn't put them - places that would turn into syntax errors if the directive - were ignored. */ - if (c_parser_pragma (parser, - last_label ? pragma_stmt : pragma_compound, - NULL)) - last_label = false, last_stmt = true; - } - else if (c_parser_next_token_is (parser, CPP_EOF)) - { - mark_valid_location_for_stdc_pragma (save_valid_for_pragma); - c_parser_error (parser, "expected declaration or statement"); - return c_parser_peek_token (parser)->location; - } - else if (c_parser_next_token_is_keyword (parser, RID_ELSE)) - { - if (parser->in_if_block) - { - mark_valid_location_for_stdc_pragma (save_valid_for_pragma); - error_at (loc, "expected %<}%> before %"); - return c_parser_peek_token (parser)->location; - } - else - { - error_at (loc, "% without a previous %"); - c_parser_consume_token (parser); - continue; - } - } - else - { - statement: - c_warn_unused_attributes (std_attrs); - last_label = false; - last_stmt = true; - mark_valid_location_for_stdc_pragma (false); - c_parser_statement_after_labels (parser, NULL); - } - - parser->error = false; - } - if (last_label) - pedwarn_c11 (label_loc, OPT_Wpedantic, "label at end of compound statement"); - location_t endloc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - /* Restore the value we started with. */ - mark_valid_location_for_stdc_pragma (save_valid_for_pragma); - return endloc; -} - -/* Parse all consecutive labels, possibly preceded by standard - attributes. In this context, a statement is required, not a - declaration, so attributes must be followed by a statement that is - not just a semicolon. */ - -static void -c_parser_all_labels (c_parser *parser) -{ - tree std_attrs = NULL; - if (c_parser_nth_token_starts_std_attributes (parser, 1)) - { - std_attrs = c_parser_std_attribute_specifier_sequence (parser); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - c_parser_error (parser, "expected statement"); - } - while (c_parser_next_token_is_keyword (parser, RID_CASE) - || c_parser_next_token_is_keyword (parser, RID_DEFAULT) - || (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) - { - c_parser_label (parser, std_attrs); - std_attrs = NULL; - if (c_parser_nth_token_starts_std_attributes (parser, 1)) - { - std_attrs = c_parser_std_attribute_specifier_sequence (parser); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - c_parser_error (parser, "expected statement"); - } - } - if (std_attrs) - c_warn_unused_attributes (std_attrs); -} - -/* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1). - - label: - identifier : gnu-attributes[opt] - case constant-expression : - default : - - GNU extensions: - - label: - case constant-expression ... constant-expression : - - The use of gnu-attributes on labels is a GNU extension. The syntax in - GNU C accepts any expressions without commas, non-constant - expressions being rejected later. Any standard - attribute-specifier-sequence before the first label has been parsed - in the caller, to distinguish statements from declarations. Any - attribute-specifier-sequence after the label is parsed in this - function. */ -static void -c_parser_label (c_parser *parser, tree std_attrs) -{ - location_t loc1 = c_parser_peek_token (parser)->location; - tree label = NULL_TREE; - - /* Remember whether this case or a user-defined label is allowed to fall - through to. */ - bool fallthrough_p = c_parser_peek_token (parser)->flags & PREV_FALLTHROUGH; - - if (c_parser_next_token_is_keyword (parser, RID_CASE)) - { - tree exp1, exp2; - c_parser_consume_token (parser); - exp1 = c_parser_expr_no_commas (parser, NULL).value; - if (c_parser_next_token_is (parser, CPP_COLON)) - { - c_parser_consume_token (parser); - label = do_case (loc1, exp1, NULL_TREE); - } - else if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) - { - c_parser_consume_token (parser); - exp2 = c_parser_expr_no_commas (parser, NULL).value; - if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) - label = do_case (loc1, exp1, exp2); - } - else - c_parser_error (parser, "expected %<:%> or %<...%>"); - } - else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) - { - c_parser_consume_token (parser); - if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) - label = do_case (loc1, NULL_TREE, NULL_TREE); - } - else - { - tree name = c_parser_peek_token (parser)->value; - tree tlab; - tree attrs; - location_t loc2 = c_parser_peek_token (parser)->location; - gcc_assert (c_parser_next_token_is (parser, CPP_NAME)); - c_parser_consume_token (parser); - gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); - c_parser_consume_token (parser); - attrs = c_parser_gnu_attributes (parser); - tlab = define_label (loc2, name); - if (tlab) - { - decl_attributes (&tlab, attrs, 0); - decl_attributes (&tlab, std_attrs, 0); - label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab)); - } - if (attrs - && c_parser_next_tokens_start_declaration (parser)) - warning_at (loc2, OPT_Wattributes, "GNU-style attribute between" - " label and declaration appertains to the label"); - } - if (label) - { - if (TREE_CODE (label) == LABEL_EXPR) - FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p; - else - FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p; - } -} - -/* Parse a statement (C90 6.6, C99 6.8, C11 6.8). - - statement: - labeled-statement - attribute-specifier-sequence[opt] compound-statement - expression-statement - attribute-specifier-sequence[opt] selection-statement - attribute-specifier-sequence[opt] iteration-statement - attribute-specifier-sequence[opt] jump-statement - - labeled-statement: - attribute-specifier-sequence[opt] label statement - - expression-statement: - expression[opt] ; - attribute-specifier-sequence expression ; - - selection-statement: - if-statement - switch-statement - - iteration-statement: - while-statement - do-statement - for-statement - - jump-statement: - goto identifier ; - continue ; - break ; - return expression[opt] ; - - GNU extensions: - - statement: - attribute-specifier-sequence[opt] asm-statement - - jump-statement: - goto * expression ; - - expression-statement: - gnu-attributes ; - - Objective-C: - - statement: - attribute-specifier-sequence[opt] objc-throw-statement - attribute-specifier-sequence[opt] objc-try-catch-statement - attribute-specifier-sequence[opt] objc-synchronized-statement - - objc-throw-statement: - @throw expression ; - @throw ; - - OpenACC: - - statement: - attribute-specifier-sequence[opt] openacc-construct - - openacc-construct: - parallel-construct - kernels-construct - data-construct - loop-construct - - parallel-construct: - parallel-directive structured-block - - kernels-construct: - kernels-directive structured-block - - data-construct: - data-directive structured-block - - loop-construct: - loop-directive structured-block - - OpenMP: - - statement: - attribute-specifier-sequence[opt] openmp-construct - - openmp-construct: - parallel-construct - for-construct - simd-construct - for-simd-construct - sections-construct - single-construct - parallel-for-construct - parallel-for-simd-construct - parallel-sections-construct - master-construct - critical-construct - atomic-construct - ordered-construct - - parallel-construct: - parallel-directive structured-block - - for-construct: - for-directive iteration-statement - - simd-construct: - simd-directive iteration-statements - - for-simd-construct: - for-simd-directive iteration-statements - - sections-construct: - sections-directive section-scope - - single-construct: - single-directive structured-block - - parallel-for-construct: - parallel-for-directive iteration-statement - - parallel-for-simd-construct: - parallel-for-simd-directive iteration-statement - - parallel-sections-construct: - parallel-sections-directive section-scope - - master-construct: - master-directive structured-block - - critical-construct: - critical-directive structured-block - - atomic-construct: - atomic-directive expression-statement - - ordered-construct: - ordered-directive structured-block - - Transactional Memory: - - statement: - attribute-specifier-sequence[opt] transaction-statement - attribute-specifier-sequence[opt] transaction-cancel-statement - - IF_P is used to track whether there's a (possibly labeled) if statement - which is not enclosed in braces and has an else clause. This is used to - implement -Wparentheses. */ - -static void -c_parser_statement (c_parser *parser, bool *if_p, location_t *loc_after_labels) -{ - c_parser_all_labels (parser); - if (loc_after_labels) - *loc_after_labels = c_parser_peek_token (parser)->location; - c_parser_statement_after_labels (parser, if_p, NULL); -} - -/* Parse a statement, other than a labeled statement. CHAIN is a vector - of if-else-if conditions. All labels and standard attributes have - been parsed in the caller. - - IF_P is used to track whether there's a (possibly labeled) if statement - which is not enclosed in braces and has an else clause. This is used to - implement -Wparentheses. */ - -static void -c_parser_statement_after_labels (c_parser *parser, bool *if_p, - vec *chain) -{ - location_t loc = c_parser_peek_token (parser)->location; - tree stmt = NULL_TREE; - bool in_if_block = parser->in_if_block; - parser->in_if_block = false; - if (if_p != NULL) - *if_p = false; - - if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE) - add_debug_begin_stmt (loc); - - restart: - switch (c_parser_peek_token (parser)->type) - { - case CPP_OPEN_BRACE: - add_stmt (c_parser_compound_statement (parser)); - break; - case CPP_KEYWORD: - switch (c_parser_peek_token (parser)->keyword) - { - case RID_IF: - c_parser_if_statement (parser, if_p, chain); - break; - case RID_SWITCH: - c_parser_switch_statement (parser, if_p); - break; - case RID_WHILE: - c_parser_while_statement (parser, false, 0, if_p); - break; - case RID_DO: - c_parser_do_statement (parser, false, 0); - break; - case RID_FOR: - c_parser_for_statement (parser, false, 0, if_p); - break; - case RID_GOTO: - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - stmt = c_finish_goto_label (loc, - c_parser_peek_token (parser)->value); - c_parser_consume_token (parser); - } - else if (c_parser_next_token_is (parser, CPP_MULT)) - { - struct c_expr val; - - c_parser_consume_token (parser); - val = c_parser_expression (parser); - val = convert_lvalue_to_rvalue (loc, val, false, true); - stmt = c_finish_goto_ptr (loc, val); - } - else - c_parser_error (parser, "expected identifier or %<*%>"); - goto expect_semicolon; - case RID_CONTINUE: - c_parser_consume_token (parser); - stmt = c_finish_bc_stmt (loc, objc_foreach_continue_label, false); - goto expect_semicolon; - case RID_BREAK: - c_parser_consume_token (parser); - stmt = c_finish_bc_stmt (loc, objc_foreach_break_label, true); - goto expect_semicolon; - case RID_RETURN: - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - stmt = c_finish_return (loc, NULL_TREE, NULL_TREE); - c_parser_consume_token (parser); - } - else - { - location_t xloc = c_parser_peek_token (parser)->location; - struct c_expr expr = c_parser_expression_conv (parser); - mark_exp_read (expr.value); - stmt = c_finish_return (EXPR_LOC_OR_LOC (expr.value, xloc), - expr.value, expr.original_type); - goto expect_semicolon; - } - break; - case RID_ASM: - stmt = c_parser_asm_statement (parser); - break; - case RID_TRANSACTION_ATOMIC: - case RID_TRANSACTION_RELAXED: - stmt = c_parser_transaction (parser, - c_parser_peek_token (parser)->keyword); - break; - case RID_TRANSACTION_CANCEL: - stmt = c_parser_transaction_cancel (parser); - goto expect_semicolon; - case RID_AT_THROW: - gcc_assert (c_dialect_objc ()); - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - stmt = objc_build_throw_stmt (loc, NULL_TREE); - c_parser_consume_token (parser); - } - else - { - struct c_expr expr = c_parser_expression (parser); - expr = convert_lvalue_to_rvalue (loc, expr, false, false); - expr.value = c_fully_fold (expr.value, false, NULL); - stmt = objc_build_throw_stmt (loc, expr.value); - goto expect_semicolon; - } - break; - case RID_AT_TRY: - gcc_assert (c_dialect_objc ()); - c_parser_objc_try_catch_finally_statement (parser); - break; - case RID_AT_SYNCHRONIZED: - gcc_assert (c_dialect_objc ()); - c_parser_objc_synchronized_statement (parser); - break; - case RID_ATTRIBUTE: - { - /* Allow '__attribute__((fallthrough));'. */ - tree attrs = c_parser_gnu_attributes (parser); - if (attribute_fallthrough_p (attrs)) - { - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - tree fn = build_call_expr_internal_loc (loc, - IFN_FALLTHROUGH, - void_type_node, 0); - add_stmt (fn); - /* Eat the ';'. */ - c_parser_consume_token (parser); - } - else - warning_at (loc, OPT_Wattributes, - "% attribute not followed " - "by %<;%>"); - } - else if (attrs != NULL_TREE) - warning_at (loc, OPT_Wattributes, "only attribute %" - " can be applied to a null statement"); - break; - } - default: - goto expr_stmt; - } - break; - case CPP_SEMICOLON: - c_parser_consume_token (parser); - break; - case CPP_CLOSE_PAREN: - case CPP_CLOSE_SQUARE: - /* Avoid infinite loop in error recovery: - c_parser_skip_until_found stops at a closing nesting - delimiter without consuming it, but here we need to consume - it to proceed further. */ - c_parser_error (parser, "expected statement"); - c_parser_consume_token (parser); - break; - case CPP_PRAGMA: - if (!c_parser_pragma (parser, pragma_stmt, if_p)) - goto restart; - break; - default: - expr_stmt: - stmt = c_finish_expr_stmt (loc, c_parser_expression_conv (parser).value); - expect_semicolon: - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - break; - } - /* Two cases cannot and do not have line numbers associated: If stmt - is degenerate, such as "2;", then stmt is an INTEGER_CST, which - cannot hold line numbers. But that's OK because the statement - will either be changed to a MODIFY_EXPR during gimplification of - the statement expr, or discarded. If stmt was compound, but - without new variables, we will have skipped the creation of a - BIND and will have a bare STATEMENT_LIST. But that's OK because - (recursively) all of the component statements should already have - line numbers assigned. ??? Can we discard no-op statements - earlier? */ - if (EXPR_LOCATION (stmt) == UNKNOWN_LOCATION) - protected_set_expr_location (stmt, loc); - - parser->in_if_block = in_if_block; -} - -/* Parse the condition from an if, do, while or for statements. */ - -static tree -c_parser_condition (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - tree cond; - cond = c_parser_expression_conv (parser).value; - cond = c_objc_common_truthvalue_conversion (loc, cond); - cond = c_fully_fold (cond, false, NULL); - if (warn_sequence_point) - verify_sequence_points (cond); - return cond; -} - -/* Parse a parenthesized condition from an if, do or while statement. - - condition: - ( expression ) -*/ -static tree -c_parser_paren_condition (c_parser *parser) -{ - tree cond; - matching_parens parens; - if (!parens.require_open (parser)) - return error_mark_node; - cond = c_parser_condition (parser); - parens.skip_until_found_close (parser); - return cond; -} - -/* Parse a statement which is a block in C99. - - IF_P is used to track whether there's a (possibly labeled) if statement - which is not enclosed in braces and has an else clause. This is used to - implement -Wparentheses. */ - -static tree -c_parser_c99_block_statement (c_parser *parser, bool *if_p, - location_t *loc_after_labels) -{ - tree block = c_begin_compound_stmt (flag_isoc99); - location_t loc = c_parser_peek_token (parser)->location; - c_parser_statement (parser, if_p, loc_after_labels); - return c_end_compound_stmt (loc, block, flag_isoc99); -} - -/* Parse the body of an if statement. This is just parsing a - statement but (a) it is a block in C99, (b) we track whether the - body is an if statement for the sake of -Wparentheses warnings, (c) - we handle an empty body specially for the sake of -Wempty-body - warnings, and (d) we call parser_compound_statement directly - because c_parser_statement_after_labels resets - parser->in_if_block. - - IF_P is used to track whether there's a (possibly labeled) if statement - which is not enclosed in braces and has an else clause. This is used to - implement -Wparentheses. */ - -static tree -c_parser_if_body (c_parser *parser, bool *if_p, - const token_indent_info &if_tinfo) -{ - tree block = c_begin_compound_stmt (flag_isoc99); - location_t body_loc = c_parser_peek_token (parser)->location; - location_t body_loc_after_labels = UNKNOWN_LOCATION; - token_indent_info body_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - - c_parser_all_labels (parser); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - location_t loc = c_parser_peek_token (parser)->location; - add_stmt (build_empty_stmt (loc)); - c_parser_consume_token (parser); - if (!c_parser_next_token_is_keyword (parser, RID_ELSE)) - warning_at (loc, OPT_Wempty_body, - "suggest braces around empty body in an % statement"); - } - else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - add_stmt (c_parser_compound_statement (parser)); - else - { - body_loc_after_labels = c_parser_peek_token (parser)->location; - c_parser_statement_after_labels (parser, if_p); - } - - token_indent_info next_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - warn_for_misleading_indentation (if_tinfo, body_tinfo, next_tinfo); - if (body_loc_after_labels != UNKNOWN_LOCATION - && next_tinfo.type != CPP_SEMICOLON) - warn_for_multistatement_macros (body_loc_after_labels, next_tinfo.location, - if_tinfo.location, RID_IF); - - return c_end_compound_stmt (body_loc, block, flag_isoc99); -} - -/* Parse the else body of an if statement. This is just parsing a - statement but (a) it is a block in C99, (b) we handle an empty body - specially for the sake of -Wempty-body warnings. CHAIN is a vector - of if-else-if conditions. */ - -static tree -c_parser_else_body (c_parser *parser, const token_indent_info &else_tinfo, - vec *chain) -{ - location_t body_loc = c_parser_peek_token (parser)->location; - tree block = c_begin_compound_stmt (flag_isoc99); - token_indent_info body_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - location_t body_loc_after_labels = UNKNOWN_LOCATION; - - c_parser_all_labels (parser); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - location_t loc = c_parser_peek_token (parser)->location; - warning_at (loc, - OPT_Wempty_body, - "suggest braces around empty body in an % statement"); - add_stmt (build_empty_stmt (loc)); - c_parser_consume_token (parser); - } - else - { - if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - body_loc_after_labels = c_parser_peek_token (parser)->location; - c_parser_statement_after_labels (parser, NULL, chain); - } - - token_indent_info next_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - warn_for_misleading_indentation (else_tinfo, body_tinfo, next_tinfo); - if (body_loc_after_labels != UNKNOWN_LOCATION - && next_tinfo.type != CPP_SEMICOLON) - warn_for_multistatement_macros (body_loc_after_labels, next_tinfo.location, - else_tinfo.location, RID_ELSE); - - return c_end_compound_stmt (body_loc, block, flag_isoc99); -} - -/* We might need to reclassify any previously-lexed identifier, e.g. - when we've left a for loop with an if-statement without else in the - body - we might have used a wrong scope for the token. See PR67784. */ - -static void -c_parser_maybe_reclassify_token (c_parser *parser) -{ - if (c_parser_next_token_is (parser, CPP_NAME)) - { - c_token *token = c_parser_peek_token (parser); - - if (token->id_kind != C_ID_CLASSNAME) - { - tree decl = lookup_name (token->value); - - token->id_kind = C_ID_ID; - if (decl) - { - if (TREE_CODE (decl) == TYPE_DECL) - token->id_kind = C_ID_TYPENAME; - } - else if (c_dialect_objc ()) - { - tree objc_interface_decl = objc_is_class_name (token->value); - /* Objective-C class names are in the same namespace as - variables and typedefs, and hence are shadowed by local - declarations. */ - if (objc_interface_decl) - { - token->value = objc_interface_decl; - token->id_kind = C_ID_CLASSNAME; - } - } - } - } -} - -/* Parse an if statement (C90 6.6.4, C99 6.8.4, C11 6.8.4). - - if-statement: - if ( expression ) statement - if ( expression ) statement else statement - - CHAIN is a vector of if-else-if conditions. - IF_P is used to track whether there's a (possibly labeled) if statement - which is not enclosed in braces and has an else clause. This is used to - implement -Wparentheses. */ - -static void -c_parser_if_statement (c_parser *parser, bool *if_p, vec *chain) -{ - tree block; - location_t loc; - tree cond; - bool nested_if = false; - tree first_body, second_body; - bool in_if_block; - - gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF)); - token_indent_info if_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - c_parser_consume_token (parser); - block = c_begin_compound_stmt (flag_isoc99); - loc = c_parser_peek_token (parser)->location; - cond = c_parser_paren_condition (parser); - in_if_block = parser->in_if_block; - parser->in_if_block = true; - first_body = c_parser_if_body (parser, &nested_if, if_tinfo); - parser->in_if_block = in_if_block; - - if (warn_duplicated_cond) - warn_duplicated_cond_add_or_warn (EXPR_LOCATION (cond), cond, &chain); - - if (c_parser_next_token_is_keyword (parser, RID_ELSE)) - { - token_indent_info else_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - c_parser_consume_token (parser); - if (warn_duplicated_cond) - { - if (c_parser_next_token_is_keyword (parser, RID_IF) - && chain == NULL) - { - /* We've got "if (COND) else if (COND2)". Start the - condition chain and add COND as the first element. */ - chain = new vec (); - if (!CONSTANT_CLASS_P (cond) && !TREE_SIDE_EFFECTS (cond)) - chain->safe_push (cond); - } - else if (!c_parser_next_token_is_keyword (parser, RID_IF)) - /* This is if-else without subsequent if. Zap the condition - chain; we would have already warned at this point. */ - vec_free (chain); - } - second_body = c_parser_else_body (parser, else_tinfo, chain); - /* Set IF_P to true to indicate that this if statement has an - else clause. This may trigger the Wparentheses warning - below when we get back up to the parent if statement. */ - if (if_p != NULL) - *if_p = true; - } - else - { - second_body = NULL_TREE; - - /* Diagnose an ambiguous else if if-then-else is nested inside - if-then. */ - if (nested_if) - warning_at (loc, OPT_Wdangling_else, - "suggest explicit braces to avoid ambiguous %"); - - if (warn_duplicated_cond) - /* This if statement does not have an else clause. We don't - need the condition chain anymore. */ - vec_free (chain); - } - c_finish_if_stmt (loc, cond, first_body, second_body); - add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); - - c_parser_maybe_reclassify_token (parser); -} - -/* Parse a switch statement (C90 6.6.4, C99 6.8.4, C11 6.8.4). - - switch-statement: - switch (expression) statement -*/ - -static void -c_parser_switch_statement (c_parser *parser, bool *if_p) -{ - struct c_expr ce; - tree block, expr, body; - unsigned char save_in_statement; - location_t switch_loc = c_parser_peek_token (parser)->location; - location_t switch_cond_loc; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH)); - c_parser_consume_token (parser); - block = c_begin_compound_stmt (flag_isoc99); - bool explicit_cast_p = false; - matching_parens parens; - if (parens.require_open (parser)) - { - switch_cond_loc = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) - && c_token_starts_typename (c_parser_peek_2nd_token (parser))) - explicit_cast_p = true; - ce = c_parser_expression (parser); - ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, true); - expr = ce.value; - /* ??? expr has no valid location? */ - parens.skip_until_found_close (parser); - } - else - { - switch_cond_loc = UNKNOWN_LOCATION; - expr = error_mark_node; - ce.original_type = error_mark_node; - } - c_start_switch (switch_loc, switch_cond_loc, expr, explicit_cast_p); - save_in_statement = in_statement; - in_statement |= IN_SWITCH_STMT; - location_t loc_after_labels; - bool open_brace_p = c_parser_peek_token (parser)->type == CPP_OPEN_BRACE; - body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels); - location_t next_loc = c_parser_peek_token (parser)->location; - if (!open_brace_p && c_parser_peek_token (parser)->type != CPP_SEMICOLON) - warn_for_multistatement_macros (loc_after_labels, next_loc, switch_loc, - RID_SWITCH); - c_finish_switch (body, ce.original_type); - in_statement = save_in_statement; - add_stmt (c_end_compound_stmt (switch_loc, block, flag_isoc99)); - c_parser_maybe_reclassify_token (parser); -} - -/* Parse a while statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). - - while-statement: - while (expression) statement - - IF_P is used to track whether there's a (possibly labeled) if statement - which is not enclosed in braces and has an else clause. This is used to - implement -Wparentheses. */ - -static void -c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, - bool *if_p) -{ - tree block, cond, body; - unsigned char save_in_statement; - location_t loc; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE)); - token_indent_info while_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - c_parser_consume_token (parser); - block = c_begin_compound_stmt (flag_isoc99); - loc = c_parser_peek_token (parser)->location; - cond = c_parser_paren_condition (parser); - if (ivdep && cond != error_mark_node) - cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, - build_int_cst (integer_type_node, - annot_expr_ivdep_kind), - integer_zero_node); - if (unroll && cond != error_mark_node) - cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, - build_int_cst (integer_type_node, - annot_expr_unroll_kind), - build_int_cst (integer_type_node, unroll)); - save_in_statement = in_statement; - in_statement = IN_ITERATION_STMT; - - token_indent_info body_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - - location_t loc_after_labels; - bool open_brace = c_parser_next_token_is (parser, CPP_OPEN_BRACE); - body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels); - add_stmt (build_stmt (loc, WHILE_STMT, cond, body)); - add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); - c_parser_maybe_reclassify_token (parser); - - token_indent_info next_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - warn_for_misleading_indentation (while_tinfo, body_tinfo, next_tinfo); - - if (next_tinfo.type != CPP_SEMICOLON && !open_brace) - warn_for_multistatement_macros (loc_after_labels, next_tinfo.location, - while_tinfo.location, RID_WHILE); - - in_statement = save_in_statement; -} - -/* Parse a do statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). - - do-statement: - do statement while ( expression ) ; -*/ - -static void -c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll) -{ - tree block, cond, body; - unsigned char save_in_statement; - location_t loc; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO)); - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - warning_at (c_parser_peek_token (parser)->location, - OPT_Wempty_body, - "suggest braces around empty body in % statement"); - block = c_begin_compound_stmt (flag_isoc99); - loc = c_parser_peek_token (parser)->location; - save_in_statement = in_statement; - in_statement = IN_ITERATION_STMT; - body = c_parser_c99_block_statement (parser, NULL); - c_parser_require_keyword (parser, RID_WHILE, "expected %"); - in_statement = save_in_statement; - cond = c_parser_paren_condition (parser); - if (ivdep && cond != error_mark_node) - cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, - build_int_cst (integer_type_node, - annot_expr_ivdep_kind), - integer_zero_node); - if (unroll && cond != error_mark_node) - cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, - build_int_cst (integer_type_node, - annot_expr_unroll_kind), - build_int_cst (integer_type_node, unroll)); - if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) - c_parser_skip_to_end_of_block_or_statement (parser); - - add_stmt (build_stmt (loc, DO_STMT, cond, body)); - add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); -} - -/* Parse a for statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). - - for-statement: - for ( expression[opt] ; expression[opt] ; expression[opt] ) statement - for ( nested-declaration expression[opt] ; expression[opt] ) statement - - The form with a declaration is new in C99. - - ??? In accordance with the old parser, the declaration may be a - nested function, which is then rejected in check_for_loop_decls, - but does it make any sense for this to be included in the grammar? - Note in particular that the nested function does not include a - trailing ';', whereas the "declaration" production includes one. - Also, can we reject bad declarations earlier and cheaper than - check_for_loop_decls? - - In Objective-C, there are two additional variants: - - foreach-statement: - for ( expression in expresssion ) statement - for ( declaration in expression ) statement - - This is inconsistent with C, because the second variant is allowed - even if c99 is not enabled. - - The rest of the comment documents these Objective-C foreach-statement. - - Here is the canonical example of the first variant: - for (object in array) { do something with object } - we call the first expression ("object") the "object_expression" and - the second expression ("array") the "collection_expression". - object_expression must be an lvalue of type "id" (a generic Objective-C - object) because the loop works by assigning to object_expression the - various objects from the collection_expression. collection_expression - must evaluate to something of type "id" which responds to the method - countByEnumeratingWithState:objects:count:. - - The canonical example of the second variant is: - for (id object in array) { do something with object } - which is completely equivalent to - { - id object; - for (object in array) { do something with object } - } - Note that initizializing 'object' in some way (eg, "for ((object = - xxx) in array) { do something with object }") is possibly - technically valid, but completely pointless as 'object' will be - assigned to something else as soon as the loop starts. We should - most likely reject it (TODO). - - The beginning of the Objective-C foreach-statement looks exactly - like the beginning of the for-statement, and we can tell it is a - foreach-statement only because the initial declaration or - expression is terminated by 'in' instead of ';'. - - IF_P is used to track whether there's a (possibly labeled) if statement - which is not enclosed in braces and has an else clause. This is used to - implement -Wparentheses. */ - -static void -c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, - bool *if_p) -{ - tree block, cond, incr, body; - unsigned char save_in_statement; - tree save_objc_foreach_break_label, save_objc_foreach_continue_label; - /* The following are only used when parsing an ObjC foreach statement. */ - tree object_expression; - /* Silence the bogus uninitialized warning. */ - tree collection_expression = NULL; - location_t loc = c_parser_peek_token (parser)->location; - location_t for_loc = loc; - bool is_foreach_statement = false; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); - token_indent_info for_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - c_parser_consume_token (parser); - /* Open a compound statement in Objective-C as well, just in case this is - as foreach expression. */ - block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ()); - cond = error_mark_node; - incr = error_mark_node; - matching_parens parens; - if (parens.require_open (parser)) - { - /* Parse the initialization declaration or expression. */ - object_expression = error_mark_node; - parser->objc_could_be_foreach_context = c_dialect_objc (); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - parser->objc_could_be_foreach_context = false; - c_parser_consume_token (parser); - c_finish_expr_stmt (loc, NULL_TREE); - } - else if (c_parser_next_tokens_start_declaration (parser) - || c_parser_nth_token_starts_std_attributes (parser, 1)) - { - c_parser_declaration_or_fndef (parser, true, true, true, true, true, - &object_expression); - parser->objc_could_be_foreach_context = false; - - if (c_parser_next_token_is_keyword (parser, RID_IN)) - { - c_parser_consume_token (parser); - is_foreach_statement = true; - if (check_for_loop_decls (for_loc, true) == NULL_TREE) - c_parser_error (parser, "multiple iterating variables in " - "fast enumeration"); - } - else - check_for_loop_decls (for_loc, flag_isoc99); - } - else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) - { - /* __extension__ can start a declaration, but is also an - unary operator that can start an expression. Consume all - but the last of a possible series of __extension__ to - determine which. */ - while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD - && (c_parser_peek_2nd_token (parser)->keyword - == RID_EXTENSION)) - c_parser_consume_token (parser); - if (c_token_starts_declaration (c_parser_peek_2nd_token (parser)) - || c_parser_nth_token_starts_std_attributes (parser, 2)) - { - int ext; - ext = disable_extension_diagnostics (); - c_parser_consume_token (parser); - c_parser_declaration_or_fndef (parser, true, true, true, true, - true, &object_expression); - parser->objc_could_be_foreach_context = false; - - restore_extension_diagnostics (ext); - if (c_parser_next_token_is_keyword (parser, RID_IN)) - { - c_parser_consume_token (parser); - is_foreach_statement = true; - if (check_for_loop_decls (for_loc, true) == NULL_TREE) - c_parser_error (parser, "multiple iterating variables in " - "fast enumeration"); - } - else - check_for_loop_decls (for_loc, flag_isoc99); - } - else - goto init_expr; - } - else - { - init_expr: - { - struct c_expr ce; - tree init_expression; - ce = c_parser_expression (parser); - init_expression = ce.value; - parser->objc_could_be_foreach_context = false; - if (c_parser_next_token_is_keyword (parser, RID_IN)) - { - c_parser_consume_token (parser); - is_foreach_statement = true; - if (! lvalue_p (init_expression)) - c_parser_error (parser, "invalid iterating variable in " - "fast enumeration"); - object_expression - = c_fully_fold (init_expression, false, NULL); - } - else - { - ce = convert_lvalue_to_rvalue (loc, ce, true, false); - init_expression = ce.value; - c_finish_expr_stmt (loc, init_expression); - c_parser_skip_until_found (parser, CPP_SEMICOLON, - "expected %<;%>"); - } - } - } - /* Parse the loop condition. In the case of a foreach - statement, there is no loop condition. */ - gcc_assert (!parser->objc_could_be_foreach_context); - if (!is_foreach_statement) - { - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - if (ivdep) - { - c_parser_error (parser, "missing loop condition in loop " - "with % pragma"); - cond = error_mark_node; - } - else if (unroll) - { - c_parser_error (parser, "missing loop condition in loop " - "with % pragma"); - cond = error_mark_node; - } - else - { - c_parser_consume_token (parser); - cond = NULL_TREE; - } - } - else - { - cond = c_parser_condition (parser); - c_parser_skip_until_found (parser, CPP_SEMICOLON, - "expected %<;%>"); - } - if (ivdep && cond != error_mark_node) - cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, - build_int_cst (integer_type_node, - annot_expr_ivdep_kind), - integer_zero_node); - if (unroll && cond != error_mark_node) - cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, - build_int_cst (integer_type_node, - annot_expr_unroll_kind), - build_int_cst (integer_type_node, unroll)); - } - /* Parse the increment expression (the third expression in a - for-statement). In the case of a foreach-statement, this is - the expression that follows the 'in'. */ - loc = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - if (is_foreach_statement) - { - c_parser_error (parser, - "missing collection in fast enumeration"); - collection_expression = error_mark_node; - } - else - incr = c_process_expr_stmt (loc, NULL_TREE); - } - else - { - if (is_foreach_statement) - collection_expression - = c_fully_fold (c_parser_expression (parser).value, false, NULL); - else - { - struct c_expr ce = c_parser_expression (parser); - ce = convert_lvalue_to_rvalue (loc, ce, true, false); - incr = c_process_expr_stmt (loc, ce.value); - } - } - parens.skip_until_found_close (parser); - } - save_in_statement = in_statement; - if (is_foreach_statement) - { - in_statement = IN_OBJC_FOREACH; - save_objc_foreach_break_label = objc_foreach_break_label; - save_objc_foreach_continue_label = objc_foreach_continue_label; - objc_foreach_break_label = create_artificial_label (loc); - objc_foreach_continue_label = create_artificial_label (loc); - } - else - in_statement = IN_ITERATION_STMT; - - token_indent_info body_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - - location_t loc_after_labels; - bool open_brace = c_parser_next_token_is (parser, CPP_OPEN_BRACE); - body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels); - - if (is_foreach_statement) - objc_finish_foreach_loop (for_loc, object_expression, - collection_expression, body, - objc_foreach_break_label, - objc_foreach_continue_label); - else - add_stmt (build_stmt (for_loc, FOR_STMT, NULL_TREE, cond, incr, - body, NULL_TREE)); - add_stmt (c_end_compound_stmt (for_loc, block, - flag_isoc99 || c_dialect_objc ())); - c_parser_maybe_reclassify_token (parser); - - token_indent_info next_tinfo - = get_token_indent_info (c_parser_peek_token (parser)); - warn_for_misleading_indentation (for_tinfo, body_tinfo, next_tinfo); - - if (next_tinfo.type != CPP_SEMICOLON && !open_brace) - warn_for_multistatement_macros (loc_after_labels, next_tinfo.location, - for_tinfo.location, RID_FOR); - - in_statement = save_in_statement; - if (is_foreach_statement) - { - objc_foreach_break_label = save_objc_foreach_break_label; - objc_foreach_continue_label = save_objc_foreach_continue_label; - } -} - -/* Parse an asm statement, a GNU extension. This is a full-blown asm - statement with inputs, outputs, clobbers, and volatile, inline, and goto - tags allowed. - - asm-qualifier: - volatile - inline - goto - - asm-qualifier-list: - asm-qualifier-list asm-qualifier - asm-qualifier - - asm-statement: - asm asm-qualifier-list[opt] ( asm-argument ) ; - - asm-argument: - asm-string-literal - asm-string-literal : asm-operands[opt] - asm-string-literal : asm-operands[opt] : asm-operands[opt] - asm-string-literal : asm-operands[opt] : asm-operands[opt] \ - : asm-clobbers[opt] - asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \ - : asm-goto-operands - - The form with asm-goto-operands is valid if and only if the - asm-qualifier-list contains goto, and is the only allowed form in that case. - Duplicate asm-qualifiers are not allowed. - - The :: token is considered equivalent to two consecutive : tokens. */ - -static tree -c_parser_asm_statement (c_parser *parser) -{ - tree str, outputs, inputs, clobbers, labels, ret; - bool simple; - location_t asm_loc = c_parser_peek_token (parser)->location; - int section, nsections; - - gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); - c_parser_consume_token (parser); - - /* Handle the asm-qualifier-list. */ - location_t volatile_loc = UNKNOWN_LOCATION; - location_t inline_loc = UNKNOWN_LOCATION; - location_t goto_loc = UNKNOWN_LOCATION; - for (;;) - { - c_token *token = c_parser_peek_token (parser); - location_t loc = token->location; - switch (token->keyword) - { - case RID_VOLATILE: - if (volatile_loc) - { - error_at (loc, "duplicate % qualifier %qE", token->value); - inform (volatile_loc, "first seen here"); - } - else - volatile_loc = loc; - c_parser_consume_token (parser); - continue; - - case RID_INLINE: - if (inline_loc) - { - error_at (loc, "duplicate % qualifier %qE", token->value); - inform (inline_loc, "first seen here"); - } - else - inline_loc = loc; - c_parser_consume_token (parser); - continue; - - case RID_GOTO: - if (goto_loc) - { - error_at (loc, "duplicate % qualifier %qE", token->value); - inform (goto_loc, "first seen here"); - } - else - goto_loc = loc; - c_parser_consume_token (parser); - continue; - - case RID_CONST: - case RID_RESTRICT: - error_at (loc, "%qE is not a valid % qualifier", token->value); - c_parser_consume_token (parser); - continue; - - default: - break; - } - break; - } - - bool is_volatile = (volatile_loc != UNKNOWN_LOCATION); - bool is_inline = (inline_loc != UNKNOWN_LOCATION); - bool is_goto = (goto_loc != UNKNOWN_LOCATION); - - ret = NULL; - - matching_parens parens; - if (!parens.require_open (parser)) - goto error; - - str = c_parser_asm_string_literal (parser); - if (str == NULL_TREE) - goto error_close_paren; - - simple = true; - outputs = NULL_TREE; - inputs = NULL_TREE; - clobbers = NULL_TREE; - labels = NULL_TREE; - - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto) - goto done_asm; - - /* Parse each colon-delimited section of operands. */ - nsections = 3 + is_goto; - for (section = 0; section < nsections; ++section) - { - if (c_parser_next_token_is (parser, CPP_SCOPE)) - { - ++section; - if (section == nsections) - { - c_parser_error (parser, "expected %<)%>"); - goto error_close_paren; - } - c_parser_consume_token (parser); - } - else if (!c_parser_require (parser, CPP_COLON, - is_goto - ? G_("expected %<:%>") - : G_("expected %<:%> or %<)%>"), - UNKNOWN_LOCATION, is_goto)) - goto error_close_paren; - - /* Once past any colon, we're no longer a simple asm. */ - simple = false; - - if ((!c_parser_next_token_is (parser, CPP_COLON) - && !c_parser_next_token_is (parser, CPP_SCOPE) - && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - || section == 3) - switch (section) - { - case 0: - outputs = c_parser_asm_operands (parser); - break; - case 1: - inputs = c_parser_asm_operands (parser); - break; - case 2: - clobbers = c_parser_asm_clobbers (parser); - break; - case 3: - labels = c_parser_asm_goto_operands (parser); - break; - default: - gcc_unreachable (); - } - - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto) - goto done_asm; - } - - done_asm: - if (!parens.require_close (parser)) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - goto error; - } - - if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) - c_parser_skip_to_end_of_block_or_statement (parser); - - ret = build_asm_stmt (is_volatile, - build_asm_expr (asm_loc, str, outputs, inputs, - clobbers, labels, simple, is_inline)); - - error: - return ret; - - error_close_paren: - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - goto error; -} - -/* Parse asm operands, a GNU extension. - - asm-operands: - asm-operand - asm-operands , asm-operand - - asm-operand: - asm-string-literal ( expression ) - [ identifier ] asm-string-literal ( expression ) -*/ - -static tree -c_parser_asm_operands (c_parser *parser) -{ - tree list = NULL_TREE; - while (true) - { - tree name, str; - struct c_expr expr; - if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) - { - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - tree id = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - name = build_string (IDENTIFIER_LENGTH (id), - IDENTIFIER_POINTER (id)); - } - else - { - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL); - return NULL_TREE; - } - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, - "expected %<]%>"); - } - else - name = NULL_TREE; - str = c_parser_asm_string_literal (parser); - if (str == NULL_TREE) - return NULL_TREE; - matching_parens parens; - if (!parens.require_open (parser)) - return NULL_TREE; - expr = c_parser_expression (parser); - mark_exp_read (expr.value); - if (!parens.require_close (parser)) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return NULL_TREE; - } - list = chainon (list, build_tree_list (build_tree_list (name, str), - expr.value)); - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - return list; -} - -/* Parse asm clobbers, a GNU extension. - - asm-clobbers: - asm-string-literal - asm-clobbers , asm-string-literal -*/ - -static tree -c_parser_asm_clobbers (c_parser *parser) -{ - tree list = NULL_TREE; - while (true) - { - tree str = c_parser_asm_string_literal (parser); - if (str) - list = tree_cons (NULL_TREE, str, list); - else - return NULL_TREE; - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - return list; -} - -/* Parse asm goto labels, a GNU extension. - - asm-goto-operands: - identifier - asm-goto-operands , identifier -*/ - -static tree -c_parser_asm_goto_operands (c_parser *parser) -{ - tree list = NULL_TREE; - while (true) - { - tree name, label; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - c_token *tok = c_parser_peek_token (parser); - name = tok->value; - label = lookup_label_for_goto (tok->location, name); - c_parser_consume_token (parser); - TREE_USED (label) = 1; - } - else - { - c_parser_error (parser, "expected identifier"); - return NULL_TREE; - } - - name = build_string (IDENTIFIER_LENGTH (name), - IDENTIFIER_POINTER (name)); - list = tree_cons (name, label, list); - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - return nreverse (list); - } -} - -/* Parse a possibly concatenated sequence of string literals. - TRANSLATE says whether to translate them to the execution character - set; WIDE_OK says whether any kind of prefixed string literal is - permitted in this context. This code is based on that in - lex_string. */ - -struct c_expr -c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok) -{ - struct c_expr ret; - size_t count; - struct obstack str_ob; - struct obstack loc_ob; - cpp_string str, istr, *strs; - c_token *tok; - location_t loc, last_tok_loc; - enum cpp_ttype type; - tree value, string_tree; - - tok = c_parser_peek_token (parser); - loc = tok->location; - last_tok_loc = linemap_resolve_location (line_table, loc, - LRK_MACRO_DEFINITION_LOCATION, - NULL); - type = tok->type; - switch (type) - { - case CPP_STRING: - case CPP_WSTRING: - case CPP_STRING16: - case CPP_STRING32: - case CPP_UTF8STRING: - string_tree = tok->value; - break; - - default: - c_parser_error (parser, "expected string literal"); - ret.set_error (); - ret.value = NULL_TREE; - ret.original_code = ERROR_MARK; - ret.original_type = NULL_TREE; - return ret; - } - - /* Try to avoid the overhead of creating and destroying an obstack - for the common case of just one string. */ - switch (c_parser_peek_2nd_token (parser)->type) - { - default: - c_parser_consume_token (parser); - str.text = (const unsigned char *) TREE_STRING_POINTER (string_tree); - str.len = TREE_STRING_LENGTH (string_tree); - count = 1; - strs = &str; - break; - - case CPP_STRING: - case CPP_WSTRING: - case CPP_STRING16: - case CPP_STRING32: - case CPP_UTF8STRING: - gcc_obstack_init (&str_ob); - gcc_obstack_init (&loc_ob); - count = 0; - do - { - c_parser_consume_token (parser); - count++; - str.text = (const unsigned char *) TREE_STRING_POINTER (string_tree); - str.len = TREE_STRING_LENGTH (string_tree); - if (type != tok->type) - { - if (type == CPP_STRING) - type = tok->type; - else if (tok->type != CPP_STRING) - error ("unsupported non-standard concatenation " - "of string literals"); - } - obstack_grow (&str_ob, &str, sizeof (cpp_string)); - obstack_grow (&loc_ob, &last_tok_loc, sizeof (location_t)); - tok = c_parser_peek_token (parser); - string_tree = tok->value; - last_tok_loc - = linemap_resolve_location (line_table, tok->location, - LRK_MACRO_DEFINITION_LOCATION, NULL); - } - while (tok->type == CPP_STRING - || tok->type == CPP_WSTRING - || tok->type == CPP_STRING16 - || tok->type == CPP_STRING32 - || tok->type == CPP_UTF8STRING); - strs = (cpp_string *) obstack_finish (&str_ob); - } - - if (count > 1 && !in_system_header_at (input_location)) - warning (OPT_Wtraditional, - "traditional C rejects string constant concatenation"); - - if ((type == CPP_STRING || wide_ok) - && ((translate - ? cpp_interpret_string : cpp_interpret_string_notranslate) - (parse_in, strs, count, &istr, type))) - { - value = build_string (istr.len, (const char *) istr.text); - free (CONST_CAST (unsigned char *, istr.text)); - if (count > 1) - { - location_t *locs = (location_t *) obstack_finish (&loc_ob); - gcc_assert (g_string_concat_db); - g_string_concat_db->record_string_concatenation (count, locs); - } - } - else - { - if (type != CPP_STRING && !wide_ok) - { - error_at (loc, "a wide string is invalid in this context"); - type = CPP_STRING; - } - /* Callers cannot generally handle error_mark_node in this - context, so return the empty string instead. An error has - been issued, either above or from cpp_interpret_string. */ - switch (type) - { - default: - case CPP_STRING: - case CPP_UTF8STRING: - value = build_string (1, ""); - break; - case CPP_STRING16: - value = build_string (TYPE_PRECISION (char16_type_node) - / TYPE_PRECISION (char_type_node), - "\0"); /* char16_t is 16 bits */ - break; - case CPP_STRING32: - value = build_string (TYPE_PRECISION (char32_type_node) - / TYPE_PRECISION (char_type_node), - "\0\0\0"); /* char32_t is 32 bits */ - break; - case CPP_WSTRING: - value = build_string (TYPE_PRECISION (wchar_type_node) - / TYPE_PRECISION (char_type_node), - "\0\0\0"); /* widest supported wchar_t - is 32 bits */ - break; - } - } - - switch (type) - { - default: - case CPP_STRING: - case CPP_UTF8STRING: - TREE_TYPE (value) = char_array_type_node; - break; - case CPP_STRING16: - TREE_TYPE (value) = char16_array_type_node; - break; - case CPP_STRING32: - TREE_TYPE (value) = char32_array_type_node; - break; - case CPP_WSTRING: - TREE_TYPE (value) = wchar_array_type_node; - } - value = fix_string_type (value); - - if (count > 1) - { - obstack_free (&str_ob, 0); - obstack_free (&loc_ob, 0); - } - - ret.value = value; - ret.original_code = STRING_CST; - ret.original_type = NULL_TREE; - set_c_expr_source_range (&ret, get_range_from_loc (line_table, loc)); - parser->seen_string_literal = true; - return ret; -} - -/* Parse an expression other than a compound expression; that is, an - assignment expression (C90 6.3.16, C99 6.5.16, C11 6.5.16). If - AFTER is not NULL then it is an Objective-C message expression which - is the primary-expression starting the expression as an initializer. - - assignment-expression: - conditional-expression - unary-expression assignment-operator assignment-expression - - assignment-operator: one of - = *= /= %= += -= <<= >>= &= ^= |= - - In GNU C we accept any conditional expression on the LHS and - diagnose the invalid lvalue rather than producing a syntax - error. */ - -static struct c_expr -c_parser_expr_no_commas (c_parser *parser, struct c_expr *after, - tree omp_atomic_lhs) -{ - struct c_expr lhs, rhs, ret; - enum tree_code code; - location_t op_location, exp_location; - bool save_in_omp_for = c_in_omp_for; - c_in_omp_for = false; - gcc_assert (!after || c_dialect_objc ()); - lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs); - op_location = c_parser_peek_token (parser)->location; - switch (c_parser_peek_token (parser)->type) - { - case CPP_EQ: - code = NOP_EXPR; - break; - case CPP_MULT_EQ: - code = MULT_EXPR; - break; - case CPP_DIV_EQ: - code = TRUNC_DIV_EXPR; - break; - case CPP_MOD_EQ: - code = TRUNC_MOD_EXPR; - break; - case CPP_PLUS_EQ: - code = PLUS_EXPR; - break; - case CPP_MINUS_EQ: - code = MINUS_EXPR; - break; - case CPP_LSHIFT_EQ: - code = LSHIFT_EXPR; - break; - case CPP_RSHIFT_EQ: - code = RSHIFT_EXPR; - break; - case CPP_AND_EQ: - code = BIT_AND_EXPR; - break; - case CPP_XOR_EQ: - code = BIT_XOR_EXPR; - break; - case CPP_OR_EQ: - code = BIT_IOR_EXPR; - break; - default: - c_in_omp_for = save_in_omp_for; - return lhs; - } - c_parser_consume_token (parser); - exp_location = c_parser_peek_token (parser)->location; - rhs = c_parser_expr_no_commas (parser, NULL); - rhs = convert_lvalue_to_rvalue (exp_location, rhs, true, true); - - ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type, - code, exp_location, rhs.value, - rhs.original_type); - set_c_expr_source_range (&ret, lhs.get_start (), rhs.get_finish ()); - if (code == NOP_EXPR) - ret.original_code = MODIFY_EXPR; - else - { - suppress_warning (ret.value, OPT_Wparentheses); - ret.original_code = ERROR_MARK; - } - ret.original_type = NULL; - c_in_omp_for = save_in_omp_for; - return ret; -} - -/* Parse a conditional expression (C90 6.3.15, C99 6.5.15, C11 6.5.15). If - AFTER is not NULL then it is an Objective-C message expression which is - the primary-expression starting the expression as an initializer. - - conditional-expression: - logical-OR-expression - logical-OR-expression ? expression : conditional-expression - - GNU extensions: - - conditional-expression: - logical-OR-expression ? : conditional-expression -*/ - -static struct c_expr -c_parser_conditional_expression (c_parser *parser, struct c_expr *after, - tree omp_atomic_lhs) -{ - struct c_expr cond, exp1, exp2, ret; - location_t start, cond_loc, colon_loc; - - gcc_assert (!after || c_dialect_objc ()); - - cond = c_parser_binary_expression (parser, after, omp_atomic_lhs); - - if (c_parser_next_token_is_not (parser, CPP_QUERY)) - return cond; - if (cond.value != error_mark_node) - start = cond.get_start (); - else - start = UNKNOWN_LOCATION; - cond_loc = c_parser_peek_token (parser)->location; - cond = convert_lvalue_to_rvalue (cond_loc, cond, true, true); - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COLON)) - { - tree eptype = NULL_TREE; - - location_t middle_loc = c_parser_peek_token (parser)->location; - pedwarn (middle_loc, OPT_Wpedantic, - "ISO C forbids omitting the middle term of a % expression"); - if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR) - { - eptype = TREE_TYPE (cond.value); - cond.value = TREE_OPERAND (cond.value, 0); - } - tree e = cond.value; - while (TREE_CODE (e) == COMPOUND_EXPR) - e = TREE_OPERAND (e, 1); - warn_for_omitted_condop (middle_loc, e); - /* Make sure first operand is calculated only once. */ - exp1.value = save_expr (default_conversion (cond.value)); - if (eptype) - exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value); - exp1.original_type = NULL; - exp1.src_range = cond.src_range; - cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value); - c_inhibit_evaluation_warnings += cond.value == truthvalue_true_node; - } - else - { - cond.value - = c_objc_common_truthvalue_conversion - (cond_loc, default_conversion (cond.value)); - c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node; - exp1 = c_parser_expression_conv (parser); - mark_exp_read (exp1.value); - c_inhibit_evaluation_warnings += - ((cond.value == truthvalue_true_node) - - (cond.value == truthvalue_false_node)); - } - - colon_loc = c_parser_peek_token (parser)->location; - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - { - c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; - ret.set_error (); - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - return ret; - } - { - location_t exp2_loc = c_parser_peek_token (parser)->location; - exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE); - exp2 = convert_lvalue_to_rvalue (exp2_loc, exp2, true, true); - } - c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; - location_t loc1 = make_location (exp1.get_start (), exp1.src_range); - location_t loc2 = make_location (exp2.get_start (), exp2.src_range); - if (__builtin_expect (omp_atomic_lhs != NULL, 0) - && (TREE_CODE (cond.value) == GT_EXPR - || TREE_CODE (cond.value) == LT_EXPR - || TREE_CODE (cond.value) == EQ_EXPR) - && c_tree_equal (exp2.value, omp_atomic_lhs) - && (c_tree_equal (TREE_OPERAND (cond.value, 0), omp_atomic_lhs) - || c_tree_equal (TREE_OPERAND (cond.value, 1), omp_atomic_lhs))) - ret.value = build3_loc (colon_loc, COND_EXPR, TREE_TYPE (omp_atomic_lhs), - cond.value, exp1.value, exp2.value); - else - ret.value - = build_conditional_expr (colon_loc, cond.value, - cond.original_code == C_MAYBE_CONST_EXPR, - exp1.value, exp1.original_type, loc1, - exp2.value, exp2.original_type, loc2); - ret.original_code = ERROR_MARK; - if (exp1.value == error_mark_node || exp2.value == error_mark_node) - ret.original_type = NULL; - else - { - tree t1, t2; - - /* If both sides are enum type, the default conversion will have - made the type of the result be an integer type. We want to - remember the enum types we started with. */ - t1 = exp1.original_type ? exp1.original_type : TREE_TYPE (exp1.value); - t2 = exp2.original_type ? exp2.original_type : TREE_TYPE (exp2.value); - ret.original_type = ((t1 != error_mark_node - && t2 != error_mark_node - && (TYPE_MAIN_VARIANT (t1) - == TYPE_MAIN_VARIANT (t2))) - ? t1 - : NULL); - } - set_c_expr_source_range (&ret, start, exp2.get_finish ()); - return ret; -} - -/* Parse a binary expression; that is, a logical-OR-expression (C90 - 6.3.5-6.3.14, C99 6.5.5-6.5.14, C11 6.5.5-6.5.14). If AFTER is not - NULL then it is an Objective-C message expression which is the - primary-expression starting the expression as an initializer. - - OMP_ATOMIC_LHS is NULL, unless parsing OpenMP #pragma omp atomic, - when it should be the unfolded lhs. In a valid OpenMP source, - one of the operands of the toplevel binary expression must be equal - to it. In that case, just return a build2 created binary operation - rather than result of parser_build_binary_op. - - multiplicative-expression: - cast-expression - multiplicative-expression * cast-expression - multiplicative-expression / cast-expression - multiplicative-expression % cast-expression - - additive-expression: - multiplicative-expression - additive-expression + multiplicative-expression - additive-expression - multiplicative-expression - - shift-expression: - additive-expression - shift-expression << additive-expression - shift-expression >> additive-expression - - relational-expression: - shift-expression - relational-expression < shift-expression - relational-expression > shift-expression - relational-expression <= shift-expression - relational-expression >= shift-expression - - equality-expression: - relational-expression - equality-expression == relational-expression - equality-expression != relational-expression - - AND-expression: - equality-expression - AND-expression & equality-expression - - exclusive-OR-expression: - AND-expression - exclusive-OR-expression ^ AND-expression - - inclusive-OR-expression: - exclusive-OR-expression - inclusive-OR-expression | exclusive-OR-expression - - logical-AND-expression: - inclusive-OR-expression - logical-AND-expression && inclusive-OR-expression - - logical-OR-expression: - logical-AND-expression - logical-OR-expression || logical-AND-expression -*/ - -static struct c_expr -c_parser_binary_expression (c_parser *parser, struct c_expr *after, - tree omp_atomic_lhs) -{ - /* A binary expression is parsed using operator-precedence parsing, - with the operands being cast expressions. All the binary - operators are left-associative. Thus a binary expression is of - form: - - E0 op1 E1 op2 E2 ... - - which we represent on a stack. On the stack, the precedence - levels are strictly increasing. When a new operator is - encountered of higher precedence than that at the top of the - stack, it is pushed; its LHS is the top expression, and its RHS - is everything parsed until it is popped. When a new operator is - encountered with precedence less than or equal to that at the top - of the stack, triples E[i-1] op[i] E[i] are popped and replaced - by the result of the operation until the operator at the top of - the stack has lower precedence than the new operator or there is - only one element on the stack; then the top expression is the LHS - of the new operator. In the case of logical AND and OR - expressions, we also need to adjust c_inhibit_evaluation_warnings - as appropriate when the operators are pushed and popped. */ - - struct { - /* The expression at this stack level. */ - struct c_expr expr; - /* The precedence of the operator on its left, PREC_NONE at the - bottom of the stack. */ - enum c_parser_prec prec; - /* The operation on its left. */ - enum tree_code op; - /* The source location of this operation. */ - location_t loc; - /* The sizeof argument if expr.original_code == {PAREN_,}SIZEOF_EXPR. */ - tree sizeof_arg; - } stack[NUM_PRECS]; - int sp; - /* Location of the binary operator. */ - location_t binary_loc = UNKNOWN_LOCATION; /* Quiet warning. */ -#define POP \ - do { \ - switch (stack[sp].op) \ - { \ - case TRUTH_ANDIF_EXPR: \ - c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ - == truthvalue_false_node); \ - break; \ - case TRUTH_ORIF_EXPR: \ - c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ - == truthvalue_true_node); \ - break; \ - case TRUNC_DIV_EXPR: \ - if ((stack[sp - 1].expr.original_code == SIZEOF_EXPR \ - || stack[sp - 1].expr.original_code == PAREN_SIZEOF_EXPR) \ - && (stack[sp].expr.original_code == SIZEOF_EXPR \ - || stack[sp].expr.original_code == PAREN_SIZEOF_EXPR)) \ - { \ - tree type0 = stack[sp - 1].sizeof_arg; \ - tree type1 = stack[sp].sizeof_arg; \ - tree first_arg = type0; \ - if (!TYPE_P (type0)) \ - type0 = TREE_TYPE (type0); \ - if (!TYPE_P (type1)) \ - type1 = TREE_TYPE (type1); \ - if (POINTER_TYPE_P (type0) \ - && comptypes (TREE_TYPE (type0), type1) \ - && !(TREE_CODE (first_arg) == PARM_DECL \ - && C_ARRAY_PARAMETER (first_arg) \ - && warn_sizeof_array_argument)) \ - { \ - auto_diagnostic_group d; \ - if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \ - "division % " \ - "does not compute the number of array " \ - "elements", \ - type0, type1)) \ - if (DECL_P (first_arg)) \ - inform (DECL_SOURCE_LOCATION (first_arg), \ - "first % operand was declared here"); \ - } \ - else if (TREE_CODE (type0) == ARRAY_TYPE \ - && !char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type0))) \ - && stack[sp].expr.original_code != PAREN_SIZEOF_EXPR) \ - maybe_warn_sizeof_array_div (stack[sp].loc, first_arg, type0, \ - stack[sp].sizeof_arg, type1); \ - } \ - break; \ - default: \ - break; \ - } \ - stack[sp - 1].expr \ - = convert_lvalue_to_rvalue (stack[sp - 1].loc, \ - stack[sp - 1].expr, true, true); \ - stack[sp].expr \ - = convert_lvalue_to_rvalue (stack[sp].loc, \ - stack[sp].expr, true, true); \ - if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 \ - && ((c_parser_next_token_is (parser, CPP_SEMICOLON) \ - && ((1 << stack[sp].prec) \ - & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) \ - | (1 << PREC_BITAND) | (1 << PREC_SHIFT) \ - | (1 << PREC_ADD) | (1 << PREC_MULT) \ - | (1 << PREC_EQ)))) \ - || ((c_parser_next_token_is (parser, CPP_QUERY) \ - || (omp_atomic_lhs == void_list_node \ - && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) \ - && (stack[sp].prec == PREC_REL || stack[sp].prec == PREC_EQ)))\ - && stack[sp].op != TRUNC_MOD_EXPR \ - && stack[sp].op != GE_EXPR \ - && stack[sp].op != LE_EXPR \ - && stack[sp].op != NE_EXPR \ - && stack[0].expr.value != error_mark_node \ - && stack[1].expr.value != error_mark_node \ - && (omp_atomic_lhs == void_list_node \ - || c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \ - || c_tree_equal (stack[1].expr.value, omp_atomic_lhs) \ - || (stack[sp].op == EQ_EXPR \ - && c_parser_peek_2nd_token (parser)->keyword == RID_IF))) \ - { \ - tree t = make_node (stack[1].op); \ - TREE_TYPE (t) = TREE_TYPE (stack[0].expr.value); \ - TREE_OPERAND (t, 0) = stack[0].expr.value; \ - TREE_OPERAND (t, 1) = stack[1].expr.value; \ - stack[0].expr.value = t; \ - } \ - else \ - stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ - stack[sp].op, \ - stack[sp - 1].expr, \ - stack[sp].expr); \ - sp--; \ - } while (0) - gcc_assert (!after || c_dialect_objc ()); - stack[0].loc = c_parser_peek_token (parser)->location; - stack[0].expr = c_parser_cast_expression (parser, after); - stack[0].prec = PREC_NONE; - stack[0].sizeof_arg = c_last_sizeof_arg; - sp = 0; - while (true) - { - enum c_parser_prec oprec; - enum tree_code ocode; - source_range src_range; - if (parser->error) - goto out; - switch (c_parser_peek_token (parser)->type) - { - case CPP_MULT: - oprec = PREC_MULT; - ocode = MULT_EXPR; - break; - case CPP_DIV: - oprec = PREC_MULT; - ocode = TRUNC_DIV_EXPR; - break; - case CPP_MOD: - oprec = PREC_MULT; - ocode = TRUNC_MOD_EXPR; - break; - case CPP_PLUS: - oprec = PREC_ADD; - ocode = PLUS_EXPR; - break; - case CPP_MINUS: - oprec = PREC_ADD; - ocode = MINUS_EXPR; - break; - case CPP_LSHIFT: - oprec = PREC_SHIFT; - ocode = LSHIFT_EXPR; - break; - case CPP_RSHIFT: - oprec = PREC_SHIFT; - ocode = RSHIFT_EXPR; - break; - case CPP_LESS: - oprec = PREC_REL; - ocode = LT_EXPR; - break; - case CPP_GREATER: - oprec = PREC_REL; - ocode = GT_EXPR; - break; - case CPP_LESS_EQ: - oprec = PREC_REL; - ocode = LE_EXPR; - break; - case CPP_GREATER_EQ: - oprec = PREC_REL; - ocode = GE_EXPR; - break; - case CPP_EQ_EQ: - oprec = PREC_EQ; - ocode = EQ_EXPR; - break; - case CPP_NOT_EQ: - oprec = PREC_EQ; - ocode = NE_EXPR; - break; - case CPP_AND: - oprec = PREC_BITAND; - ocode = BIT_AND_EXPR; - break; - case CPP_XOR: - oprec = PREC_BITXOR; - ocode = BIT_XOR_EXPR; - break; - case CPP_OR: - oprec = PREC_BITOR; - ocode = BIT_IOR_EXPR; - break; - case CPP_AND_AND: - oprec = PREC_LOGAND; - ocode = TRUTH_ANDIF_EXPR; - break; - case CPP_OR_OR: - oprec = PREC_LOGOR; - ocode = TRUTH_ORIF_EXPR; - break; - default: - /* Not a binary operator, so end of the binary - expression. */ - goto out; - } - binary_loc = c_parser_peek_token (parser)->location; - while (oprec <= stack[sp].prec) - POP; - c_parser_consume_token (parser); - switch (ocode) - { - case TRUTH_ANDIF_EXPR: - src_range = stack[sp].expr.src_range; - stack[sp].expr - = convert_lvalue_to_rvalue (stack[sp].loc, - stack[sp].expr, true, true); - stack[sp].expr.value = c_objc_common_truthvalue_conversion - (stack[sp].loc, default_conversion (stack[sp].expr.value)); - c_inhibit_evaluation_warnings += (stack[sp].expr.value - == truthvalue_false_node); - set_c_expr_source_range (&stack[sp].expr, src_range); - break; - case TRUTH_ORIF_EXPR: - src_range = stack[sp].expr.src_range; - stack[sp].expr - = convert_lvalue_to_rvalue (stack[sp].loc, - stack[sp].expr, true, true); - stack[sp].expr.value = c_objc_common_truthvalue_conversion - (stack[sp].loc, default_conversion (stack[sp].expr.value)); - c_inhibit_evaluation_warnings += (stack[sp].expr.value - == truthvalue_true_node); - set_c_expr_source_range (&stack[sp].expr, src_range); - break; - default: - break; - } - sp++; - stack[sp].loc = binary_loc; - stack[sp].expr = c_parser_cast_expression (parser, NULL); - stack[sp].prec = oprec; - stack[sp].op = ocode; - stack[sp].sizeof_arg = c_last_sizeof_arg; - } - out: - while (sp > 0) - POP; - return stack[0].expr; -#undef POP -} - -/* Parse a cast expression (C90 6.3.4, C99 6.5.4, C11 6.5.4). If AFTER - is not NULL then it is an Objective-C message expression which is the - primary-expression starting the expression as an initializer. - - cast-expression: - unary-expression - ( type-name ) unary-expression -*/ - -static struct c_expr -c_parser_cast_expression (c_parser *parser, struct c_expr *after) -{ - location_t cast_loc = c_parser_peek_token (parser)->location; - gcc_assert (!after || c_dialect_objc ()); - if (after) - return c_parser_postfix_expression_after_primary (parser, - cast_loc, *after); - /* If the expression begins with a parenthesized type name, it may - be either a cast or a compound literal; we need to see whether - the next character is '{' to tell the difference. If not, it is - an unary expression. Full detection of unknown typenames here - would require a 3-token lookahead. */ - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) - && c_token_starts_typename (c_parser_peek_2nd_token (parser))) - { - struct c_type_name *type_name; - struct c_expr ret; - struct c_expr expr; - matching_parens parens; - parens.consume_open (parser); - type_name = c_parser_type_name (parser, true); - parens.skip_until_found_close (parser); - if (type_name == NULL) - { - ret.set_error (); - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - return ret; - } - - /* Save casted types in the function's used types hash table. */ - used_types_insert (type_name->specs->type); - - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - return c_parser_postfix_expression_after_paren_type (parser, type_name, - cast_loc); - if (type_name->specs->alignas_p) - error_at (type_name->specs->locations[cdw_alignas], - "alignment specified for type name in cast"); - { - location_t expr_loc = c_parser_peek_token (parser)->location; - expr = c_parser_cast_expression (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true); - } - ret.value = c_cast_expr (cast_loc, type_name, expr.value); - if (ret.value && expr.value) - set_c_expr_source_range (&ret, cast_loc, expr.get_finish ()); - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - return ret; - } - else - return c_parser_unary_expression (parser); -} - -/* Parse an unary expression (C90 6.3.3, C99 6.5.3, C11 6.5.3). - - unary-expression: - postfix-expression - ++ unary-expression - -- unary-expression - unary-operator cast-expression - sizeof unary-expression - sizeof ( type-name ) - - unary-operator: one of - & * + - ~ ! - - GNU extensions: - - unary-expression: - __alignof__ unary-expression - __alignof__ ( type-name ) - && identifier - - (C11 permits _Alignof with type names only.) - - unary-operator: one of - __extension__ __real__ __imag__ - - Transactional Memory: - - unary-expression: - transaction-expression - - In addition, the GNU syntax treats ++ and -- as unary operators, so - they may be applied to cast expressions with errors for non-lvalues - given later. */ - -static struct c_expr -c_parser_unary_expression (c_parser *parser) -{ - int ext; - struct c_expr ret, op; - location_t op_loc = c_parser_peek_token (parser)->location; - location_t exp_loc; - location_t finish; - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - switch (c_parser_peek_token (parser)->type) - { - case CPP_PLUS_PLUS: - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - - op = default_function_array_read_conversion (exp_loc, op); - return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op); - case CPP_MINUS_MINUS: - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - - op = default_function_array_read_conversion (exp_loc, op); - return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); - case CPP_AND: - c_parser_consume_token (parser); - op = c_parser_cast_expression (parser, NULL); - mark_exp_read (op.value); - return parser_build_unary_op (op_loc, ADDR_EXPR, op); - case CPP_MULT: - { - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - finish = op.get_finish (); - op = convert_lvalue_to_rvalue (exp_loc, op, true, true); - location_t combined_loc = make_location (op_loc, op_loc, finish); - ret.value = build_indirect_ref (combined_loc, op.value, RO_UNARY_STAR); - ret.src_range.m_start = op_loc; - ret.src_range.m_finish = finish; - return ret; - } - case CPP_PLUS: - if (!c_dialect_objc () && !in_system_header_at (input_location)) - warning_at (op_loc, - OPT_Wtraditional, - "traditional C rejects the unary plus operator"); - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - op = convert_lvalue_to_rvalue (exp_loc, op, true, true); - return parser_build_unary_op (op_loc, CONVERT_EXPR, op); - case CPP_MINUS: - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - op = convert_lvalue_to_rvalue (exp_loc, op, true, true); - return parser_build_unary_op (op_loc, NEGATE_EXPR, op); - case CPP_COMPL: - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - op = convert_lvalue_to_rvalue (exp_loc, op, true, true); - return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); - case CPP_NOT: - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - op = convert_lvalue_to_rvalue (exp_loc, op, true, true); - return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op); - case CPP_AND_AND: - /* Refer to the address of a label as a pointer. */ - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - ret.value = finish_label_address_expr - (c_parser_peek_token (parser)->value, op_loc); - set_c_expr_source_range (&ret, op_loc, - c_parser_peek_token (parser)->get_finish ()); - c_parser_consume_token (parser); - } - else - { - c_parser_error (parser, "expected identifier"); - ret.set_error (); - } - return ret; - case CPP_KEYWORD: - switch (c_parser_peek_token (parser)->keyword) - { - case RID_SIZEOF: - return c_parser_sizeof_expression (parser); - case RID_ALIGNOF: - return c_parser_alignof_expression (parser); - case RID_BUILTIN_HAS_ATTRIBUTE: - return c_parser_has_attribute_expression (parser); - case RID_EXTENSION: - c_parser_consume_token (parser); - ext = disable_extension_diagnostics (); - ret = c_parser_cast_expression (parser, NULL); - restore_extension_diagnostics (ext); - return ret; - case RID_REALPART: - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); - return parser_build_unary_op (op_loc, REALPART_EXPR, op); - case RID_IMAGPART: - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); - return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); - case RID_TRANSACTION_ATOMIC: - case RID_TRANSACTION_RELAXED: - return c_parser_transaction_expression (parser, - c_parser_peek_token (parser)->keyword); - default: - return c_parser_postfix_expression (parser); - } - default: - return c_parser_postfix_expression (parser); - } -} - -/* Parse a sizeof expression. */ - -static struct c_expr -c_parser_sizeof_expression (c_parser *parser) -{ - struct c_expr expr; - struct c_expr result; - location_t expr_loc; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); - - location_t start; - location_t finish = UNKNOWN_LOCATION; - - start = c_parser_peek_token (parser)->location; - - c_parser_consume_token (parser); - c_inhibit_evaluation_warnings++; - in_sizeof++; - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) - && c_token_starts_typename (c_parser_peek_2nd_token (parser))) - { - /* Either sizeof ( type-name ) or sizeof unary-expression - starting with a compound literal. */ - struct c_type_name *type_name; - matching_parens parens; - parens.consume_open (parser); - expr_loc = c_parser_peek_token (parser)->location; - type_name = c_parser_type_name (parser, true); - parens.skip_until_found_close (parser); - finish = parser->tokens_buf[0].location; - if (type_name == NULL) - { - struct c_expr ret; - c_inhibit_evaluation_warnings--; - in_sizeof--; - ret.set_error (); - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - return ret; - } - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - { - expr = c_parser_postfix_expression_after_paren_type (parser, - type_name, - expr_loc); - finish = expr.get_finish (); - goto sizeof_expr; - } - /* sizeof ( type-name ). */ - if (type_name->specs->alignas_p) - error_at (type_name->specs->locations[cdw_alignas], - "alignment specified for type name in %"); - c_inhibit_evaluation_warnings--; - in_sizeof--; - result = c_expr_sizeof_type (expr_loc, type_name); - } - else - { - expr_loc = c_parser_peek_token (parser)->location; - expr = c_parser_unary_expression (parser); - finish = expr.get_finish (); - sizeof_expr: - c_inhibit_evaluation_warnings--; - in_sizeof--; - mark_exp_read (expr.value); - if (TREE_CODE (expr.value) == COMPONENT_REF - && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) - error_at (expr_loc, "% applied to a bit-field"); - result = c_expr_sizeof_expr (expr_loc, expr); - } - if (finish == UNKNOWN_LOCATION) - finish = start; - set_c_expr_source_range (&result, start, finish); - return result; -} - -/* Parse an alignof expression. */ - -static struct c_expr -c_parser_alignof_expression (c_parser *parser) -{ - struct c_expr expr; - location_t start_loc = c_parser_peek_token (parser)->location; - location_t end_loc; - tree alignof_spelling = c_parser_peek_token (parser)->value; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF)); - bool is_c11_alignof = strcmp (IDENTIFIER_POINTER (alignof_spelling), - "_Alignof") == 0; - /* A diagnostic is not required for the use of this identifier in - the implementation namespace; only diagnose it for the C11 - spelling because of existing code using the other spellings. */ - if (is_c11_alignof) - { - if (flag_isoc99) - pedwarn_c99 (start_loc, OPT_Wpedantic, "ISO C99 does not support %qE", - alignof_spelling); - else - pedwarn_c99 (start_loc, OPT_Wpedantic, "ISO C90 does not support %qE", - alignof_spelling); - } - c_parser_consume_token (parser); - c_inhibit_evaluation_warnings++; - in_alignof++; - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) - && c_token_starts_typename (c_parser_peek_2nd_token (parser))) - { - /* Either __alignof__ ( type-name ) or __alignof__ - unary-expression starting with a compound literal. */ - location_t loc; - struct c_type_name *type_name; - struct c_expr ret; - matching_parens parens; - parens.consume_open (parser); - loc = c_parser_peek_token (parser)->location; - type_name = c_parser_type_name (parser, true); - end_loc = c_parser_peek_token (parser)->location; - parens.skip_until_found_close (parser); - if (type_name == NULL) - { - struct c_expr ret; - c_inhibit_evaluation_warnings--; - in_alignof--; - ret.set_error (); - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - return ret; - } - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - { - expr = c_parser_postfix_expression_after_paren_type (parser, - type_name, - loc); - goto alignof_expr; - } - /* alignof ( type-name ). */ - if (type_name->specs->alignas_p) - error_at (type_name->specs->locations[cdw_alignas], - "alignment specified for type name in %qE", - alignof_spelling); - c_inhibit_evaluation_warnings--; - in_alignof--; - ret.value = c_sizeof_or_alignof_type (loc, groktypename (type_name, - NULL, NULL), - false, is_c11_alignof, 1); - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - set_c_expr_source_range (&ret, start_loc, end_loc); - return ret; - } - else - { - struct c_expr ret; - expr = c_parser_unary_expression (parser); - end_loc = expr.src_range.m_finish; - alignof_expr: - mark_exp_read (expr.value); - c_inhibit_evaluation_warnings--; - in_alignof--; - if (is_c11_alignof) - pedwarn (start_loc, - OPT_Wpedantic, "ISO C does not allow %<%E (expression)%>", - alignof_spelling); - ret.value = c_alignof_expr (start_loc, expr.value); - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - set_c_expr_source_range (&ret, start_loc, end_loc); - return ret; - } -} - -/* Parse the __builtin_has_attribute ([expr|type], attribute-spec) - expression. */ - -static struct c_expr -c_parser_has_attribute_expression (c_parser *parser) -{ - gcc_assert (c_parser_next_token_is_keyword (parser, - RID_BUILTIN_HAS_ATTRIBUTE)); - location_t start = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - - c_inhibit_evaluation_warnings++; - - matching_parens parens; - if (!parens.require_open (parser)) - { - c_inhibit_evaluation_warnings--; - in_typeof--; - - struct c_expr result; - result.set_error (); - result.original_code = ERROR_MARK; - result.original_type = NULL; - return result; - } - - /* Treat the type argument the same way as in typeof for the purposes - of warnings. FIXME: Generalize this so the warning refers to - __builtin_has_attribute rather than typeof. */ - in_typeof++; - - /* The first operand: one of DECL, EXPR, or TYPE. */ - tree oper = NULL_TREE; - if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) - { - struct c_type_name *tname = c_parser_type_name (parser); - in_typeof--; - if (tname) - { - oper = groktypename (tname, NULL, NULL); - pop_maybe_used (variably_modified_type_p (oper, NULL_TREE)); - } - } - else - { - struct c_expr cexpr = c_parser_expr_no_commas (parser, NULL); - c_inhibit_evaluation_warnings--; - in_typeof--; - if (cexpr.value != error_mark_node) - { - mark_exp_read (cexpr.value); - oper = cexpr.value; - tree etype = TREE_TYPE (oper); - bool was_vm = variably_modified_type_p (etype, NULL_TREE); - /* This is returned with the type so that when the type is - evaluated, this can be evaluated. */ - if (was_vm) - oper = c_fully_fold (oper, false, NULL); - pop_maybe_used (was_vm); - } - } - - struct c_expr result; - result.original_code = ERROR_MARK; - result.original_type = NULL; - - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - { - /* Consume the closing parenthesis if that's the next token - in the likely case the built-in was invoked with fewer - than two arguments. */ - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - c_parser_consume_token (parser); - c_inhibit_evaluation_warnings--; - result.set_error (); - return result; - } - - bool save_translate_strings_p = parser->translate_strings_p; - - location_t atloc = c_parser_peek_token (parser)->location; - /* Parse a single attribute. Require no leading comma and do not - allow empty attributes. */ - tree attr = c_parser_gnu_attribute (parser, NULL_TREE, false, false); - - parser->translate_strings_p = save_translate_strings_p; - - location_t finish = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - c_parser_consume_token (parser); - else - { - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - - result.set_error (); - return result; - } - - if (!attr) - { - error_at (atloc, "expected identifier"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - result.set_error (); - return result; - } - - result.original_code = INTEGER_CST; - result.original_type = boolean_type_node; - - if (has_attribute (atloc, oper, attr, default_conversion)) - result.value = boolean_true_node; - else - result.value = boolean_false_node; - - set_c_expr_source_range (&result, start, finish); - return result; -} - -/* Helper function to read arguments of builtins which are interfaces - for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and - others. The name of the builtin is passed using BNAME parameter. - Function returns true if there were no errors while parsing and - stores the arguments in CEXPR_LIST. If it returns true, - *OUT_CLOSE_PAREN_LOC is written to with the location of the closing - parenthesis. */ -static bool -c_parser_get_builtin_args (c_parser *parser, const char *bname, - vec **ret_cexpr_list, - bool choose_expr_p, - location_t *out_close_paren_loc) -{ - location_t loc = c_parser_peek_token (parser)->location; - vec *cexpr_list; - c_expr_t expr; - bool saved_force_folding_builtin_constant_p; - - *ret_cexpr_list = NULL; - if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) - { - error_at (loc, "cannot take address of %qs", bname); - return false; - } - - c_parser_consume_token (parser); - - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - *out_close_paren_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - return true; - } - - saved_force_folding_builtin_constant_p - = force_folding_builtin_constant_p; - force_folding_builtin_constant_p |= choose_expr_p; - expr = c_parser_expr_no_commas (parser, NULL); - force_folding_builtin_constant_p - = saved_force_folding_builtin_constant_p; - vec_alloc (cexpr_list, 1); - vec_safe_push (cexpr_list, expr); - while (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - expr = c_parser_expr_no_commas (parser, NULL); - vec_safe_push (cexpr_list, expr); - } - - *out_close_paren_loc = c_parser_peek_token (parser)->location; - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - return false; - - *ret_cexpr_list = cexpr_list; - return true; -} - -/* This represents a single generic-association. */ - -struct c_generic_association -{ - /* The location of the starting token of the type. */ - location_t type_location; - /* The association's type, or NULL_TREE for 'default'. */ - tree type; - /* The association's expression. */ - struct c_expr expression; -}; - -/* Parse a generic-selection. (C11 6.5.1.1). - - generic-selection: - _Generic ( assignment-expression , generic-assoc-list ) - - generic-assoc-list: - generic-association - generic-assoc-list , generic-association - - generic-association: - type-name : assignment-expression - default : assignment-expression -*/ - -static struct c_expr -c_parser_generic_selection (c_parser *parser) -{ - struct c_expr selector, error_expr; - tree selector_type; - struct c_generic_association matched_assoc; - int match_found = -1; - location_t generic_loc, selector_loc; - - error_expr.original_code = ERROR_MARK; - error_expr.original_type = NULL; - error_expr.set_error (); - matched_assoc.type_location = UNKNOWN_LOCATION; - matched_assoc.type = NULL_TREE; - matched_assoc.expression = error_expr; - - gcc_assert (c_parser_next_token_is_keyword (parser, RID_GENERIC)); - generic_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - if (flag_isoc99) - pedwarn_c99 (generic_loc, OPT_Wpedantic, - "ISO C99 does not support %<_Generic%>"); - else - pedwarn_c99 (generic_loc, OPT_Wpedantic, - "ISO C90 does not support %<_Generic%>"); - - matching_parens parens; - if (!parens.require_open (parser)) - return error_expr; - - c_inhibit_evaluation_warnings++; - selector_loc = c_parser_peek_token (parser)->location; - selector = c_parser_expr_no_commas (parser, NULL); - selector = default_function_array_conversion (selector_loc, selector); - c_inhibit_evaluation_warnings--; - - if (selector.value == error_mark_node) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return selector; - } - mark_exp_read (selector.value); - selector_type = TREE_TYPE (selector.value); - /* In ISO C terms, rvalues (including the controlling expression of - _Generic) do not have qualified types. */ - if (TREE_CODE (selector_type) != ARRAY_TYPE) - selector_type = TYPE_MAIN_VARIANT (selector_type); - /* In ISO C terms, _Noreturn is not part of the type of expressions - such as &abort, but in GCC it is represented internally as a type - qualifier. */ - if (FUNCTION_POINTER_TYPE_P (selector_type) - && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED) - selector_type - = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type))); - - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return error_expr; - } - - auto_vec associations; - while (1) - { - struct c_generic_association assoc, *iter; - unsigned int ix; - c_token *token = c_parser_peek_token (parser); - - assoc.type_location = token->location; - if (token->type == CPP_KEYWORD && token->keyword == RID_DEFAULT) - { - c_parser_consume_token (parser); - assoc.type = NULL_TREE; - } - else - { - struct c_type_name *type_name; - - type_name = c_parser_type_name (parser); - if (type_name == NULL) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return error_expr; - } - assoc.type = groktypename (type_name, NULL, NULL); - if (assoc.type == error_mark_node) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return error_expr; - } - - if (TREE_CODE (assoc.type) == FUNCTION_TYPE) - error_at (assoc.type_location, - "%<_Generic%> association has function type"); - else if (!COMPLETE_TYPE_P (assoc.type)) - error_at (assoc.type_location, - "%<_Generic%> association has incomplete type"); - - if (variably_modified_type_p (assoc.type, NULL_TREE)) - error_at (assoc.type_location, - "%<_Generic%> association has " - "variable length type"); - } - - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return error_expr; - } - - assoc.expression = c_parser_expr_no_commas (parser, NULL); - if (assoc.expression.value == error_mark_node) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return error_expr; - } - - for (ix = 0; associations.iterate (ix, &iter); ++ix) - { - if (assoc.type == NULL_TREE) - { - if (iter->type == NULL_TREE) - { - error_at (assoc.type_location, - "duplicate % case in %<_Generic%>"); - inform (iter->type_location, "original % is here"); - } - } - else if (iter->type != NULL_TREE) - { - if (comptypes (assoc.type, iter->type)) - { - error_at (assoc.type_location, - "%<_Generic%> specifies two compatible types"); - inform (iter->type_location, "compatible type is here"); - } - } - } - - if (assoc.type == NULL_TREE) - { - if (match_found < 0) - { - matched_assoc = assoc; - match_found = associations.length (); - } - } - else if (comptypes (assoc.type, selector_type)) - { - if (match_found < 0 || matched_assoc.type == NULL_TREE) - { - matched_assoc = assoc; - match_found = associations.length (); - } - else - { - error_at (assoc.type_location, - "%<_Generic%> selector matches multiple associations"); - inform (matched_assoc.type_location, - "other match is here"); - } - } - - associations.safe_push (assoc); - - if (c_parser_peek_token (parser)->type != CPP_COMMA) - break; - c_parser_consume_token (parser); - } - - unsigned int ix; - struct c_generic_association *iter; - FOR_EACH_VEC_ELT (associations, ix, iter) - if (ix != (unsigned) match_found) - mark_exp_read (iter->expression.value); - - if (!parens.require_close (parser)) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return error_expr; - } - - if (match_found < 0) - { - error_at (selector_loc, "%<_Generic%> selector of type %qT is not " - "compatible with any association", - selector_type); - return error_expr; - } - - return matched_assoc.expression; -} - -/* Check the validity of a function pointer argument *EXPR (argument - position POS) to __builtin_tgmath. Return the number of function - arguments if possibly valid; return 0 having reported an error if - not valid. */ - -static unsigned int -check_tgmath_function (c_expr *expr, unsigned int pos) -{ - tree type = TREE_TYPE (expr->value); - if (!FUNCTION_POINTER_TYPE_P (type)) - { - error_at (expr->get_location (), - "argument %u of %<__builtin_tgmath%> is not a function pointer", - pos); - return 0; - } - type = TREE_TYPE (type); - if (!prototype_p (type)) - { - error_at (expr->get_location (), - "argument %u of %<__builtin_tgmath%> is unprototyped", pos); - return 0; - } - if (stdarg_p (type)) - { - error_at (expr->get_location (), - "argument %u of %<__builtin_tgmath%> has variable arguments", - pos); - return 0; - } - unsigned int nargs = 0; - function_args_iterator iter; - tree t; - FOREACH_FUNCTION_ARGS (type, t, iter) - { - if (t == void_type_node) - break; - nargs++; - } - if (nargs == 0) - { - error_at (expr->get_location (), - "argument %u of %<__builtin_tgmath%> has no arguments", pos); - return 0; - } - return nargs; -} - -/* Ways in which a parameter or return value of a type-generic macro - may vary between the different functions the macro may call. */ -enum tgmath_parm_kind - { - tgmath_fixed, tgmath_real, tgmath_complex - }; - -/* Helper function for c_parser_postfix_expression. Parse predefined - identifiers. */ - -static struct c_expr -c_parser_predefined_identifier (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - switch (c_parser_peek_token (parser)->keyword) - { - case RID_FUNCTION_NAME: - pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " - "identifier", "__FUNCTION__"); - break; - case RID_PRETTY_FUNCTION_NAME: - pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " - "identifier", "__PRETTY_FUNCTION__"); - break; - case RID_C99_FUNCTION_NAME: - pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not support " - "%<__func__%> predefined identifier"); - break; - default: - gcc_unreachable (); - } - - struct c_expr expr; - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - expr.value = fname_decl (loc, c_parser_peek_token (parser)->keyword, - c_parser_peek_token (parser)->value); - set_c_expr_source_range (&expr, loc, loc); - c_parser_consume_token (parser); - return expr; -} - -/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2, - C11 6.5.1-6.5.2). Compound literals aren't handled here; callers have to - call c_parser_postfix_expression_after_paren_type on encountering them. - - postfix-expression: - primary-expression - postfix-expression [ expression ] - postfix-expression ( argument-expression-list[opt] ) - postfix-expression . identifier - postfix-expression -> identifier - postfix-expression ++ - postfix-expression -- - ( type-name ) { initializer-list } - ( type-name ) { initializer-list , } - - argument-expression-list: - argument-expression - argument-expression-list , argument-expression - - primary-expression: - identifier - constant - string-literal - ( expression ) - generic-selection - - GNU extensions: - - primary-expression: - __func__ - (treated as a keyword in GNU C) - __FUNCTION__ - __PRETTY_FUNCTION__ - ( compound-statement ) - __builtin_va_arg ( assignment-expression , type-name ) - __builtin_offsetof ( type-name , offsetof-member-designator ) - __builtin_choose_expr ( assignment-expression , - assignment-expression , - assignment-expression ) - __builtin_types_compatible_p ( type-name , type-name ) - __builtin_tgmath ( expr-list ) - __builtin_complex ( assignment-expression , assignment-expression ) - __builtin_shuffle ( assignment-expression , assignment-expression ) - __builtin_shuffle ( assignment-expression , - assignment-expression , - assignment-expression, ) - __builtin_convertvector ( assignment-expression , type-name ) - __builtin_assoc_barrier ( assignment-expression ) - - offsetof-member-designator: - identifier - offsetof-member-designator . identifier - offsetof-member-designator [ expression ] - - Objective-C: - - primary-expression: - [ objc-receiver objc-message-args ] - @selector ( objc-selector-arg ) - @protocol ( identifier ) - @encode ( type-name ) - objc-string-literal - Classname . identifier -*/ - -static struct c_expr -c_parser_postfix_expression (c_parser *parser) -{ - struct c_expr expr, e1; - struct c_type_name *t1, *t2; - location_t loc = c_parser_peek_token (parser)->location; - source_range tok_range = c_parser_peek_token (parser)->get_range (); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - switch (c_parser_peek_token (parser)->type) - { - case CPP_NUMBER: - expr.value = c_parser_peek_token (parser)->value; - set_c_expr_source_range (&expr, tok_range); - loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - if (TREE_CODE (expr.value) == FIXED_CST - && !targetm.fixed_point_supported_p ()) - { - error_at (loc, "fixed-point types not supported for this target"); - expr.set_error (); - } - break; - case CPP_CHAR: - case CPP_CHAR16: - case CPP_CHAR32: - case CPP_UTF8CHAR: - case CPP_WCHAR: - expr.value = c_parser_peek_token (parser)->value; - /* For the purpose of warning when a pointer is compared with - a zero character constant. */ - expr.original_type = char_type_node; - set_c_expr_source_range (&expr, tok_range); - c_parser_consume_token (parser); - break; - case CPP_STRING: - case CPP_STRING16: - case CPP_STRING32: - case CPP_WSTRING: - case CPP_UTF8STRING: - expr = c_parser_string_literal (parser, parser->translate_strings_p, - true); - break; - case CPP_OBJC_STRING: - gcc_assert (c_dialect_objc ()); - expr.value - = objc_build_string_object (c_parser_peek_token (parser)->value); - set_c_expr_source_range (&expr, tok_range); - c_parser_consume_token (parser); - break; - case CPP_NAME: - switch (c_parser_peek_token (parser)->id_kind) - { - case C_ID_ID: - { - tree id = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - expr.value = build_external_ref (loc, id, - (c_parser_peek_token (parser)->type - == CPP_OPEN_PAREN), - &expr.original_type); - set_c_expr_source_range (&expr, tok_range); - break; - } - case C_ID_CLASSNAME: - { - /* Here we parse the Objective-C 2.0 Class.name dot - syntax. */ - tree class_name = c_parser_peek_token (parser)->value; - tree component; - c_parser_consume_token (parser); - gcc_assert (c_dialect_objc ()); - if (!c_parser_require (parser, CPP_DOT, "expected %<.%>")) - { - expr.set_error (); - break; - } - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - expr.set_error (); - break; - } - c_token *component_tok = c_parser_peek_token (parser); - component = component_tok->value; - location_t end_loc = component_tok->get_finish (); - c_parser_consume_token (parser); - expr.value = objc_build_class_component_ref (class_name, - component); - set_c_expr_source_range (&expr, loc, end_loc); - break; - } - default: - c_parser_error (parser, "expected expression"); - expr.set_error (); - break; - } - break; - case CPP_OPEN_PAREN: - /* A parenthesized expression, statement expression or compound - literal. */ - if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE) - { - /* A statement expression. */ - tree stmt; - location_t brace_loc; - c_parser_consume_token (parser); - brace_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - /* If we've not yet started the current function's statement list, - or we're in the parameter scope of an old-style function - declaration, statement expressions are not allowed. */ - if (!building_stmt_list_p () || old_style_parameter_scope ()) - { - error_at (loc, "braced-group within expression allowed " - "only inside a function"); - parser->error = true; - c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.set_error (); - break; - } - stmt = c_begin_stmt_expr (); - c_parser_compound_statement_nostart (parser); - location_t close_loc = c_parser_peek_token (parser)->location; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids braced-groups within expressions"); - expr.value = c_finish_stmt_expr (brace_loc, stmt); - set_c_expr_source_range (&expr, loc, close_loc); - mark_exp_read (expr.value); - } - else - { - /* A parenthesized expression. */ - location_t loc_open_paren = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - expr = c_parser_expression (parser); - if (TREE_CODE (expr.value) == MODIFY_EXPR) - suppress_warning (expr.value, OPT_Wparentheses); - if (expr.original_code != C_MAYBE_CONST_EXPR - && expr.original_code != SIZEOF_EXPR) - expr.original_code = ERROR_MARK; - /* Remember that we saw ( ) around the sizeof. */ - if (expr.original_code == SIZEOF_EXPR) - expr.original_code = PAREN_SIZEOF_EXPR; - /* Don't change EXPR.ORIGINAL_TYPE. */ - location_t loc_close_paren = c_parser_peek_token (parser)->location; - set_c_expr_source_range (&expr, loc_open_paren, loc_close_paren); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>", loc_open_paren); - } - break; - case CPP_KEYWORD: - switch (c_parser_peek_token (parser)->keyword) - { - case RID_FUNCTION_NAME: - case RID_PRETTY_FUNCTION_NAME: - case RID_C99_FUNCTION_NAME: - expr = c_parser_predefined_identifier (parser); - break; - case RID_VA_ARG: - { - location_t start_loc = loc; - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - { - expr.set_error (); - break; - } - e1 = c_parser_expr_no_commas (parser, NULL); - mark_exp_read (e1.value); - e1.value = c_fully_fold (e1.value, false, NULL); - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.set_error (); - break; - } - loc = c_parser_peek_token (parser)->location; - t1 = c_parser_type_name (parser); - location_t end_loc = c_parser_peek_token (parser)->get_finish (); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - if (t1 == NULL) - { - expr.set_error (); - } - else - { - tree type_expr = NULL_TREE; - expr.value = c_build_va_arg (start_loc, e1.value, loc, - groktypename (t1, &type_expr, NULL)); - if (type_expr) - { - expr.value = build2 (C_MAYBE_CONST_EXPR, - TREE_TYPE (expr.value), type_expr, - expr.value); - C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true; - } - set_c_expr_source_range (&expr, start_loc, end_loc); - } - } - break; - case RID_OFFSETOF: - { - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - { - expr.set_error (); - break; - } - t1 = c_parser_type_name (parser); - if (t1 == NULL) - parser->error = true; - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - gcc_assert (parser->error); - if (parser->error) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.set_error (); - break; - } - tree type = groktypename (t1, NULL, NULL); - tree offsetof_ref; - if (type == error_mark_node) - offsetof_ref = error_mark_node; - else - { - offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node); - SET_EXPR_LOCATION (offsetof_ref, loc); - } - /* Parse the second argument to __builtin_offsetof. We - must have one identifier, and beyond that we want to - accept sub structure and sub array references. */ - if (c_parser_next_token_is (parser, CPP_NAME)) - { - c_token *comp_tok = c_parser_peek_token (parser); - offsetof_ref = build_component_ref - (loc, offsetof_ref, comp_tok->value, comp_tok->location); - c_parser_consume_token (parser); - while (c_parser_next_token_is (parser, CPP_DOT) - || c_parser_next_token_is (parser, - CPP_OPEN_SQUARE) - || c_parser_next_token_is (parser, - CPP_DEREF)) - { - if (c_parser_next_token_is (parser, CPP_DEREF)) - { - loc = c_parser_peek_token (parser)->location; - offsetof_ref = build_array_ref (loc, - offsetof_ref, - integer_zero_node); - goto do_dot; - } - else if (c_parser_next_token_is (parser, CPP_DOT)) - { - do_dot: - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, - CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - break; - } - c_token *comp_tok = c_parser_peek_token (parser); - offsetof_ref = build_component_ref - (loc, offsetof_ref, comp_tok->value, - comp_tok->location); - c_parser_consume_token (parser); - } - else - { - struct c_expr ce; - tree idx; - loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - ce = c_parser_expression (parser); - ce = convert_lvalue_to_rvalue (loc, ce, false, false); - idx = ce.value; - idx = c_fully_fold (idx, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, - "expected %<]%>"); - offsetof_ref = build_array_ref (loc, offsetof_ref, idx); - } - } - } - else - c_parser_error (parser, "expected identifier"); - location_t end_loc = c_parser_peek_token (parser)->get_finish (); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - expr.value = fold_offsetof (offsetof_ref); - set_c_expr_source_range (&expr, loc, end_loc); - } - break; - case RID_CHOOSE_EXPR: - { - vec *cexpr_list; - c_expr_t *e1_p, *e2_p, *e3_p; - tree c; - location_t close_paren_loc; - - c_parser_consume_token (parser); - if (!c_parser_get_builtin_args (parser, - "__builtin_choose_expr", - &cexpr_list, true, - &close_paren_loc)) - { - expr.set_error (); - break; - } - - if (vec_safe_length (cexpr_list) != 3) - { - error_at (loc, "wrong number of arguments to " - "%<__builtin_choose_expr%>"); - expr.set_error (); - break; - } - - e1_p = &(*cexpr_list)[0]; - e2_p = &(*cexpr_list)[1]; - e3_p = &(*cexpr_list)[2]; - - c = e1_p->value; - mark_exp_read (e2_p->value); - mark_exp_read (e3_p->value); - if (TREE_CODE (c) != INTEGER_CST - || !INTEGRAL_TYPE_P (TREE_TYPE (c))) - error_at (loc, - "first argument to %<__builtin_choose_expr%> not" - " a constant"); - constant_expression_warning (c); - expr = integer_zerop (c) ? *e3_p : *e2_p; - set_c_expr_source_range (&expr, loc, close_paren_loc); - break; - } - case RID_TYPES_COMPATIBLE_P: - { - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - { - expr.set_error (); - break; - } - t1 = c_parser_type_name (parser); - if (t1 == NULL) - { - expr.set_error (); - break; - } - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.set_error (); - break; - } - t2 = c_parser_type_name (parser); - if (t2 == NULL) - { - expr.set_error (); - break; - } - location_t close_paren_loc = c_parser_peek_token (parser)->location; - parens.skip_until_found_close (parser); - tree e1, e2; - e1 = groktypename (t1, NULL, NULL); - e2 = groktypename (t2, NULL, NULL); - if (e1 == error_mark_node || e2 == error_mark_node) - { - expr.set_error (); - break; - } - - e1 = TYPE_MAIN_VARIANT (e1); - e2 = TYPE_MAIN_VARIANT (e2); - - expr.value - = comptypes (e1, e2) ? integer_one_node : integer_zero_node; - set_c_expr_source_range (&expr, loc, close_paren_loc); - } - break; - case RID_BUILTIN_TGMATH: - { - vec *cexpr_list; - location_t close_paren_loc; - - c_parser_consume_token (parser); - if (!c_parser_get_builtin_args (parser, - "__builtin_tgmath", - &cexpr_list, false, - &close_paren_loc)) - { - expr.set_error (); - break; - } - - if (vec_safe_length (cexpr_list) < 3) - { - error_at (loc, "too few arguments to %<__builtin_tgmath%>"); - expr.set_error (); - break; - } - - unsigned int i; - c_expr_t *p; - FOR_EACH_VEC_ELT (*cexpr_list, i, p) - *p = convert_lvalue_to_rvalue (loc, *p, true, true); - unsigned int nargs = check_tgmath_function (&(*cexpr_list)[0], 1); - if (nargs == 0) - { - expr.set_error (); - break; - } - if (vec_safe_length (cexpr_list) < nargs) - { - error_at (loc, "too few arguments to %<__builtin_tgmath%>"); - expr.set_error (); - break; - } - unsigned int num_functions = vec_safe_length (cexpr_list) - nargs; - if (num_functions < 2) - { - error_at (loc, "too few arguments to %<__builtin_tgmath%>"); - expr.set_error (); - break; - } - - /* The first NUM_FUNCTIONS expressions are the function - pointers. The remaining NARGS expressions are the - arguments that are to be passed to one of those - functions, chosen following rules. */ - for (unsigned int j = 1; j < num_functions; j++) - { - unsigned int this_nargs - = check_tgmath_function (&(*cexpr_list)[j], j + 1); - if (this_nargs == 0) - { - expr.set_error (); - goto out; - } - if (this_nargs != nargs) - { - error_at ((*cexpr_list)[j].get_location (), - "argument %u of %<__builtin_tgmath%> has " - "wrong number of arguments", j + 1); - expr.set_error (); - goto out; - } - } - - /* The functions all have the same number of arguments. - Determine whether arguments and return types vary in - ways permitted for functions. */ - /* The first entry in each of these vectors is for the - return type, subsequent entries for parameter - types. */ - auto_vec parm_kind (nargs + 1); - auto_vec parm_first (nargs + 1); - auto_vec parm_complex (nargs + 1); - auto_vec parm_varies (nargs + 1); - tree first_type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[0].value)); - tree first_ret = TYPE_MAIN_VARIANT (TREE_TYPE (first_type)); - parm_first.quick_push (first_ret); - parm_complex.quick_push (TREE_CODE (first_ret) == COMPLEX_TYPE); - parm_varies.quick_push (false); - function_args_iterator iter; - tree t; - unsigned int argpos; - FOREACH_FUNCTION_ARGS (first_type, t, iter) - { - if (t == void_type_node) - break; - parm_first.quick_push (TYPE_MAIN_VARIANT (t)); - parm_complex.quick_push (TREE_CODE (t) == COMPLEX_TYPE); - parm_varies.quick_push (false); - } - for (unsigned int j = 1; j < num_functions; j++) - { - tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); - tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - if (ret != parm_first[0]) - { - parm_varies[0] = true; - if (!SCALAR_FLOAT_TYPE_P (parm_first[0]) - && !COMPLEX_FLOAT_TYPE_P (parm_first[0])) - { - error_at ((*cexpr_list)[0].get_location (), - "invalid type-generic return type for " - "argument %u of %<__builtin_tgmath%>", - 1); - expr.set_error (); - goto out; - } - if (!SCALAR_FLOAT_TYPE_P (ret) - && !COMPLEX_FLOAT_TYPE_P (ret)) - { - error_at ((*cexpr_list)[j].get_location (), - "invalid type-generic return type for " - "argument %u of %<__builtin_tgmath%>", - j + 1); - expr.set_error (); - goto out; - } - } - if (TREE_CODE (ret) == COMPLEX_TYPE) - parm_complex[0] = true; - argpos = 1; - FOREACH_FUNCTION_ARGS (type, t, iter) - { - if (t == void_type_node) - break; - t = TYPE_MAIN_VARIANT (t); - if (t != parm_first[argpos]) - { - parm_varies[argpos] = true; - if (!SCALAR_FLOAT_TYPE_P (parm_first[argpos]) - && !COMPLEX_FLOAT_TYPE_P (parm_first[argpos])) - { - error_at ((*cexpr_list)[0].get_location (), - "invalid type-generic type for " - "argument %u of argument %u of " - "%<__builtin_tgmath%>", argpos, 1); - expr.set_error (); - goto out; - } - if (!SCALAR_FLOAT_TYPE_P (t) - && !COMPLEX_FLOAT_TYPE_P (t)) - { - error_at ((*cexpr_list)[j].get_location (), - "invalid type-generic type for " - "argument %u of argument %u of " - "%<__builtin_tgmath%>", argpos, j + 1); - expr.set_error (); - goto out; - } - } - if (TREE_CODE (t) == COMPLEX_TYPE) - parm_complex[argpos] = true; - argpos++; - } - } - enum tgmath_parm_kind max_variation = tgmath_fixed; - for (unsigned int j = 0; j <= nargs; j++) - { - enum tgmath_parm_kind this_kind; - if (parm_varies[j]) - { - if (parm_complex[j]) - max_variation = this_kind = tgmath_complex; - else - { - this_kind = tgmath_real; - if (max_variation != tgmath_complex) - max_variation = tgmath_real; - } - } - else - this_kind = tgmath_fixed; - parm_kind.quick_push (this_kind); - } - if (max_variation == tgmath_fixed) - { - error_at (loc, "function arguments of %<__builtin_tgmath%> " - "all have the same type"); - expr.set_error (); - break; - } - - /* Identify a parameter (not the return type) that varies, - including with complex types if any variation includes - complex types; there must be at least one such - parameter. */ - unsigned int tgarg = 0; - for (unsigned int j = 1; j <= nargs; j++) - if (parm_kind[j] == max_variation) - { - tgarg = j; - break; - } - if (tgarg == 0) - { - error_at (loc, "function arguments of %<__builtin_tgmath%> " - "lack type-generic parameter"); - expr.set_error (); - break; - } - - /* Determine the type of the relevant parameter for each - function. */ - auto_vec tg_type (num_functions); - for (unsigned int j = 0; j < num_functions; j++) - { - tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); - argpos = 1; - FOREACH_FUNCTION_ARGS (type, t, iter) - { - if (argpos == tgarg) - { - tg_type.quick_push (TYPE_MAIN_VARIANT (t)); - break; - } - argpos++; - } - } - - /* Verify that the corresponding types are different for - all the listed functions. Also determine whether all - the types are complex, whether all the types are - standard or binary, and whether all the types are - decimal. */ - bool all_complex = true; - bool all_binary = true; - bool all_decimal = true; - hash_set tg_types; - FOR_EACH_VEC_ELT (tg_type, i, t) - { - if (TREE_CODE (t) == COMPLEX_TYPE) - all_decimal = false; - else - { - all_complex = false; - if (DECIMAL_FLOAT_TYPE_P (t)) - all_binary = false; - else - all_decimal = false; - } - if (tg_types.add (t)) - { - error_at ((*cexpr_list)[i].get_location (), - "duplicate type-generic parameter type for " - "function argument %u of %<__builtin_tgmath%>", - i + 1); - expr.set_error (); - goto out; - } - } - - /* Verify that other parameters and the return type whose - types vary have their types varying in the correct - way. */ - for (unsigned int j = 0; j < num_functions; j++) - { - tree exp_type = tg_type[j]; - tree exp_real_type = exp_type; - if (TREE_CODE (exp_type) == COMPLEX_TYPE) - exp_real_type = TREE_TYPE (exp_type); - tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); - tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - if ((parm_kind[0] == tgmath_complex && ret != exp_type) - || (parm_kind[0] == tgmath_real && ret != exp_real_type)) - { - error_at ((*cexpr_list)[j].get_location (), - "bad return type for function argument %u " - "of %<__builtin_tgmath%>", j + 1); - expr.set_error (); - goto out; - } - argpos = 1; - FOREACH_FUNCTION_ARGS (type, t, iter) - { - if (t == void_type_node) - break; - t = TYPE_MAIN_VARIANT (t); - if ((parm_kind[argpos] == tgmath_complex - && t != exp_type) - || (parm_kind[argpos] == tgmath_real - && t != exp_real_type)) - { - error_at ((*cexpr_list)[j].get_location (), - "bad type for argument %u of " - "function argument %u of " - "%<__builtin_tgmath%>", argpos, j + 1); - expr.set_error (); - goto out; - } - argpos++; - } - } - - /* The functions listed are a valid set of functions for a - macro to select between. Identify the - matching function, if any. First, the argument types - must be combined following rules. Integer - types are treated as _Decimal64 if any type-generic - argument is decimal, or if the only alternatives for - type-generic arguments are of decimal types, and are - otherwise treated as double (or _Complex double for - complex integer types, or _Float64 or _Complex _Float64 - if all the return types are the same _FloatN or - _FloatNx type). After that adjustment, types are - combined following the usual arithmetic conversions. - If the function only accepts complex arguments, a - complex type is produced. */ - bool arg_complex = all_complex; - bool arg_binary = all_binary; - bool arg_int_decimal = all_decimal; - for (unsigned int j = 1; j <= nargs; j++) - { - if (parm_kind[j] == tgmath_fixed) - continue; - c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1]; - tree type = TREE_TYPE (ce->value); - if (!INTEGRAL_TYPE_P (type) - && !SCALAR_FLOAT_TYPE_P (type) - && TREE_CODE (type) != COMPLEX_TYPE) - { - error_at (ce->get_location (), - "invalid type of argument %u of type-generic " - "function", j); - expr.set_error (); - goto out; - } - if (DECIMAL_FLOAT_TYPE_P (type)) - { - arg_int_decimal = true; - if (all_complex) - { - error_at (ce->get_location (), - "decimal floating-point argument %u to " - "complex-only type-generic function", j); - expr.set_error (); - goto out; - } - else if (all_binary) - { - error_at (ce->get_location (), - "decimal floating-point argument %u to " - "binary-only type-generic function", j); - expr.set_error (); - goto out; - } - else if (arg_complex) - { - error_at (ce->get_location (), - "both complex and decimal floating-point " - "arguments to type-generic function"); - expr.set_error (); - goto out; - } - else if (arg_binary) - { - error_at (ce->get_location (), - "both binary and decimal floating-point " - "arguments to type-generic function"); - expr.set_error (); - goto out; - } - } - else if (TREE_CODE (type) == COMPLEX_TYPE) - { - arg_complex = true; - if (COMPLEX_FLOAT_TYPE_P (type)) - arg_binary = true; - if (all_decimal) - { - error_at (ce->get_location (), - "complex argument %u to " - "decimal-only type-generic function", j); - expr.set_error (); - goto out; - } - else if (arg_int_decimal) - { - error_at (ce->get_location (), - "both complex and decimal floating-point " - "arguments to type-generic function"); - expr.set_error (); - goto out; - } - } - else if (SCALAR_FLOAT_TYPE_P (type)) - { - arg_binary = true; - if (all_decimal) - { - error_at (ce->get_location (), - "binary argument %u to " - "decimal-only type-generic function", j); - expr.set_error (); - goto out; - } - else if (arg_int_decimal) - { - error_at (ce->get_location (), - "both binary and decimal floating-point " - "arguments to type-generic function"); - expr.set_error (); - goto out; - } - } - } - /* For a macro rounding its result to a narrower type, map - integer types to _Float64 not double if the return type - is a _FloatN or _FloatNx type. */ - bool arg_int_float64 = false; - if (parm_kind[0] == tgmath_fixed - && SCALAR_FLOAT_TYPE_P (parm_first[0]) - && float64_type_node != NULL_TREE) - for (unsigned int j = 0; j < NUM_FLOATN_NX_TYPES; j++) - if (parm_first[0] == FLOATN_TYPE_NODE (j)) - { - arg_int_float64 = true; - break; - } - tree arg_real = NULL_TREE; - for (unsigned int j = 1; j <= nargs; j++) - { - if (parm_kind[j] == tgmath_fixed) - continue; - c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1]; - tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ce->value)); - if (TREE_CODE (type) == COMPLEX_TYPE) - type = TREE_TYPE (type); - if (INTEGRAL_TYPE_P (type)) - type = (arg_int_decimal - ? dfloat64_type_node - : arg_int_float64 - ? float64_type_node - : double_type_node); - if (arg_real == NULL_TREE) - arg_real = type; - else - arg_real = common_type (arg_real, type); - if (arg_real == error_mark_node) - { - expr.set_error (); - goto out; - } - } - tree arg_type = (arg_complex - ? build_complex_type (arg_real) - : arg_real); - - /* Look for a function to call with type-generic parameter - type ARG_TYPE. */ - c_expr_t *fn = NULL; - for (unsigned int j = 0; j < num_functions; j++) - { - if (tg_type[j] == arg_type) - { - fn = &(*cexpr_list)[j]; - break; - } - } - if (fn == NULL - && parm_kind[0] == tgmath_fixed - && SCALAR_FLOAT_TYPE_P (parm_first[0])) - { - /* Presume this is a macro that rounds its result to a - narrower type, and look for the first function with - at least the range and precision of the argument - type. */ - for (unsigned int j = 0; j < num_functions; j++) - { - if (arg_complex - != (TREE_CODE (tg_type[j]) == COMPLEX_TYPE)) - continue; - tree real_tg_type = (arg_complex - ? TREE_TYPE (tg_type[j]) - : tg_type[j]); - if (DECIMAL_FLOAT_TYPE_P (arg_real) - != DECIMAL_FLOAT_TYPE_P (real_tg_type)) - continue; - scalar_float_mode arg_mode - = SCALAR_FLOAT_TYPE_MODE (arg_real); - scalar_float_mode tg_mode - = SCALAR_FLOAT_TYPE_MODE (real_tg_type); - const real_format *arg_fmt = REAL_MODE_FORMAT (arg_mode); - const real_format *tg_fmt = REAL_MODE_FORMAT (tg_mode); - if (arg_fmt->b == tg_fmt->b - && arg_fmt->p <= tg_fmt->p - && arg_fmt->emax <= tg_fmt->emax - && (arg_fmt->emin - arg_fmt->p - >= tg_fmt->emin - tg_fmt->p)) - { - fn = &(*cexpr_list)[j]; - break; - } - } - } - if (fn == NULL) - { - error_at (loc, "no matching function for type-generic call"); - expr.set_error (); - break; - } - - /* Construct a call to FN. */ - vec *args; - vec_alloc (args, nargs); - vec *origtypes; - vec_alloc (origtypes, nargs); - auto_vec arg_loc (nargs); - for (unsigned int j = 0; j < nargs; j++) - { - c_expr_t *ce = &(*cexpr_list)[num_functions + j]; - args->quick_push (ce->value); - arg_loc.quick_push (ce->get_location ()); - origtypes->quick_push (ce->original_type); - } - expr.value = c_build_function_call_vec (loc, arg_loc, fn->value, - args, origtypes); - set_c_expr_source_range (&expr, loc, close_paren_loc); - break; - } - case RID_BUILTIN_CALL_WITH_STATIC_CHAIN: - { - vec *cexpr_list; - c_expr_t *e2_p; - tree chain_value; - location_t close_paren_loc; - - c_parser_consume_token (parser); - if (!c_parser_get_builtin_args (parser, - "__builtin_call_with_static_chain", - &cexpr_list, false, - &close_paren_loc)) - { - expr.set_error (); - break; - } - if (vec_safe_length (cexpr_list) != 2) - { - error_at (loc, "wrong number of arguments to " - "%<__builtin_call_with_static_chain%>"); - expr.set_error (); - break; - } - - expr = (*cexpr_list)[0]; - e2_p = &(*cexpr_list)[1]; - *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true); - chain_value = e2_p->value; - mark_exp_read (chain_value); - - if (TREE_CODE (expr.value) != CALL_EXPR) - error_at (loc, "first argument to " - "%<__builtin_call_with_static_chain%> " - "must be a call expression"); - else if (TREE_CODE (TREE_TYPE (chain_value)) != POINTER_TYPE) - error_at (loc, "second argument to " - "%<__builtin_call_with_static_chain%> " - "must be a pointer type"); - else - CALL_EXPR_STATIC_CHAIN (expr.value) = chain_value; - set_c_expr_source_range (&expr, loc, close_paren_loc); - break; - } - case RID_BUILTIN_COMPLEX: - { - vec *cexpr_list; - c_expr_t *e1_p, *e2_p; - location_t close_paren_loc; - - c_parser_consume_token (parser); - if (!c_parser_get_builtin_args (parser, - "__builtin_complex", - &cexpr_list, false, - &close_paren_loc)) - { - expr.set_error (); - break; - } - - if (vec_safe_length (cexpr_list) != 2) - { - error_at (loc, "wrong number of arguments to " - "%<__builtin_complex%>"); - expr.set_error (); - break; - } - - e1_p = &(*cexpr_list)[0]; - e2_p = &(*cexpr_list)[1]; - - *e1_p = convert_lvalue_to_rvalue (loc, *e1_p, true, true); - if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR) - e1_p->value = convert (TREE_TYPE (e1_p->value), - TREE_OPERAND (e1_p->value, 0)); - *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true); - if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR) - e2_p->value = convert (TREE_TYPE (e2_p->value), - TREE_OPERAND (e2_p->value, 0)); - if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) - || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) - || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2_p->value)) - || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2_p->value))) - { - error_at (loc, "%<__builtin_complex%> operand " - "not of real binary floating-point type"); - expr.set_error (); - break; - } - if (TYPE_MAIN_VARIANT (TREE_TYPE (e1_p->value)) - != TYPE_MAIN_VARIANT (TREE_TYPE (e2_p->value))) - { - error_at (loc, - "%<__builtin_complex%> operands of different types"); - expr.set_error (); - break; - } - pedwarn_c90 (loc, OPT_Wpedantic, - "ISO C90 does not support complex types"); - expr.value = build2_loc (loc, COMPLEX_EXPR, - build_complex_type - (TYPE_MAIN_VARIANT - (TREE_TYPE (e1_p->value))), - e1_p->value, e2_p->value); - set_c_expr_source_range (&expr, loc, close_paren_loc); - break; - } - case RID_BUILTIN_SHUFFLE: - { - vec *cexpr_list; - unsigned int i; - c_expr_t *p; - location_t close_paren_loc; - - c_parser_consume_token (parser); - if (!c_parser_get_builtin_args (parser, - "__builtin_shuffle", - &cexpr_list, false, - &close_paren_loc)) - { - expr.set_error (); - break; - } - - FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) - *p = convert_lvalue_to_rvalue (loc, *p, true, true); - - if (vec_safe_length (cexpr_list) == 2) - expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, - NULL_TREE, - (*cexpr_list)[1].value); - - else if (vec_safe_length (cexpr_list) == 3) - expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, - (*cexpr_list)[1].value, - (*cexpr_list)[2].value); - else - { - error_at (loc, "wrong number of arguments to " - "%<__builtin_shuffle%>"); - expr.set_error (); - } - set_c_expr_source_range (&expr, loc, close_paren_loc); - break; - } - case RID_BUILTIN_SHUFFLEVECTOR: - { - vec *cexpr_list; - unsigned int i; - c_expr_t *p; - location_t close_paren_loc; - - c_parser_consume_token (parser); - if (!c_parser_get_builtin_args (parser, - "__builtin_shufflevector", - &cexpr_list, false, - &close_paren_loc)) - { - expr.set_error (); - break; - } - - FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) - *p = convert_lvalue_to_rvalue (loc, *p, true, true); - - if (vec_safe_length (cexpr_list) < 3) - { - error_at (loc, "wrong number of arguments to " - "%<__builtin_shuffle%>"); - expr.set_error (); - } - else - { - auto_vec mask; - for (i = 2; i < cexpr_list->length (); ++i) - mask.safe_push ((*cexpr_list)[i].value); - expr.value = c_build_shufflevector (loc, (*cexpr_list)[0].value, - (*cexpr_list)[1].value, - mask); - } - set_c_expr_source_range (&expr, loc, close_paren_loc); - break; - } - case RID_BUILTIN_CONVERTVECTOR: - { - location_t start_loc = loc; - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - { - expr.set_error (); - break; - } - e1 = c_parser_expr_no_commas (parser, NULL); - mark_exp_read (e1.value); - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.set_error (); - break; - } - loc = c_parser_peek_token (parser)->location; - t1 = c_parser_type_name (parser); - location_t end_loc = c_parser_peek_token (parser)->get_finish (); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - if (t1 == NULL) - expr.set_error (); - else - { - tree type_expr = NULL_TREE; - expr.value = c_build_vec_convert (start_loc, e1.value, loc, - groktypename (t1, &type_expr, - NULL)); - set_c_expr_source_range (&expr, start_loc, end_loc); - } - } - break; - case RID_BUILTIN_ASSOC_BARRIER: - { - location_t start_loc = loc; - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - { - expr.set_error (); - break; - } - e1 = c_parser_expr_no_commas (parser, NULL); - mark_exp_read (e1.value); - location_t end_loc = c_parser_peek_token (parser)->get_finish (); - parens.skip_until_found_close (parser); - expr.value = build1_loc (loc, PAREN_EXPR, TREE_TYPE (e1.value), - e1.value); - set_c_expr_source_range (&expr, start_loc, end_loc); - } - break; - case RID_AT_SELECTOR: - { - gcc_assert (c_dialect_objc ()); - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - { - expr.set_error (); - break; - } - tree sel = c_parser_objc_selector_arg (parser); - location_t close_loc = c_parser_peek_token (parser)->location; - parens.skip_until_found_close (parser); - expr.value = objc_build_selector_expr (loc, sel); - set_c_expr_source_range (&expr, loc, close_loc); - } - break; - case RID_AT_PROTOCOL: - { - gcc_assert (c_dialect_objc ()); - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - { - expr.set_error (); - break; - } - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.set_error (); - break; - } - tree id = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - location_t close_loc = c_parser_peek_token (parser)->location; - parens.skip_until_found_close (parser); - expr.value = objc_build_protocol_expr (id); - set_c_expr_source_range (&expr, loc, close_loc); - } - break; - case RID_AT_ENCODE: - { - /* Extension to support C-structures in the archiver. */ - gcc_assert (c_dialect_objc ()); - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - { - expr.set_error (); - break; - } - t1 = c_parser_type_name (parser); - if (t1 == NULL) - { - expr.set_error (); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - break; - } - location_t close_loc = c_parser_peek_token (parser)->location; - parens.skip_until_found_close (parser); - tree type = groktypename (t1, NULL, NULL); - expr.value = objc_build_encode_expr (type); - set_c_expr_source_range (&expr, loc, close_loc); - } - break; - case RID_GENERIC: - expr = c_parser_generic_selection (parser); - break; - default: - c_parser_error (parser, "expected expression"); - expr.set_error (); - break; - } - break; - case CPP_OPEN_SQUARE: - if (c_dialect_objc ()) - { - tree receiver, args; - c_parser_consume_token (parser); - receiver = c_parser_objc_receiver (parser); - args = c_parser_objc_message_args (parser); - location_t close_loc = c_parser_peek_token (parser)->location; - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, - "expected %<]%>"); - expr.value = objc_build_message_expr (receiver, args); - set_c_expr_source_range (&expr, loc, close_loc); - break; - } - /* Else fall through to report error. */ - /* FALLTHRU */ - default: - c_parser_error (parser, "expected expression"); - expr.set_error (); - break; - } - out: - return c_parser_postfix_expression_after_primary - (parser, EXPR_LOC_OR_LOC (expr.value, loc), expr); -} - -/* Parse a postfix expression after a parenthesized type name: the - brace-enclosed initializer of a compound literal, possibly followed - by some postfix operators. This is separate because it is not - possible to tell until after the type name whether a cast - expression has a cast or a compound literal, or whether the operand - of sizeof is a parenthesized type name or starts with a compound - literal. TYPE_LOC is the location where TYPE_NAME starts--the - location of the first token after the parentheses around the type - name. */ - -static struct c_expr -c_parser_postfix_expression_after_paren_type (c_parser *parser, - struct c_type_name *type_name, - location_t type_loc) -{ - tree type; - struct c_expr init; - bool non_const; - struct c_expr expr; - location_t start_loc; - tree type_expr = NULL_TREE; - bool type_expr_const = true; - check_compound_literal_type (type_loc, type_name); - rich_location richloc (line_table, type_loc); - start_init (NULL_TREE, NULL, 0, &richloc); - type = groktypename (type_name, &type_expr, &type_expr_const); - start_loc = c_parser_peek_token (parser)->location; - if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) - { - error_at (type_loc, "compound literal has variable size"); - type = error_mark_node; - } - init = c_parser_braced_init (parser, type, false, NULL); - finish_init (); - maybe_warn_string_init (type_loc, type, init); - - if (type != error_mark_node - && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)) - && current_function_decl) - { - error ("compound literal qualified by address-space qualifier"); - type = error_mark_node; - } - - pedwarn_c90 (start_loc, OPT_Wpedantic, "ISO C90 forbids compound literals"); - non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) - ? CONSTRUCTOR_NON_CONST (init.value) - : init.original_code == C_MAYBE_CONST_EXPR); - non_const |= !type_expr_const; - unsigned int alignas_align = 0; - if (type != error_mark_node - && type_name->specs->align_log != -1) - { - alignas_align = 1U << type_name->specs->align_log; - if (alignas_align < min_align_of_type (type)) - { - error_at (type_name->specs->locations[cdw_alignas], - "%<_Alignas%> specifiers cannot reduce " - "alignment of compound literal"); - alignas_align = 0; - } - } - expr.value = build_compound_literal (start_loc, type, init.value, non_const, - alignas_align); - set_c_expr_source_range (&expr, init.src_range); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - if (type != error_mark_node - && expr.value != error_mark_node - && type_expr) - { - if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR) - { - gcc_assert (C_MAYBE_CONST_EXPR_PRE (expr.value) == NULL_TREE); - C_MAYBE_CONST_EXPR_PRE (expr.value) = type_expr; - } - else - { - gcc_assert (!non_const); - expr.value = build2 (C_MAYBE_CONST_EXPR, type, - type_expr, expr.value); - } - } - return c_parser_postfix_expression_after_primary (parser, start_loc, expr); -} - -/* Callback function for sizeof_pointer_memaccess_warning to compare - types. */ - -static bool -sizeof_ptr_memacc_comptypes (tree type1, tree type2) -{ - return comptypes (type1, type2) == 1; -} - -/* Warn for patterns where abs-like function appears to be used incorrectly, - gracefully ignore any non-abs-like function. The warning location should - be LOC. FNDECL is the declaration of called function, it must be a - BUILT_IN_NORMAL function. ARG is the first and only argument of the - call. */ - -static void -warn_for_abs (location_t loc, tree fndecl, tree arg) -{ - /* Avoid warning in unreachable subexpressions. */ - if (c_inhibit_evaluation_warnings) - return; - - tree atype = TREE_TYPE (arg); - - /* Casts from pointers (and thus arrays and fndecls) will generate - -Wint-conversion warnings. Most other wrong types hopefully lead to type - mismatch errors. TODO: Think about what to do with FIXED_POINT_TYPE_P - types and possibly other exotic types. */ - if (!INTEGRAL_TYPE_P (atype) - && !SCALAR_FLOAT_TYPE_P (atype) - && TREE_CODE (atype) != COMPLEX_TYPE) - return; - - enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); - - switch (fcode) - { - case BUILT_IN_ABS: - case BUILT_IN_LABS: - case BUILT_IN_LLABS: - case BUILT_IN_IMAXABS: - if (!INTEGRAL_TYPE_P (atype)) - { - if (SCALAR_FLOAT_TYPE_P (atype)) - warning_at (loc, OPT_Wabsolute_value, - "using integer absolute value function %qD when " - "argument is of floating-point type %qT", - fndecl, atype); - else if (TREE_CODE (atype) == COMPLEX_TYPE) - warning_at (loc, OPT_Wabsolute_value, - "using integer absolute value function %qD when " - "argument is of complex type %qT", fndecl, atype); - else - gcc_unreachable (); - return; - } - if (TYPE_UNSIGNED (atype)) - warning_at (loc, OPT_Wabsolute_value, - "taking the absolute value of unsigned type %qT " - "has no effect", atype); - break; - - CASE_FLT_FN (BUILT_IN_FABS): - CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS): - if (!SCALAR_FLOAT_TYPE_P (atype) - || DECIMAL_FLOAT_MODE_P (TYPE_MODE (atype))) - { - if (INTEGRAL_TYPE_P (atype)) - warning_at (loc, OPT_Wabsolute_value, - "using floating-point absolute value function %qD " - "when argument is of integer type %qT", fndecl, atype); - else if (DECIMAL_FLOAT_TYPE_P (atype)) - warning_at (loc, OPT_Wabsolute_value, - "using floating-point absolute value function %qD " - "when argument is of decimal floating-point type %qT", - fndecl, atype); - else if (TREE_CODE (atype) == COMPLEX_TYPE) - warning_at (loc, OPT_Wabsolute_value, - "using floating-point absolute value function %qD when " - "argument is of complex type %qT", fndecl, atype); - else - gcc_unreachable (); - return; - } - break; - - CASE_FLT_FN (BUILT_IN_CABS): - if (TREE_CODE (atype) != COMPLEX_TYPE) - { - if (INTEGRAL_TYPE_P (atype)) - warning_at (loc, OPT_Wabsolute_value, - "using complex absolute value function %qD when " - "argument is of integer type %qT", fndecl, atype); - else if (SCALAR_FLOAT_TYPE_P (atype)) - warning_at (loc, OPT_Wabsolute_value, - "using complex absolute value function %qD when " - "argument is of floating-point type %qT", - fndecl, atype); - else - gcc_unreachable (); - - return; - } - break; - - case BUILT_IN_FABSD32: - case BUILT_IN_FABSD64: - case BUILT_IN_FABSD128: - if (!DECIMAL_FLOAT_TYPE_P (atype)) - { - if (INTEGRAL_TYPE_P (atype)) - warning_at (loc, OPT_Wabsolute_value, - "using decimal floating-point absolute value " - "function %qD when argument is of integer type %qT", - fndecl, atype); - else if (SCALAR_FLOAT_TYPE_P (atype)) - warning_at (loc, OPT_Wabsolute_value, - "using decimal floating-point absolute value " - "function %qD when argument is of floating-point " - "type %qT", fndecl, atype); - else if (TREE_CODE (atype) == COMPLEX_TYPE) - warning_at (loc, OPT_Wabsolute_value, - "using decimal floating-point absolute value " - "function %qD when argument is of complex type %qT", - fndecl, atype); - else - gcc_unreachable (); - return; - } - break; - - default: - return; - } - - if (!TYPE_ARG_TYPES (TREE_TYPE (fndecl))) - return; - - tree ftype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); - if (TREE_CODE (atype) == COMPLEX_TYPE) - { - gcc_assert (TREE_CODE (ftype) == COMPLEX_TYPE); - atype = TREE_TYPE (atype); - ftype = TREE_TYPE (ftype); - } - - if (TYPE_PRECISION (ftype) < TYPE_PRECISION (atype)) - warning_at (loc, OPT_Wabsolute_value, - "absolute value function %qD given an argument of type %qT " - "but has parameter of type %qT which may cause truncation " - "of value", fndecl, atype, ftype); -} - - -/* Parse a postfix expression after the initial primary or compound - literal; that is, parse a series of postfix operators. - - EXPR_LOC is the location of the primary expression. */ - -static struct c_expr -c_parser_postfix_expression_after_primary (c_parser *parser, - location_t expr_loc, - struct c_expr expr) -{ - struct c_expr orig_expr; - tree ident, idx; - location_t sizeof_arg_loc[3], comp_loc; - tree sizeof_arg[3]; - unsigned int literal_zero_mask; - unsigned int i; - vec *exprlist; - vec *origtypes = NULL; - vec arg_loc = vNULL; - location_t start; - location_t finish; - - while (true) - { - location_t op_loc = c_parser_peek_token (parser)->location; - switch (c_parser_peek_token (parser)->type) - { - case CPP_OPEN_SQUARE: - /* Array reference. */ - c_parser_consume_token (parser); - idx = c_parser_expression (parser).value; - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, - "expected %<]%>"); - start = expr.get_start (); - finish = parser->tokens_buf[0].location; - expr.value = build_array_ref (op_loc, expr.value, idx); - set_c_expr_source_range (&expr, start, finish); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - break; - case CPP_OPEN_PAREN: - /* Function call. */ - { - matching_parens parens; - parens.consume_open (parser); - for (i = 0; i < 3; i++) - { - sizeof_arg[i] = NULL_TREE; - sizeof_arg_loc[i] = UNKNOWN_LOCATION; - } - literal_zero_mask = 0; - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - exprlist = NULL; - else - exprlist = c_parser_expr_list (parser, true, false, &origtypes, - sizeof_arg_loc, sizeof_arg, - &arg_loc, &literal_zero_mask); - parens.skip_until_found_close (parser); - } - orig_expr = expr; - mark_exp_read (expr.value); - if (warn_sizeof_pointer_memaccess) - sizeof_pointer_memaccess_warning (sizeof_arg_loc, - expr.value, exprlist, - sizeof_arg, - sizeof_ptr_memacc_comptypes); - if (TREE_CODE (expr.value) == FUNCTION_DECL) - { - if (fndecl_built_in_p (expr.value, BUILT_IN_MEMSET) - && vec_safe_length (exprlist) == 3) - { - tree arg0 = (*exprlist)[0]; - tree arg2 = (*exprlist)[2]; - warn_for_memset (expr_loc, arg0, arg2, literal_zero_mask); - } - if (warn_absolute_value - && fndecl_built_in_p (expr.value, BUILT_IN_NORMAL) - && vec_safe_length (exprlist) == 1) - warn_for_abs (expr_loc, expr.value, (*exprlist)[0]); - } - - start = expr.get_start (); - finish = parser->tokens_buf[0].get_finish (); - expr.value - = c_build_function_call_vec (expr_loc, arg_loc, expr.value, - exprlist, origtypes); - set_c_expr_source_range (&expr, start, finish); - - expr.original_code = ERROR_MARK; - if (TREE_CODE (expr.value) == INTEGER_CST - && TREE_CODE (orig_expr.value) == FUNCTION_DECL - && fndecl_built_in_p (orig_expr.value, BUILT_IN_CONSTANT_P)) - expr.original_code = C_MAYBE_CONST_EXPR; - expr.original_type = NULL; - if (exprlist) - { - release_tree_vector (exprlist); - release_tree_vector (origtypes); - } - arg_loc.release (); - break; - case CPP_DOT: - /* Structure element reference. */ - c_parser_consume_token (parser); - expr = default_function_array_conversion (expr_loc, expr); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - c_token *comp_tok = c_parser_peek_token (parser); - ident = comp_tok->value; - comp_loc = comp_tok->location; - } - else - { - c_parser_error (parser, "expected identifier"); - expr.set_error (); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - return expr; - } - start = expr.get_start (); - finish = c_parser_peek_token (parser)->get_finish (); - c_parser_consume_token (parser); - expr.value = build_component_ref (op_loc, expr.value, ident, - comp_loc); - set_c_expr_source_range (&expr, start, finish); - expr.original_code = ERROR_MARK; - if (TREE_CODE (expr.value) != COMPONENT_REF) - expr.original_type = NULL; - else - { - /* Remember the original type of a bitfield. */ - tree field = TREE_OPERAND (expr.value, 1); - if (TREE_CODE (field) != FIELD_DECL) - expr.original_type = NULL; - else - expr.original_type = DECL_BIT_FIELD_TYPE (field); - } - break; - case CPP_DEREF: - /* Structure element reference. */ - c_parser_consume_token (parser); - expr = convert_lvalue_to_rvalue (expr_loc, expr, true, false); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - c_token *comp_tok = c_parser_peek_token (parser); - ident = comp_tok->value; - comp_loc = comp_tok->location; - } - else - { - c_parser_error (parser, "expected identifier"); - expr.set_error (); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - return expr; - } - start = expr.get_start (); - finish = c_parser_peek_token (parser)->get_finish (); - c_parser_consume_token (parser); - expr.value = build_component_ref (op_loc, - build_indirect_ref (op_loc, - expr.value, - RO_ARROW), - ident, comp_loc); - set_c_expr_source_range (&expr, start, finish); - expr.original_code = ERROR_MARK; - if (TREE_CODE (expr.value) != COMPONENT_REF) - expr.original_type = NULL; - else - { - /* Remember the original type of a bitfield. */ - tree field = TREE_OPERAND (expr.value, 1); - if (TREE_CODE (field) != FIELD_DECL) - expr.original_type = NULL; - else - expr.original_type = DECL_BIT_FIELD_TYPE (field); - } - break; - case CPP_PLUS_PLUS: - /* Postincrement. */ - start = expr.get_start (); - finish = c_parser_peek_token (parser)->get_finish (); - c_parser_consume_token (parser); - expr = default_function_array_read_conversion (expr_loc, expr); - expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR, - expr.value, false); - set_c_expr_source_range (&expr, start, finish); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - break; - case CPP_MINUS_MINUS: - /* Postdecrement. */ - start = expr.get_start (); - finish = c_parser_peek_token (parser)->get_finish (); - c_parser_consume_token (parser); - expr = default_function_array_read_conversion (expr_loc, expr); - expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR, - expr.value, false); - set_c_expr_source_range (&expr, start, finish); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - break; - default: - return expr; - } - } -} - -/* Parse an expression (C90 6.3.17, C99 6.5.17, C11 6.5.17). - - expression: - assignment-expression - expression , assignment-expression -*/ - -static struct c_expr -c_parser_expression (c_parser *parser) -{ - location_t tloc = c_parser_peek_token (parser)->location; - struct c_expr expr; - expr = c_parser_expr_no_commas (parser, NULL); - if (c_parser_next_token_is (parser, CPP_COMMA)) - expr = convert_lvalue_to_rvalue (tloc, expr, true, false); - while (c_parser_next_token_is (parser, CPP_COMMA)) - { - struct c_expr next; - tree lhsval; - location_t loc = c_parser_peek_token (parser)->location; - location_t expr_loc; - c_parser_consume_token (parser); - expr_loc = c_parser_peek_token (parser)->location; - lhsval = expr.value; - while (TREE_CODE (lhsval) == COMPOUND_EXPR - || TREE_CODE (lhsval) == NOP_EXPR) - { - if (TREE_CODE (lhsval) == COMPOUND_EXPR) - lhsval = TREE_OPERAND (lhsval, 1); - else - lhsval = TREE_OPERAND (lhsval, 0); - } - if (DECL_P (lhsval) || handled_component_p (lhsval)) - mark_exp_read (lhsval); - next = c_parser_expr_no_commas (parser, NULL); - next = convert_lvalue_to_rvalue (expr_loc, next, true, false); - expr.value = build_compound_expr (loc, expr.value, next.value); - expr.original_code = COMPOUND_EXPR; - expr.original_type = next.original_type; - } - return expr; -} - -/* Parse an expression and convert functions or arrays to pointers and - lvalues to rvalues. */ - -static struct c_expr -c_parser_expression_conv (c_parser *parser) -{ - struct c_expr expr; - location_t loc = c_parser_peek_token (parser)->location; - expr = c_parser_expression (parser); - expr = convert_lvalue_to_rvalue (loc, expr, true, false); - return expr; -} - -/* Helper function of c_parser_expr_list. Check if IDXth (0 based) - argument is a literal zero alone and if so, set it in literal_zero_mask. */ - -static inline void -c_parser_check_literal_zero (c_parser *parser, unsigned *literal_zero_mask, - unsigned int idx) -{ - if (idx >= HOST_BITS_PER_INT) - return; - - c_token *tok = c_parser_peek_token (parser); - switch (tok->type) - { - case CPP_NUMBER: - case CPP_CHAR: - case CPP_WCHAR: - case CPP_CHAR16: - case CPP_CHAR32: - case CPP_UTF8CHAR: - /* If a parameter is literal zero alone, remember it - for -Wmemset-transposed-args warning. */ - if (integer_zerop (tok->value) - && !TREE_OVERFLOW (tok->value) - && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA - || c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN)) - *literal_zero_mask |= 1U << idx; - default: - break; - } -} - -/* Parse a non-empty list of expressions. If CONVERT_P, convert - functions and arrays to pointers and lvalues to rvalues. If - FOLD_P, fold the expressions. If LOCATIONS is non-NULL, save the - locations of function arguments into this vector. - - nonempty-expr-list: - assignment-expression - nonempty-expr-list , assignment-expression -*/ - -static vec * -c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, - vec **p_orig_types, - location_t *sizeof_arg_loc, tree *sizeof_arg, - vec *locations, - unsigned int *literal_zero_mask) -{ - vec *ret; - vec *orig_types; - struct c_expr expr; - unsigned int idx = 0; - - ret = make_tree_vector (); - if (p_orig_types == NULL) - orig_types = NULL; - else - orig_types = make_tree_vector (); - - if (literal_zero_mask) - c_parser_check_literal_zero (parser, literal_zero_mask, 0); - expr = c_parser_expr_no_commas (parser, NULL); - if (convert_p) - expr = convert_lvalue_to_rvalue (expr.get_location (), expr, true, true); - if (fold_p) - expr.value = c_fully_fold (expr.value, false, NULL); - ret->quick_push (expr.value); - if (orig_types) - orig_types->quick_push (expr.original_type); - if (locations) - locations->safe_push (expr.get_location ()); - if (sizeof_arg != NULL - && (expr.original_code == SIZEOF_EXPR - || expr.original_code == PAREN_SIZEOF_EXPR)) - { - sizeof_arg[0] = c_last_sizeof_arg; - sizeof_arg_loc[0] = c_last_sizeof_loc; - } - while (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - if (literal_zero_mask) - c_parser_check_literal_zero (parser, literal_zero_mask, idx + 1); - expr = c_parser_expr_no_commas (parser, NULL); - if (convert_p) - expr = convert_lvalue_to_rvalue (expr.get_location (), expr, true, - true); - if (fold_p) - expr.value = c_fully_fold (expr.value, false, NULL); - vec_safe_push (ret, expr.value); - if (orig_types) - vec_safe_push (orig_types, expr.original_type); - if (locations) - locations->safe_push (expr.get_location ()); - if (++idx < 3 - && sizeof_arg != NULL - && (expr.original_code == SIZEOF_EXPR - || expr.original_code == PAREN_SIZEOF_EXPR)) - { - sizeof_arg[idx] = c_last_sizeof_arg; - sizeof_arg_loc[idx] = c_last_sizeof_loc; - } - } - if (orig_types) - *p_orig_types = orig_types; - return ret; -} - -/* Parse Objective-C-specific constructs. */ - -/* Parse an objc-class-definition. - - objc-class-definition: - @interface identifier objc-superclass[opt] objc-protocol-refs[opt] - objc-class-instance-variables[opt] objc-methodprotolist @end - @implementation identifier objc-superclass[opt] - objc-class-instance-variables[opt] - @interface identifier ( identifier ) objc-protocol-refs[opt] - objc-methodprotolist @end - @interface identifier ( ) objc-protocol-refs[opt] - objc-methodprotolist @end - @implementation identifier ( identifier ) - - objc-superclass: - : identifier - - "@interface identifier (" must start "@interface identifier ( - identifier ) ...": objc-methodprotolist in the first production may - not start with a parenthesized identifier as a declarator of a data - definition with no declaration specifiers if the objc-superclass, - objc-protocol-refs and objc-class-instance-variables are omitted. */ - -static void -c_parser_objc_class_definition (c_parser *parser, tree attributes) -{ - bool iface_p; - tree id1; - tree superclass; - if (c_parser_next_token_is_keyword (parser, RID_AT_INTERFACE)) - iface_p = true; - else if (c_parser_next_token_is_keyword (parser, RID_AT_IMPLEMENTATION)) - iface_p = false; - else - gcc_unreachable (); - - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - return; - } - id1 = c_parser_peek_token (parser)->value; - location_t loc1 = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - /* We have a category or class extension. */ - tree id2; - tree proto = NULL_TREE; - matching_parens parens; - parens.consume_open (parser); - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - /* We have a class extension. */ - id2 = NULL_TREE; - } - else - { - c_parser_error (parser, "expected identifier or %<)%>"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return; - } - } - else - { - id2 = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - } - parens.skip_until_found_close (parser); - if (!iface_p) - { - objc_start_category_implementation (id1, id2); - return; - } - if (c_parser_next_token_is (parser, CPP_LESS)) - proto = c_parser_objc_protocol_refs (parser); - objc_start_category_interface (id1, id2, proto, attributes); - c_parser_objc_methodprotolist (parser); - c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); - objc_finish_interface (); - return; - } - if (c_parser_next_token_is (parser, CPP_COLON)) - { - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - return; - } - superclass = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - } - else - superclass = NULL_TREE; - if (iface_p) - { - tree proto = NULL_TREE; - if (c_parser_next_token_is (parser, CPP_LESS)) - proto = c_parser_objc_protocol_refs (parser); - objc_start_class_interface (id1, loc1, superclass, proto, attributes); - } - else - objc_start_class_implementation (id1, superclass); - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - c_parser_objc_class_instance_variables (parser); - if (iface_p) - { - objc_continue_interface (); - c_parser_objc_methodprotolist (parser); - c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); - objc_finish_interface (); - } - else - { - objc_continue_implementation (); - return; - } -} - -/* Parse objc-class-instance-variables. - - objc-class-instance-variables: - { objc-instance-variable-decl-list[opt] } - - objc-instance-variable-decl-list: - objc-visibility-spec - objc-instance-variable-decl ; - ; - objc-instance-variable-decl-list objc-visibility-spec - objc-instance-variable-decl-list objc-instance-variable-decl ; - objc-instance-variable-decl-list ; - - objc-visibility-spec: - @private - @protected - @public - - objc-instance-variable-decl: - struct-declaration -*/ - -static void -c_parser_objc_class_instance_variables (c_parser *parser) -{ - gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); - c_parser_consume_token (parser); - while (c_parser_next_token_is_not (parser, CPP_EOF)) - { - tree decls; - /* Parse any stray semicolon. */ - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, - "extra semicolon"); - c_parser_consume_token (parser); - continue; - } - /* Stop if at the end of the instance variables. */ - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - c_parser_consume_token (parser); - break; - } - /* Parse any objc-visibility-spec. */ - if (c_parser_next_token_is_keyword (parser, RID_AT_PRIVATE)) - { - c_parser_consume_token (parser); - objc_set_visibility (OBJC_IVAR_VIS_PRIVATE); - continue; - } - else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED)) - { - c_parser_consume_token (parser); - objc_set_visibility (OBJC_IVAR_VIS_PROTECTED); - continue; - } - else if (c_parser_next_token_is_keyword (parser, RID_AT_PUBLIC)) - { - c_parser_consume_token (parser); - objc_set_visibility (OBJC_IVAR_VIS_PUBLIC); - continue; - } - else if (c_parser_next_token_is_keyword (parser, RID_AT_PACKAGE)) - { - c_parser_consume_token (parser); - objc_set_visibility (OBJC_IVAR_VIS_PACKAGE); - continue; - } - else if (c_parser_next_token_is (parser, CPP_PRAGMA)) - { - c_parser_pragma (parser, pragma_external, NULL); - continue; - } - - /* Parse some comma-separated declarations. */ - decls = c_parser_struct_declaration (parser); - if (decls == NULL) - { - /* There is a syntax error. We want to skip the offending - tokens up to the next ';' (included) or '}' - (excluded). */ - - /* First, skip manually a ')' or ']'. This is because they - reduce the nesting level, so c_parser_skip_until_found() - wouldn't be able to skip past them. */ - c_token *token = c_parser_peek_token (parser); - if (token->type == CPP_CLOSE_PAREN || token->type == CPP_CLOSE_SQUARE) - c_parser_consume_token (parser); - - /* Then, do the standard skipping. */ - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - - /* We hopefully recovered. Start normal parsing again. */ - parser->error = false; - continue; - } - else - { - /* Comma-separated instance variables are chained together - in reverse order; add them one by one. */ - tree ivar = nreverse (decls); - for (; ivar; ivar = DECL_CHAIN (ivar)) - objc_add_instance_variable (copy_node (ivar)); - } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - } -} - -/* Parse an objc-class-declaration. - - objc-class-declaration: - @class identifier-list ; -*/ - -static void -c_parser_objc_class_declaration (c_parser *parser) -{ - gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_CLASS)); - c_parser_consume_token (parser); - /* Any identifiers, including those declared as type names, are OK - here. */ - while (true) - { - tree id; - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - parser->error = false; - return; - } - id = c_parser_peek_token (parser)->value; - objc_declare_class (id); - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); -} - -/* Parse an objc-alias-declaration. - - objc-alias-declaration: - @compatibility_alias identifier identifier ; -*/ - -static void -c_parser_objc_alias_declaration (c_parser *parser) -{ - tree id1, id2; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_ALIAS)); - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - return; - } - id1 = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - return; - } - id2 = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - objc_declare_alias (id1, id2); -} - -/* Parse an objc-protocol-definition. - - objc-protocol-definition: - @protocol identifier objc-protocol-refs[opt] objc-methodprotolist @end - @protocol identifier-list ; - - "@protocol identifier ;" should be resolved as "@protocol - identifier-list ;": objc-methodprotolist may not start with a - semicolon in the first alternative if objc-protocol-refs are - omitted. */ - -static void -c_parser_objc_protocol_definition (c_parser *parser, tree attributes) -{ - gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL)); - - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - return; - } - if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA - || c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON) - { - /* Any identifiers, including those declared as type names, are - OK here. */ - while (true) - { - tree id; - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - break; - } - id = c_parser_peek_token (parser)->value; - objc_declare_protocol (id, attributes); - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - } - else - { - tree id = c_parser_peek_token (parser)->value; - tree proto = NULL_TREE; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_LESS)) - proto = c_parser_objc_protocol_refs (parser); - parser->objc_pq_context = true; - objc_start_protocol (id, proto, attributes); - c_parser_objc_methodprotolist (parser); - c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); - parser->objc_pq_context = false; - objc_finish_interface (); - } -} - -/* Parse an objc-method-type. - - objc-method-type: - + - - - - Return true if it is a class method (+) and false if it is - an instance method (-). -*/ -static inline bool -c_parser_objc_method_type (c_parser *parser) -{ - switch (c_parser_peek_token (parser)->type) - { - case CPP_PLUS: - c_parser_consume_token (parser); - return true; - case CPP_MINUS: - c_parser_consume_token (parser); - return false; - default: - gcc_unreachable (); - } -} - -/* Parse an objc-method-definition. - - objc-method-definition: - objc-method-type objc-method-decl ;[opt] compound-statement -*/ - -static void -c_parser_objc_method_definition (c_parser *parser) -{ - bool is_class_method = c_parser_objc_method_type (parser); - tree decl, attributes = NULL_TREE, expr = NULL_TREE; - parser->objc_pq_context = true; - decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, - &expr); - if (decl == error_mark_node) - return; /* Bail here. */ - - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - c_parser_consume_token (parser); - pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, - "extra semicolon in method definition specified"); - } - - if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - { - c_parser_error (parser, "expected %<{%>"); - return; - } - - parser->objc_pq_context = false; - if (objc_start_method_definition (is_class_method, decl, attributes, expr)) - { - add_stmt (c_parser_compound_statement (parser)); - objc_finish_method_definition (current_function_decl); - } - else - { - /* This code is executed when we find a method definition - outside of an @implementation context (or invalid for other - reasons). Parse the method (to keep going) but do not emit - any code. - */ - c_parser_compound_statement (parser); - } -} - -/* Parse an objc-methodprotolist. - - objc-methodprotolist: - empty - objc-methodprotolist objc-methodproto - objc-methodprotolist declaration - objc-methodprotolist ; - @optional - @required - - The declaration is a data definition, which may be missing - declaration specifiers under the same rules and diagnostics as - other data definitions outside functions, and the stray semicolon - is diagnosed the same way as a stray semicolon outside a - function. */ - -static void -c_parser_objc_methodprotolist (c_parser *parser) -{ - while (true) - { - /* The list is terminated by @end. */ - switch (c_parser_peek_token (parser)->type) - { - case CPP_SEMICOLON: - pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, - "ISO C does not allow extra %<;%> outside of a function"); - c_parser_consume_token (parser); - break; - case CPP_PLUS: - case CPP_MINUS: - c_parser_objc_methodproto (parser); - break; - case CPP_PRAGMA: - c_parser_pragma (parser, pragma_external, NULL); - break; - case CPP_EOF: - return; - default: - if (c_parser_next_token_is_keyword (parser, RID_AT_END)) - return; - else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)) - c_parser_objc_at_property_declaration (parser); - else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL)) - { - objc_set_method_opt (true); - c_parser_consume_token (parser); - } - else if (c_parser_next_token_is_keyword (parser, RID_AT_REQUIRED)) - { - objc_set_method_opt (false); - c_parser_consume_token (parser); - } - else - c_parser_declaration_or_fndef (parser, false, false, true, - false, true); - break; - } - } -} - -/* Parse an objc-methodproto. - - objc-methodproto: - objc-method-type objc-method-decl ; -*/ - -static void -c_parser_objc_methodproto (c_parser *parser) -{ - bool is_class_method = c_parser_objc_method_type (parser); - tree decl, attributes = NULL_TREE; - - /* Remember protocol qualifiers in prototypes. */ - parser->objc_pq_context = true; - decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, - NULL); - /* Forget protocol qualifiers now. */ - parser->objc_pq_context = false; - - /* Do not allow the presence of attributes to hide an erroneous - method implementation in the interface section. */ - if (!c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - c_parser_error (parser, "expected %<;%>"); - return; - } - - if (decl != error_mark_node) - objc_add_method_declaration (is_class_method, decl, attributes); - - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); -} - -/* If we are at a position that method attributes may be present, check that - there are not any parsed already (a syntax error) and then collect any - specified at the current location. Finally, if new attributes were present, - check that the next token is legal ( ';' for decls and '{' for defs). */ - -static bool -c_parser_objc_maybe_method_attributes (c_parser* parser, tree* attributes) -{ - bool bad = false; - if (*attributes) - { - c_parser_error (parser, - "method attributes must be specified at the end only"); - *attributes = NULL_TREE; - bad = true; - } - - if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - *attributes = c_parser_gnu_attributes (parser); - - /* If there were no attributes here, just report any earlier error. */ - if (*attributes == NULL_TREE || bad) - return bad; - - /* If the attributes are followed by a ; or {, then just report any earlier - error. */ - if (c_parser_next_token_is (parser, CPP_SEMICOLON) - || c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - return bad; - - /* We've got attributes, but not at the end. */ - c_parser_error (parser, - "expected %<;%> or %<{%> after method attribute definition"); - return true; -} - -/* Parse an objc-method-decl. - - objc-method-decl: - ( objc-type-name ) objc-selector - objc-selector - ( objc-type-name ) objc-keyword-selector objc-optparmlist - objc-keyword-selector objc-optparmlist - gnu-attributes - - objc-keyword-selector: - objc-keyword-decl - objc-keyword-selector objc-keyword-decl - - objc-keyword-decl: - objc-selector : ( objc-type-name ) identifier - objc-selector : identifier - : ( objc-type-name ) identifier - : identifier - - objc-optparmlist: - objc-optparms objc-optellipsis - - objc-optparms: - empty - objc-opt-parms , parameter-declaration - - objc-optellipsis: - empty - , ... -*/ - -static tree -c_parser_objc_method_decl (c_parser *parser, bool is_class_method, - tree *attributes, tree *expr) -{ - tree type = NULL_TREE; - tree sel; - tree parms = NULL_TREE; - bool ellipsis = false; - bool attr_err = false; - - *attributes = NULL_TREE; - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - matching_parens parens; - parens.consume_open (parser); - type = c_parser_objc_type_name (parser); - parens.skip_until_found_close (parser); - } - sel = c_parser_objc_selector (parser); - /* If there is no selector, or a colon follows, we have an - objc-keyword-selector. If there is a selector, and a colon does - not follow, that selector ends the objc-method-decl. */ - if (!sel || c_parser_next_token_is (parser, CPP_COLON)) - { - tree tsel = sel; - tree list = NULL_TREE; - while (true) - { - tree atype = NULL_TREE, id, keyworddecl; - tree param_attr = NULL_TREE; - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - break; - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - c_parser_consume_token (parser); - atype = c_parser_objc_type_name (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - } - /* New ObjC allows attributes on method parameters. */ - if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - param_attr = c_parser_gnu_attributes (parser); - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - return error_mark_node; - } - id = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - keyworddecl = objc_build_keyword_decl (tsel, atype, id, param_attr); - list = chainon (list, keyworddecl); - tsel = c_parser_objc_selector (parser); - if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON)) - break; - } - - attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; - - /* Parse the optional parameter list. Optional Objective-C - method parameters follow the C syntax, and may include '...' - to denote a variable number of arguments. */ - parms = make_node (TREE_LIST); - while (c_parser_next_token_is (parser, CPP_COMMA)) - { - struct c_parm *parm; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) - { - ellipsis = true; - c_parser_consume_token (parser); - attr_err |= c_parser_objc_maybe_method_attributes - (parser, attributes) ; - break; - } - parm = c_parser_parameter_declaration (parser, NULL_TREE, false); - if (parm == NULL) - break; - parms = chainon (parms, - build_tree_list (NULL_TREE, grokparm (parm, expr))); - } - sel = list; - } - else - attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; - - if (sel == NULL) - { - c_parser_error (parser, "objective-c method declaration is expected"); - return error_mark_node; - } - - if (attr_err) - return error_mark_node; - - return objc_build_method_signature (is_class_method, type, sel, parms, ellipsis); -} - -/* Parse an objc-type-name. - - objc-type-name: - objc-type-qualifiers[opt] type-name - objc-type-qualifiers[opt] - - objc-type-qualifiers: - objc-type-qualifier - objc-type-qualifiers objc-type-qualifier - - objc-type-qualifier: one of - in out inout bycopy byref oneway -*/ - -static tree -c_parser_objc_type_name (c_parser *parser) -{ - tree quals = NULL_TREE; - struct c_type_name *type_name = NULL; - tree type = NULL_TREE; - while (true) - { - c_token *token = c_parser_peek_token (parser); - if (token->type == CPP_KEYWORD - && (token->keyword == RID_IN - || token->keyword == RID_OUT - || token->keyword == RID_INOUT - || token->keyword == RID_BYCOPY - || token->keyword == RID_BYREF - || token->keyword == RID_ONEWAY)) - { - quals = chainon (build_tree_list (NULL_TREE, token->value), quals); - c_parser_consume_token (parser); - } - else - break; - } - if (c_parser_next_tokens_start_typename (parser, cla_prefer_type)) - type_name = c_parser_type_name (parser); - if (type_name) - type = groktypename (type_name, NULL, NULL); - - /* If the type is unknown, and error has already been produced and - we need to recover from the error. In that case, use NULL_TREE - for the type, as if no type had been specified; this will use the - default type ('id') which is good for error recovery. */ - if (type == error_mark_node) - type = NULL_TREE; - - return build_tree_list (quals, type); -} - -/* Parse objc-protocol-refs. - - objc-protocol-refs: - < identifier-list > -*/ - -static tree -c_parser_objc_protocol_refs (c_parser *parser) -{ - tree list = NULL_TREE; - gcc_assert (c_parser_next_token_is (parser, CPP_LESS)); - c_parser_consume_token (parser); - /* Any identifiers, including those declared as type names, are OK - here. */ - while (true) - { - tree id; - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - break; - } - id = c_parser_peek_token (parser)->value; - list = chainon (list, build_tree_list (NULL_TREE, id)); - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - c_parser_require (parser, CPP_GREATER, "expected %<>%>"); - return list; -} - -/* Parse an objc-try-catch-finally-statement. - - objc-try-catch-finally-statement: - @try compound-statement objc-catch-list[opt] - @try compound-statement objc-catch-list[opt] @finally compound-statement - - objc-catch-list: - @catch ( objc-catch-parameter-declaration ) compound-statement - objc-catch-list @catch ( objc-catch-parameter-declaration ) compound-statement - - objc-catch-parameter-declaration: - parameter-declaration - '...' - - where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS. - - PS: This function is identical to cp_parser_objc_try_catch_finally_statement - for C++. Keep them in sync. */ - -static void -c_parser_objc_try_catch_finally_statement (c_parser *parser) -{ - location_t location; - tree stmt; - - gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY)); - c_parser_consume_token (parser); - location = c_parser_peek_token (parser)->location; - objc_maybe_warn_exceptions (location); - stmt = c_parser_compound_statement (parser); - objc_begin_try_stmt (location, stmt); - - while (c_parser_next_token_is_keyword (parser, RID_AT_CATCH)) - { - struct c_parm *parm; - tree parameter_declaration = error_mark_node; - bool seen_open_paren = false; - - c_parser_consume_token (parser); - matching_parens parens; - if (!parens.require_open (parser)) - seen_open_paren = true; - if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) - { - /* We have "@catch (...)" (where the '...' are literally - what is in the code). Skip the '...'. - parameter_declaration is set to NULL_TREE, and - objc_being_catch_clauses() knows that that means - '...'. */ - c_parser_consume_token (parser); - parameter_declaration = NULL_TREE; - } - else - { - /* We have "@catch (NSException *exception)" or something - like that. Parse the parameter declaration. */ - parm = c_parser_parameter_declaration (parser, NULL_TREE, false); - if (parm == NULL) - parameter_declaration = error_mark_node; - else - parameter_declaration = grokparm (parm, NULL); - } - if (seen_open_paren) - parens.require_close (parser); - else - { - /* If there was no open parenthesis, we are recovering from - an error, and we are trying to figure out what mistake - the user has made. */ - - /* If there is an immediate closing parenthesis, the user - probably forgot the opening one (ie, they typed "@catch - NSException *e)". Parse the closing parenthesis and keep - going. */ - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - c_parser_consume_token (parser); - - /* If these is no immediate closing parenthesis, the user - probably doesn't know that parenthesis are required at - all (ie, they typed "@catch NSException *e"). So, just - forget about the closing parenthesis and keep going. */ - } - objc_begin_catch_clause (parameter_declaration); - if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) - c_parser_compound_statement_nostart (parser); - objc_finish_catch_clause (); - } - if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY)) - { - c_parser_consume_token (parser); - location = c_parser_peek_token (parser)->location; - stmt = c_parser_compound_statement (parser); - objc_build_finally_clause (location, stmt); - } - objc_finish_try_stmt (); -} - -/* Parse an objc-synchronized-statement. - - objc-synchronized-statement: - @synchronized ( expression ) compound-statement -*/ - -static void -c_parser_objc_synchronized_statement (c_parser *parser) -{ - location_t loc; - tree expr, stmt; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED)); - c_parser_consume_token (parser); - loc = c_parser_peek_token (parser)->location; - objc_maybe_warn_exceptions (loc); - matching_parens parens; - if (parens.require_open (parser)) - { - struct c_expr ce = c_parser_expression (parser); - ce = convert_lvalue_to_rvalue (loc, ce, false, false); - expr = ce.value; - expr = c_fully_fold (expr, false, NULL); - parens.skip_until_found_close (parser); - } - else - expr = error_mark_node; - stmt = c_parser_compound_statement (parser); - objc_build_synchronized (loc, expr, stmt); -} - -/* Parse an objc-selector; return NULL_TREE without an error if the - next token is not an objc-selector. - - objc-selector: - identifier - one of - enum struct union if else while do for switch case default - break continue return goto asm sizeof typeof __alignof - unsigned long const short volatile signed restrict _Complex - in out inout bycopy byref oneway int char float double void _Bool - _Atomic - - ??? Why this selection of keywords but not, for example, storage - class specifiers? */ - -static tree -c_parser_objc_selector (c_parser *parser) -{ - c_token *token = c_parser_peek_token (parser); - tree value = token->value; - if (token->type == CPP_NAME) - { - c_parser_consume_token (parser); - return value; - } - if (token->type != CPP_KEYWORD) - return NULL_TREE; - switch (token->keyword) - { - case RID_ENUM: - case RID_STRUCT: - case RID_UNION: - case RID_IF: - case RID_ELSE: - case RID_WHILE: - case RID_DO: - case RID_FOR: - case RID_SWITCH: - case RID_CASE: - case RID_DEFAULT: - case RID_BREAK: - case RID_CONTINUE: - case RID_RETURN: - case RID_GOTO: - case RID_ASM: - case RID_SIZEOF: - case RID_TYPEOF: - case RID_ALIGNOF: - case RID_UNSIGNED: - case RID_LONG: - case RID_CONST: - case RID_SHORT: - case RID_VOLATILE: - case RID_SIGNED: - case RID_RESTRICT: - case RID_COMPLEX: - case RID_IN: - case RID_OUT: - case RID_INOUT: - case RID_BYCOPY: - case RID_BYREF: - case RID_ONEWAY: - case RID_INT: - case RID_CHAR: - case RID_FLOAT: - case RID_DOUBLE: - CASE_RID_FLOATN_NX: - case RID_VOID: - case RID_BOOL: - case RID_ATOMIC: - case RID_AUTO_TYPE: - case RID_INT_N_0: - case RID_INT_N_1: - case RID_INT_N_2: - case RID_INT_N_3: - c_parser_consume_token (parser); - return value; - default: - return NULL_TREE; - } -} - -/* Parse an objc-selector-arg. - - objc-selector-arg: - objc-selector - objc-keywordname-list - - objc-keywordname-list: - objc-keywordname - objc-keywordname-list objc-keywordname - - objc-keywordname: - objc-selector : - : -*/ - -static tree -c_parser_objc_selector_arg (c_parser *parser) -{ - tree sel = c_parser_objc_selector (parser); - tree list = NULL_TREE; - if (sel - && c_parser_next_token_is_not (parser, CPP_COLON) - && c_parser_next_token_is_not (parser, CPP_SCOPE)) - return sel; - while (true) - { - if (c_parser_next_token_is (parser, CPP_SCOPE)) - { - c_parser_consume_token (parser); - list = chainon (list, build_tree_list (sel, NULL_TREE)); - list = chainon (list, build_tree_list (NULL_TREE, NULL_TREE)); - } - else - { - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - return list; - list = chainon (list, build_tree_list (sel, NULL_TREE)); - } - sel = c_parser_objc_selector (parser); - if (!sel - && c_parser_next_token_is_not (parser, CPP_COLON) - && c_parser_next_token_is_not (parser, CPP_SCOPE)) - break; - } - return list; -} - -/* Parse an objc-receiver. - - objc-receiver: - expression - class-name - type-name -*/ - -static tree -c_parser_objc_receiver (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - - if (c_parser_peek_token (parser)->type == CPP_NAME - && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME - || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) - { - tree id = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - return objc_get_class_reference (id); - } - struct c_expr ce = c_parser_expression (parser); - ce = convert_lvalue_to_rvalue (loc, ce, false, false); - return c_fully_fold (ce.value, false, NULL); -} - -/* Parse objc-message-args. - - objc-message-args: - objc-selector - objc-keywordarg-list - - objc-keywordarg-list: - objc-keywordarg - objc-keywordarg-list objc-keywordarg - - objc-keywordarg: - objc-selector : objc-keywordexpr - : objc-keywordexpr -*/ - -static tree -c_parser_objc_message_args (c_parser *parser) -{ - tree sel = c_parser_objc_selector (parser); - tree list = NULL_TREE; - if (sel && c_parser_next_token_is_not (parser, CPP_COLON)) - return sel; - while (true) - { - tree keywordexpr; - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - return error_mark_node; - keywordexpr = c_parser_objc_keywordexpr (parser); - list = chainon (list, build_tree_list (sel, keywordexpr)); - sel = c_parser_objc_selector (parser); - if (!sel && c_parser_next_token_is_not (parser, CPP_COLON)) - break; - } - return list; -} - -/* Parse an objc-keywordexpr. - - objc-keywordexpr: - nonempty-expr-list -*/ - -static tree -c_parser_objc_keywordexpr (c_parser *parser) -{ - tree ret; - vec *expr_list = c_parser_expr_list (parser, true, true, - NULL, NULL, NULL, NULL); - if (vec_safe_length (expr_list) == 1) - { - /* Just return the expression, remove a level of - indirection. */ - ret = (*expr_list)[0]; - } - else - { - /* We have a comma expression, we will collapse later. */ - ret = build_tree_list_vec (expr_list); - } - release_tree_vector (expr_list); - return ret; -} - -/* A check, needed in several places, that ObjC interface, implementation or - method definitions are not prefixed by incorrect items. */ -static bool -c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, - struct c_declspecs *specs) -{ - if (!specs->declspecs_seen_p || specs->non_sc_seen_p - || specs->typespec_kind != ctsk_none) - { - c_parser_error (parser, - "no type or storage class may be specified here,"); - c_parser_skip_to_end_of_block_or_statement (parser); - return true; - } - return false; -} - -/* Parse an Objective-C @property declaration. The syntax is: - - objc-property-declaration: - '@property' objc-property-attributes[opt] struct-declaration ; - - objc-property-attributes: - '(' objc-property-attribute-list ')' - - objc-property-attribute-list: - objc-property-attribute - objc-property-attribute-list, objc-property-attribute - - objc-property-attribute - 'getter' = identifier - 'setter' = identifier - 'readonly' - 'readwrite' - 'assign' - 'retain' - 'copy' - 'nonatomic' - - For example: - @property NSString *name; - @property (readonly) id object; - @property (retain, nonatomic, getter=getTheName) id name; - @property int a, b, c; - - PS: This function is identical to cp_parser_objc_at_propery_declaration - for C++. Keep them in sync. */ -static void -c_parser_objc_at_property_declaration (c_parser *parser) -{ - gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)); - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); /* Eat '@property'. */ - - /* Parse the optional attribute list. - - A list of parsed, but not verified, attributes. */ - vec prop_attr_list = vNULL; - - bool syntax_error = false; - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - matching_parens parens; - - location_t attr_start = c_parser_peek_token (parser)->location; - /* Eat the '(' */ - parens.consume_open (parser); - - /* Property attribute keywords are valid now. */ - parser->objc_property_attr_context = true; - - /* Allow @property (), with a warning. */ - location_t attr_end = c_parser_peek_token (parser)->location; - - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - location_t attr_comb = make_location (attr_end, attr_start, attr_end); - warning_at (attr_comb, OPT_Wattributes, - "empty property attribute list"); - } - else - while (true) - { - c_token *token = c_parser_peek_token (parser); - attr_start = token->location; - attr_end = get_finish (token->location); - location_t attr_comb = make_location (attr_start, attr_start, - attr_end); - - if (token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA) - { - warning_at (attr_comb, OPT_Wattributes, - "missing property attribute"); - if (token->type == CPP_CLOSE_PAREN) - break; - c_parser_consume_token (parser); - continue; - } - - tree attr_name = NULL_TREE; - enum rid keyword = RID_MAX; /* Not a valid property attribute. */ - bool add_at = false; - if (token->type == CPP_KEYWORD) - { - keyword = token->keyword; - if (OBJC_IS_AT_KEYWORD (keyword)) - { - /* For '@' keywords the token value has the keyword, - prepend the '@' for diagnostics. */ - attr_name = token->value; - add_at = true; - } - else - attr_name = ridpointers[(int)keyword]; - } - else if (token->type == CPP_NAME) - attr_name = token->value; - c_parser_consume_token (parser); - - enum objc_property_attribute_kind prop_kind - = objc_prop_attr_kind_for_rid (keyword); - property_attribute_info *prop - = new property_attribute_info (attr_name, attr_comb, prop_kind); - prop_attr_list.safe_push (prop); - - tree meth_name; - switch (prop->prop_kind) - { - default: break; - case OBJC_PROPERTY_ATTR_UNKNOWN: - if (attr_name) - error_at (attr_comb, "unknown property attribute %<%s%s%>", - add_at ? "@" : "", IDENTIFIER_POINTER (attr_name)); - else - error_at (attr_comb, "unknown property attribute"); - prop->parse_error = syntax_error = true; - break; - - case OBJC_PROPERTY_ATTR_GETTER: - case OBJC_PROPERTY_ATTR_SETTER: - if (c_parser_next_token_is_not (parser, CPP_EQ)) - { - attr_comb = make_location (attr_end, attr_start, attr_end); - error_at (attr_comb, "expected %<=%> after Objective-C %qE", - attr_name); - prop->parse_error = syntax_error = true; - break; - } - token = c_parser_peek_token (parser); - attr_end = token->location; - c_parser_consume_token (parser); /* eat the = */ - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - attr_comb = make_location (attr_end, attr_start, attr_end); - error_at (attr_comb, "expected %qE selector name", - attr_name); - prop->parse_error = syntax_error = true; - break; - } - /* Get the end of the method name, and consume the name. */ - token = c_parser_peek_token (parser); - attr_end = get_finish (token->location); - meth_name = token->value; - c_parser_consume_token (parser); - if (prop->prop_kind == OBJC_PROPERTY_ATTR_SETTER) - { - if (c_parser_next_token_is_not (parser, CPP_COLON)) - { - attr_comb = make_location (attr_end, attr_start, - attr_end); - error_at (attr_comb, "setter method names must" - " terminate with %<:%>"); - prop->parse_error = syntax_error = true; - } - else - { - attr_end = get_finish (c_parser_peek_token - (parser)->location); - c_parser_consume_token (parser); - } - attr_comb = make_location (attr_start, attr_start, - attr_end); - } - else - attr_comb = make_location (attr_start, attr_start, - attr_end); - prop->ident = meth_name; - /* Updated location including all that was successfully - parsed. */ - prop->prop_loc = attr_comb; - break; - } - - /* If we see a comma here, then keep going - even if we already - saw a syntax error. For simple mistakes e.g. (asign, getter=x) - this makes a more useful output and avoid spurious warnings about - missing attributes that are, in fact, specified after the one with - the syntax error. */ - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - parser->objc_property_attr_context = false; - - if (syntax_error && c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) - /* We don't really want to chew the whole of the file looking for a - matching closing parenthesis, so we will try to read the decl and - let the error handling for that close out the statement. */ - ; - else - syntax_error = false, parens.skip_until_found_close (parser); - } - - /* 'properties' is the list of properties that we read. Usually a - single one, but maybe more (eg, in "@property int a, b, c;" there - are three). */ - tree properties = c_parser_struct_declaration (parser); - - if (properties == error_mark_node) - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - else - { - if (properties == NULL_TREE) - c_parser_error (parser, "expected identifier"); - else - { - /* Comma-separated properties are chained together in reverse order; - add them one by one. */ - properties = nreverse (properties); - for (; properties; properties = TREE_CHAIN (properties)) - objc_add_property_declaration (loc, copy_node (properties), - prop_attr_list); - } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - } - - while (!prop_attr_list.is_empty()) - delete prop_attr_list.pop (); - prop_attr_list.release (); - parser->error = false; -} - -/* Parse an Objective-C @synthesize declaration. The syntax is: - - objc-synthesize-declaration: - @synthesize objc-synthesize-identifier-list ; - - objc-synthesize-identifier-list: - objc-synthesize-identifier - objc-synthesize-identifier-list, objc-synthesize-identifier - - objc-synthesize-identifier - identifier - identifier = identifier - - For example: - @synthesize MyProperty; - @synthesize OneProperty, AnotherProperty=MyIvar, YetAnotherProperty; - - PS: This function is identical to cp_parser_objc_at_synthesize_declaration - for C++. Keep them in sync. -*/ -static void -c_parser_objc_at_synthesize_declaration (c_parser *parser) -{ - tree list = NULL_TREE; - location_t loc; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNTHESIZE)); - loc = c_parser_peek_token (parser)->location; - - c_parser_consume_token (parser); - while (true) - { - tree property, ivar; - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - /* Once we find the semicolon, we can resume normal parsing. - We have to reset parser->error manually because - c_parser_skip_until_found() won't reset it for us if the - next token is precisely a semicolon. */ - parser->error = false; - return; - } - property = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_EQ)) - { - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - parser->error = false; - return; - } - ivar = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - } - else - ivar = NULL_TREE; - list = chainon (list, build_tree_list (ivar, property)); - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - objc_add_synthesize_declaration (loc, list); -} - -/* Parse an Objective-C @dynamic declaration. The syntax is: - - objc-dynamic-declaration: - @dynamic identifier-list ; - - For example: - @dynamic MyProperty; - @dynamic MyProperty, AnotherProperty; - - PS: This function is identical to cp_parser_objc_at_dynamic_declaration - for C++. Keep them in sync. -*/ -static void -c_parser_objc_at_dynamic_declaration (c_parser *parser) -{ - tree list = NULL_TREE; - location_t loc; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_DYNAMIC)); - loc = c_parser_peek_token (parser)->location; - - c_parser_consume_token (parser); - while (true) - { - tree property; - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - parser->error = false; - return; - } - property = c_parser_peek_token (parser)->value; - list = chainon (list, build_tree_list (NULL_TREE, property)); - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - objc_add_dynamic_declaration (loc, list); -} - - -/* Parse a pragma GCC ivdep. */ - -static bool -c_parse_pragma_ivdep (c_parser *parser) -{ - c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); - return true; -} - -/* Parse a pragma GCC unroll. */ - -static unsigned short -c_parser_pragma_unroll (c_parser *parser) -{ - unsigned short unroll; - c_parser_consume_pragma (parser); - location_t location = c_parser_peek_token (parser)->location; - tree expr = c_parser_expr_no_commas (parser, NULL).value; - mark_exp_read (expr); - expr = c_fully_fold (expr, false, NULL); - HOST_WIDE_INT lunroll = 0; - if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) - || TREE_CODE (expr) != INTEGER_CST - || (lunroll = tree_to_shwi (expr)) < 0 - || lunroll >= USHRT_MAX) - { - error_at (location, "%<#pragma GCC unroll%> requires an" - " assignment-expression that evaluates to a non-negative" - " integral constant less than %u", USHRT_MAX); - unroll = 0; - } - else - { - unroll = (unsigned short)lunroll; - if (unroll == 0) - unroll = 1; - } - - c_parser_skip_to_pragma_eol (parser); - return unroll; -} - -/* Handle pragmas. Some OpenMP pragmas are associated with, and therefore - should be considered, statements. ALLOW_STMT is true if we're within - the context of a function and such pragmas are to be allowed. Returns - true if we actually parsed such a pragma. */ - -static bool -c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) -{ - unsigned int id; - const char *construct = NULL; - - id = c_parser_peek_token (parser)->pragma_kind; - gcc_assert (id != PRAGMA_NONE); - - switch (id) - { - case PRAGMA_OACC_DECLARE: - c_parser_oacc_declare (parser); - return false; - - case PRAGMA_OACC_ENTER_DATA: - if (context != pragma_compound) - { - construct = "acc enter data"; - in_compound: - if (context == pragma_stmt) - { - error_at (c_parser_peek_token (parser)->location, - "%<#pragma %s%> may only be used in compound " - "statements", construct); - c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); - return true; - } - goto bad_stmt; - } - c_parser_oacc_enter_exit_data (parser, true); - return false; - - case PRAGMA_OACC_EXIT_DATA: - if (context != pragma_compound) - { - construct = "acc exit data"; - goto in_compound; - } - c_parser_oacc_enter_exit_data (parser, false); - return false; - - case PRAGMA_OACC_ROUTINE: - if (context != pragma_external) - { - error_at (c_parser_peek_token (parser)->location, - "%<#pragma acc routine%> must be at file scope"); - c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); - return false; - } - c_parser_oacc_routine (parser, context); - return false; - - case PRAGMA_OACC_UPDATE: - if (context != pragma_compound) - { - construct = "acc update"; - goto in_compound; - } - c_parser_oacc_update (parser); - return false; - - case PRAGMA_OMP_BARRIER: - if (context != pragma_compound) - { - construct = "omp barrier"; - goto in_compound; - } - c_parser_omp_barrier (parser); - return false; - - case PRAGMA_OMP_DEPOBJ: - if (context != pragma_compound) - { - construct = "omp depobj"; - goto in_compound; - } - c_parser_omp_depobj (parser); - return false; - - case PRAGMA_OMP_FLUSH: - if (context != pragma_compound) - { - construct = "omp flush"; - goto in_compound; - } - c_parser_omp_flush (parser); - return false; - - case PRAGMA_OMP_TASKWAIT: - if (context != pragma_compound) - { - construct = "omp taskwait"; - goto in_compound; - } - c_parser_omp_taskwait (parser); - return false; - - case PRAGMA_OMP_TASKYIELD: - if (context != pragma_compound) - { - construct = "omp taskyield"; - goto in_compound; - } - c_parser_omp_taskyield (parser); - return false; - - case PRAGMA_OMP_CANCEL: - if (context != pragma_compound) - { - construct = "omp cancel"; - goto in_compound; - } - c_parser_omp_cancel (parser); - return false; - - case PRAGMA_OMP_CANCELLATION_POINT: - return c_parser_omp_cancellation_point (parser, context); - - case PRAGMA_OMP_THREADPRIVATE: - c_parser_omp_threadprivate (parser); - return false; - - case PRAGMA_OMP_TARGET: - return c_parser_omp_target (parser, context, if_p); - - case PRAGMA_OMP_END_DECLARE_TARGET: - c_parser_omp_end_declare_target (parser); - return false; - - case PRAGMA_OMP_SCAN: - error_at (c_parser_peek_token (parser)->location, - "%<#pragma omp scan%> may only be used in " - "a loop construct with % % clause"); - c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); - return false; - - case PRAGMA_OMP_SECTION: - error_at (c_parser_peek_token (parser)->location, - "%<#pragma omp section%> may only be used in " - "%<#pragma omp sections%> construct"); - c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); - return false; - - case PRAGMA_OMP_DECLARE: - return c_parser_omp_declare (parser, context); - - case PRAGMA_OMP_REQUIRES: - if (context != pragma_external) - { - error_at (c_parser_peek_token (parser)->location, - "%<#pragma omp requires%> may only be used at file scope"); - c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); - return false; - } - c_parser_omp_requires (parser); - return false; - - case PRAGMA_OMP_NOTHING: - c_parser_omp_nothing (parser); - return false; - - case PRAGMA_OMP_ERROR: - return c_parser_omp_error (parser, context); - - case PRAGMA_OMP_ORDERED: - return c_parser_omp_ordered (parser, context, if_p); - - case PRAGMA_IVDEP: - { - const bool ivdep = c_parse_pragma_ivdep (parser); - unsigned short unroll; - if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_UNROLL) - unroll = c_parser_pragma_unroll (parser); - else - unroll = 0; - if (!c_parser_next_token_is_keyword (parser, RID_FOR) - && !c_parser_next_token_is_keyword (parser, RID_WHILE) - && !c_parser_next_token_is_keyword (parser, RID_DO)) - { - c_parser_error (parser, "for, while or do statement expected"); - return false; - } - if (c_parser_next_token_is_keyword (parser, RID_FOR)) - c_parser_for_statement (parser, ivdep, unroll, if_p); - else if (c_parser_next_token_is_keyword (parser, RID_WHILE)) - c_parser_while_statement (parser, ivdep, unroll, if_p); - else - c_parser_do_statement (parser, ivdep, unroll); - } - return true; - - case PRAGMA_UNROLL: - { - unsigned short unroll = c_parser_pragma_unroll (parser); - bool ivdep; - if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_IVDEP) - ivdep = c_parse_pragma_ivdep (parser); - else - ivdep = false; - if (!c_parser_next_token_is_keyword (parser, RID_FOR) - && !c_parser_next_token_is_keyword (parser, RID_WHILE) - && !c_parser_next_token_is_keyword (parser, RID_DO)) - { - c_parser_error (parser, "for, while or do statement expected"); - return false; - } - if (c_parser_next_token_is_keyword (parser, RID_FOR)) - c_parser_for_statement (parser, ivdep, unroll, if_p); - else if (c_parser_next_token_is_keyword (parser, RID_WHILE)) - c_parser_while_statement (parser, ivdep, unroll, if_p); - else - c_parser_do_statement (parser, ivdep, unroll); - } - return true; - - case PRAGMA_GCC_PCH_PREPROCESS: - c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); - c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); - return false; - - case PRAGMA_OACC_WAIT: - if (context != pragma_compound) - { - construct = "acc wait"; - goto in_compound; - } - /* FALL THROUGH. */ - - default: - if (id < PRAGMA_FIRST_EXTERNAL) - { - if (context != pragma_stmt && context != pragma_compound) - { - bad_stmt: - c_parser_error (parser, "expected declaration specifiers"); - c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); - return false; - } - c_parser_omp_construct (parser, if_p); - return true; - } - break; - } - - c_parser_consume_pragma (parser); - c_invoke_pragma_handler (id); - - /* Skip to EOL, but suppress any error message. Those will have been - generated by the handler routine through calling error, as opposed - to calling c_parser_error. */ - parser->error = true; - c_parser_skip_to_pragma_eol (parser); - - return false; -} - -/* The interface the pragma parsers have to the lexer. */ - -enum cpp_ttype -pragma_lex (tree *value, location_t *loc) -{ - c_token *tok = c_parser_peek_token (the_parser); - enum cpp_ttype ret = tok->type; - - *value = tok->value; - if (loc) - *loc = tok->location; - - if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) - ret = CPP_EOF; - else if (ret == CPP_STRING) - *value = c_parser_string_literal (the_parser, false, false).value; - else - { - if (ret == CPP_KEYWORD) - ret = CPP_NAME; - c_parser_consume_token (the_parser); - } - - return ret; -} - -static void -c_parser_pragma_pch_preprocess (c_parser *parser) -{ - tree name = NULL; - - parser->lex_joined_string = true; - c_parser_consume_pragma (parser); - if (c_parser_next_token_is (parser, CPP_STRING)) - { - name = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - } - else - c_parser_error (parser, "expected string literal"); - c_parser_skip_to_pragma_eol (parser); - parser->lex_joined_string = false; - - if (name) - c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); -} - -/* OpenACC and OpenMP parsing routines. */ - -/* Returns name of the next clause. - If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and - the token is not consumed. Otherwise appropriate pragma_omp_clause is - returned and the token is consumed. */ - -static pragma_omp_clause -c_parser_omp_clause_name (c_parser *parser) -{ - pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; - - if (c_parser_next_token_is_keyword (parser, RID_AUTO)) - result = PRAGMA_OACC_CLAUSE_AUTO; - else if (c_parser_next_token_is_keyword (parser, RID_IF)) - result = PRAGMA_OMP_CLAUSE_IF; - else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) - result = PRAGMA_OMP_CLAUSE_DEFAULT; - else if (c_parser_next_token_is_keyword (parser, RID_FOR)) - result = PRAGMA_OMP_CLAUSE_FOR; - else if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - switch (p[0]) - { - case 'a': - if (!strcmp ("affinity", p)) - result = PRAGMA_OMP_CLAUSE_AFFINITY; - else if (!strcmp ("aligned", p)) - result = PRAGMA_OMP_CLAUSE_ALIGNED; - else if (!strcmp ("allocate", p)) - result = PRAGMA_OMP_CLAUSE_ALLOCATE; - else if (!strcmp ("async", p)) - result = PRAGMA_OACC_CLAUSE_ASYNC; - else if (!strcmp ("attach", p)) - result = PRAGMA_OACC_CLAUSE_ATTACH; - break; - case 'b': - if (!strcmp ("bind", p)) - result = PRAGMA_OMP_CLAUSE_BIND; - break; - case 'c': - if (!strcmp ("collapse", p)) - result = PRAGMA_OMP_CLAUSE_COLLAPSE; - else if (!strcmp ("copy", p)) - result = PRAGMA_OACC_CLAUSE_COPY; - else if (!strcmp ("copyin", p)) - result = PRAGMA_OMP_CLAUSE_COPYIN; - else if (!strcmp ("copyout", p)) - result = PRAGMA_OACC_CLAUSE_COPYOUT; - else if (!strcmp ("copyprivate", p)) - result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; - else if (!strcmp ("create", p)) - result = PRAGMA_OACC_CLAUSE_CREATE; - break; - case 'd': - if (!strcmp ("defaultmap", p)) - result = PRAGMA_OMP_CLAUSE_DEFAULTMAP; - else if (!strcmp ("delete", p)) - result = PRAGMA_OACC_CLAUSE_DELETE; - else if (!strcmp ("depend", p)) - result = PRAGMA_OMP_CLAUSE_DEPEND; - else if (!strcmp ("detach", p)) - result = PRAGMA_OACC_CLAUSE_DETACH; - else if (!strcmp ("device", p)) - result = PRAGMA_OMP_CLAUSE_DEVICE; - else if (!strcmp ("deviceptr", p)) - result = PRAGMA_OACC_CLAUSE_DEVICEPTR; - else if (!strcmp ("device_resident", p)) - result = PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT; - else if (!strcmp ("device_type", p)) - result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE; - else if (!strcmp ("dist_schedule", p)) - result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; - break; - case 'f': - if (!strcmp ("filter", p)) - result = PRAGMA_OMP_CLAUSE_FILTER; - else if (!strcmp ("final", p)) - result = PRAGMA_OMP_CLAUSE_FINAL; - else if (!strcmp ("finalize", p)) - result = PRAGMA_OACC_CLAUSE_FINALIZE; - else if (!strcmp ("firstprivate", p)) - result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; - else if (!strcmp ("from", p)) - result = PRAGMA_OMP_CLAUSE_FROM; - break; - case 'g': - if (!strcmp ("gang", p)) - result = PRAGMA_OACC_CLAUSE_GANG; - else if (!strcmp ("grainsize", p)) - result = PRAGMA_OMP_CLAUSE_GRAINSIZE; - break; - case 'h': - if (!strcmp ("hint", p)) - result = PRAGMA_OMP_CLAUSE_HINT; - else if (!strcmp ("host", p)) - result = PRAGMA_OACC_CLAUSE_HOST; - break; - case 'i': - if (!strcmp ("if_present", p)) - result = PRAGMA_OACC_CLAUSE_IF_PRESENT; - else if (!strcmp ("in_reduction", p)) - result = PRAGMA_OMP_CLAUSE_IN_REDUCTION; - else if (!strcmp ("inbranch", p)) - result = PRAGMA_OMP_CLAUSE_INBRANCH; - else if (!strcmp ("independent", p)) - result = PRAGMA_OACC_CLAUSE_INDEPENDENT; - else if (!strcmp ("is_device_ptr", p)) - result = PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR; - break; - case 'l': - if (!strcmp ("lastprivate", p)) - result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; - else if (!strcmp ("linear", p)) - result = PRAGMA_OMP_CLAUSE_LINEAR; - else if (!strcmp ("link", p)) - result = PRAGMA_OMP_CLAUSE_LINK; - break; - case 'm': - if (!strcmp ("map", p)) - result = PRAGMA_OMP_CLAUSE_MAP; - else if (!strcmp ("mergeable", p)) - result = PRAGMA_OMP_CLAUSE_MERGEABLE; - break; - case 'n': - if (!strcmp ("no_create", p)) - result = PRAGMA_OACC_CLAUSE_NO_CREATE; - else if (!strcmp ("nogroup", p)) - result = PRAGMA_OMP_CLAUSE_NOGROUP; - else if (!strcmp ("nohost", p)) - result = PRAGMA_OACC_CLAUSE_NOHOST; - else if (!strcmp ("nontemporal", p)) - result = PRAGMA_OMP_CLAUSE_NONTEMPORAL; - else if (!strcmp ("notinbranch", p)) - result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; - else if (!strcmp ("nowait", p)) - result = PRAGMA_OMP_CLAUSE_NOWAIT; - else if (!strcmp ("num_gangs", p)) - result = PRAGMA_OACC_CLAUSE_NUM_GANGS; - else if (!strcmp ("num_tasks", p)) - result = PRAGMA_OMP_CLAUSE_NUM_TASKS; - else if (!strcmp ("num_teams", p)) - result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; - else if (!strcmp ("num_threads", p)) - result = PRAGMA_OMP_CLAUSE_NUM_THREADS; - else if (!strcmp ("num_workers", p)) - result = PRAGMA_OACC_CLAUSE_NUM_WORKERS; - break; - case 'o': - if (!strcmp ("ordered", p)) - result = PRAGMA_OMP_CLAUSE_ORDERED; - else if (!strcmp ("order", p)) - result = PRAGMA_OMP_CLAUSE_ORDER; - break; - case 'p': - if (!strcmp ("parallel", p)) - result = PRAGMA_OMP_CLAUSE_PARALLEL; - else if (!strcmp ("present", p)) - result = PRAGMA_OACC_CLAUSE_PRESENT; - /* As of OpenACC 2.5, these are now aliases of the non-present_or - clauses. */ - else if (!strcmp ("present_or_copy", p) - || !strcmp ("pcopy", p)) - result = PRAGMA_OACC_CLAUSE_COPY; - else if (!strcmp ("present_or_copyin", p) - || !strcmp ("pcopyin", p)) - result = PRAGMA_OACC_CLAUSE_COPYIN; - else if (!strcmp ("present_or_copyout", p) - || !strcmp ("pcopyout", p)) - result = PRAGMA_OACC_CLAUSE_COPYOUT; - else if (!strcmp ("present_or_create", p) - || !strcmp ("pcreate", p)) - result = PRAGMA_OACC_CLAUSE_CREATE; - else if (!strcmp ("priority", p)) - result = PRAGMA_OMP_CLAUSE_PRIORITY; - else if (!strcmp ("private", p)) - result = PRAGMA_OMP_CLAUSE_PRIVATE; - else if (!strcmp ("proc_bind", p)) - result = PRAGMA_OMP_CLAUSE_PROC_BIND; - break; - case 'r': - if (!strcmp ("reduction", p)) - result = PRAGMA_OMP_CLAUSE_REDUCTION; - break; - case 's': - if (!strcmp ("safelen", p)) - result = PRAGMA_OMP_CLAUSE_SAFELEN; - else if (!strcmp ("schedule", p)) - result = PRAGMA_OMP_CLAUSE_SCHEDULE; - else if (!strcmp ("sections", p)) - result = PRAGMA_OMP_CLAUSE_SECTIONS; - else if (!strcmp ("self", p)) /* "self" is a synonym for "host". */ - result = PRAGMA_OACC_CLAUSE_HOST; - else if (!strcmp ("seq", p)) - result = PRAGMA_OACC_CLAUSE_SEQ; - else if (!strcmp ("shared", p)) - result = PRAGMA_OMP_CLAUSE_SHARED; - else if (!strcmp ("simd", p)) - result = PRAGMA_OMP_CLAUSE_SIMD; - else if (!strcmp ("simdlen", p)) - result = PRAGMA_OMP_CLAUSE_SIMDLEN; - break; - case 't': - if (!strcmp ("task_reduction", p)) - result = PRAGMA_OMP_CLAUSE_TASK_REDUCTION; - else if (!strcmp ("taskgroup", p)) - result = PRAGMA_OMP_CLAUSE_TASKGROUP; - else if (!strcmp ("thread_limit", p)) - result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; - else if (!strcmp ("threads", p)) - result = PRAGMA_OMP_CLAUSE_THREADS; - else if (!strcmp ("tile", p)) - result = PRAGMA_OACC_CLAUSE_TILE; - else if (!strcmp ("to", p)) - result = PRAGMA_OMP_CLAUSE_TO; - break; - case 'u': - if (!strcmp ("uniform", p)) - result = PRAGMA_OMP_CLAUSE_UNIFORM; - else if (!strcmp ("untied", p)) - result = PRAGMA_OMP_CLAUSE_UNTIED; - else if (!strcmp ("use_device", p)) - result = PRAGMA_OACC_CLAUSE_USE_DEVICE; - else if (!strcmp ("use_device_addr", p)) - result = PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR; - else if (!strcmp ("use_device_ptr", p)) - result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR; - break; - case 'v': - if (!strcmp ("vector", p)) - result = PRAGMA_OACC_CLAUSE_VECTOR; - else if (!strcmp ("vector_length", p)) - result = PRAGMA_OACC_CLAUSE_VECTOR_LENGTH; - break; - case 'w': - if (!strcmp ("wait", p)) - result = PRAGMA_OACC_CLAUSE_WAIT; - else if (!strcmp ("worker", p)) - result = PRAGMA_OACC_CLAUSE_WORKER; - break; - } - } - - if (result != PRAGMA_OMP_CLAUSE_NONE) - c_parser_consume_token (parser); - - return result; -} - -/* Validate that a clause of the given type does not already exist. */ - -static void -check_no_duplicate_clause (tree clauses, enum omp_clause_code code, - const char *name) -{ - if (tree c = omp_find_clause (clauses, code)) - error_at (OMP_CLAUSE_LOCATION (c), "too many %qs clauses", name); -} - -/* OpenACC 2.0 - Parse wait clause or wait directive parameters. */ - -static tree -c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list) -{ - vec *args; - tree t, args_tree; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - args = c_parser_expr_list (parser, false, true, NULL, NULL, NULL, NULL); - args_tree = build_tree_list_vec (args); - - for (t = args_tree; t; t = TREE_CHAIN (t)) - { - tree targ = TREE_VALUE (t); - - if (targ != error_mark_node) - { - if (!INTEGRAL_TYPE_P (TREE_TYPE (targ))) - { - c_parser_error (parser, "expression must be integral"); - targ = error_mark_node; - } - else - { - tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT); - - OMP_CLAUSE_DECL (c) = targ; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - } - } - - release_tree_vector (args); - parens.require_close (parser); - return list; -} - -/* OpenACC 2.0, OpenMP 2.5: - variable-list: - identifier - variable-list , identifier - - If KIND is nonzero, create the appropriate node and install the - decl in OMP_CLAUSE_DECL and add the node to the head of the list. - If KIND is nonzero, CLAUSE_LOC is the location of the clause. - - If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; - return the list created. - - The optional ALLOW_DEREF argument is true if list items can use the deref - (->) operator. */ - -struct omp_dim -{ - tree low_bound, length; - location_t loc; - bool no_colon; - omp_dim (tree lb, tree len, location_t lo, bool nc) - : low_bound (lb), length (len), loc (lo), no_colon (nc) {} -}; - -static tree -c_parser_omp_variable_list (c_parser *parser, - location_t clause_loc, - enum omp_clause_code kind, tree list, - bool allow_deref = false) -{ - auto_vec dims; - bool array_section_p; - auto_vec tokens; - unsigned int tokens_avail = 0; - bool first = true; - - while (1) - { - if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) - { - if (c_parser_next_token_is_not (parser, CPP_NAME) - || c_parser_peek_token (parser)->id_kind != C_ID_ID) - { - struct c_expr expr = c_parser_expr_no_commas (parser, NULL); - if (expr.value != error_mark_node) - { - tree u = build_omp_clause (clause_loc, kind); - OMP_CLAUSE_DECL (u) = expr.value; - OMP_CLAUSE_CHAIN (u) = list; - list = u; - } - - if (c_parser_next_token_is_not (parser, CPP_COMMA)) - break; - - c_parser_consume_token (parser); - first = false; - continue; - } - - tokens.truncate (0); - unsigned int nesting_depth = 0; - while (1) - { - c_token *token = c_parser_peek_token (parser); - switch (token->type) - { - case CPP_EOF: - case CPP_PRAGMA_EOL: - break; - case CPP_OPEN_BRACE: - case CPP_OPEN_PAREN: - case CPP_OPEN_SQUARE: - ++nesting_depth; - goto add; - case CPP_CLOSE_BRACE: - case CPP_CLOSE_PAREN: - case CPP_CLOSE_SQUARE: - if (nesting_depth-- == 0) - break; - goto add; - case CPP_COMMA: - if (nesting_depth == 0) - break; - goto add; - default: - add: - tokens.safe_push (*token); - c_parser_consume_token (parser); - continue; - } - break; - } - - /* Make sure nothing tries to read past the end of the tokens. */ - c_token eof_token; - memset (&eof_token, 0, sizeof (eof_token)); - eof_token.type = CPP_EOF; - tokens.safe_push (eof_token); - tokens.safe_push (eof_token); - - tokens_avail = parser->tokens_avail; - gcc_assert (parser->tokens == &parser->tokens_buf[0]); - parser->tokens = tokens.address (); - parser->tokens_avail = tokens.length (); - } - - tree t = NULL_TREE; - - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_ID) - { - t = lookup_name (c_parser_peek_token (parser)->value); - - if (t == NULL_TREE) - { - undeclared_variable (c_parser_peek_token (parser)->location, - c_parser_peek_token (parser)->value); - t = error_mark_node; - } - - c_parser_consume_token (parser); - } - else if (c_parser_next_token_is (parser, CPP_KEYWORD) - && (c_parser_peek_token (parser)->keyword == RID_FUNCTION_NAME - || (c_parser_peek_token (parser)->keyword - == RID_PRETTY_FUNCTION_NAME) - || (c_parser_peek_token (parser)->keyword - == RID_C99_FUNCTION_NAME))) - t = c_parser_predefined_identifier (parser).value; - else - { - if (first) - c_parser_error (parser, "expected identifier"); - break; - } - - if (t == error_mark_node) - ; - else if (kind != 0) - { - switch (kind) - { - case OMP_CLAUSE__CACHE_: - /* The OpenACC cache directive explicitly only allows "array - elements or subarrays". */ - if (c_parser_peek_token (parser)->type != CPP_OPEN_SQUARE) - { - c_parser_error (parser, "expected %<[%>"); - t = error_mark_node; - break; - } - /* FALLTHROUGH */ - case OMP_CLAUSE_MAP: - case OMP_CLAUSE_FROM: - case OMP_CLAUSE_TO: - start_component_ref: - while (c_parser_next_token_is (parser, CPP_DOT) - || (allow_deref - && c_parser_next_token_is (parser, CPP_DEREF))) - { - location_t op_loc = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_DEREF)) - t = build_simple_mem_ref (t); - c_parser_consume_token (parser); - if (!c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - t = error_mark_node; - break; - } - - c_token *comp_tok = c_parser_peek_token (parser); - tree ident = comp_tok->value; - location_t comp_loc = comp_tok->location; - c_parser_consume_token (parser); - t = build_component_ref (op_loc, t, ident, comp_loc); - } - /* FALLTHROUGH */ - case OMP_CLAUSE_AFFINITY: - case OMP_CLAUSE_DEPEND: - case OMP_CLAUSE_REDUCTION: - case OMP_CLAUSE_IN_REDUCTION: - case OMP_CLAUSE_TASK_REDUCTION: - array_section_p = false; - dims.truncate (0); - while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) - { - location_t loc = UNKNOWN_LOCATION; - tree low_bound = NULL_TREE, length = NULL_TREE; - bool no_colon = false; - - c_parser_consume_token (parser); - if (!c_parser_next_token_is (parser, CPP_COLON)) - { - location_t expr_loc - = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expression (parser); - expr = convert_lvalue_to_rvalue (expr_loc, expr, - false, true); - low_bound = expr.value; - loc = expr_loc; - } - if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) - { - length = integer_one_node; - no_colon = true; - } - else - { - /* Look for `:'. */ - if (!c_parser_require (parser, CPP_COLON, - "expected %<:%>")) - { - t = error_mark_node; - break; - } - array_section_p = true; - if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) - { - location_t expr_loc - = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expression (parser); - expr = convert_lvalue_to_rvalue (expr_loc, expr, - false, true); - length = expr.value; - } - } - /* Look for the closing `]'. */ - if (!c_parser_require (parser, CPP_CLOSE_SQUARE, - "expected %<]%>")) - { - t = error_mark_node; - break; - } - - dims.safe_push (omp_dim (low_bound, length, loc, no_colon)); - } - - if (t != error_mark_node) - { - if ((kind == OMP_CLAUSE_MAP - || kind == OMP_CLAUSE_FROM - || kind == OMP_CLAUSE_TO) - && !array_section_p - && (c_parser_next_token_is (parser, CPP_DOT) - || (allow_deref - && c_parser_next_token_is (parser, - CPP_DEREF)))) - { - for (unsigned i = 0; i < dims.length (); i++) - { - gcc_assert (dims[i].length == integer_one_node); - t = build_array_ref (dims[i].loc, - t, dims[i].low_bound); - } - goto start_component_ref; - } - else - for (unsigned i = 0; i < dims.length (); i++) - t = tree_cons (dims[i].low_bound, dims[i].length, t); - } - - if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) - && t != error_mark_node - && parser->tokens_avail != 2) - { - if (array_section_p) - { - error_at (c_parser_peek_token (parser)->location, - "expected %<)%> or %<,%>"); - t = error_mark_node; - } - else - { - parser->tokens = tokens.address (); - parser->tokens_avail = tokens.length (); - - t = c_parser_expr_no_commas (parser, NULL).value; - if (t != error_mark_node && parser->tokens_avail != 2) - { - error_at (c_parser_peek_token (parser)->location, - "expected %<)%> or %<,%>"); - t = error_mark_node; - } - } - } - break; - default: - break; - } - - if (t != error_mark_node) - { - tree u = build_omp_clause (clause_loc, kind); - OMP_CLAUSE_DECL (u) = t; - OMP_CLAUSE_CHAIN (u) = list; - list = u; - } - } - else - list = tree_cons (t, NULL_TREE, list); - - if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) - { - parser->tokens = &parser->tokens_buf[0]; - parser->tokens_avail = tokens_avail; - } - if (c_parser_next_token_is_not (parser, CPP_COMMA)) - break; - - c_parser_consume_token (parser); - first = false; - } - - return list; -} - -/* Similarly, but expect leading and trailing parenthesis. This is a very - common case for OpenACC and OpenMP clauses. The optional ALLOW_DEREF - argument is true if list items can use the deref (->) operator. */ - -static tree -c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, - tree list, bool allow_deref = false) -{ - /* The clauses location. */ - location_t loc = c_parser_peek_token (parser)->location; - - matching_parens parens; - if (parens.require_open (parser)) - { - list = c_parser_omp_variable_list (parser, loc, kind, list, allow_deref); - parens.skip_until_found_close (parser); - } - return list; -} - -/* OpenACC 2.0: - copy ( variable-list ) - copyin ( variable-list ) - copyout ( variable-list ) - create ( variable-list ) - delete ( variable-list ) - present ( variable-list ) - - OpenACC 2.6: - no_create ( variable-list ) - attach ( variable-list ) - detach ( variable-list ) */ - -static tree -c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind, - tree list) -{ - enum gomp_map_kind kind; - switch (c_kind) - { - case PRAGMA_OACC_CLAUSE_ATTACH: - kind = GOMP_MAP_ATTACH; - break; - case PRAGMA_OACC_CLAUSE_COPY: - kind = GOMP_MAP_TOFROM; - break; - case PRAGMA_OACC_CLAUSE_COPYIN: - kind = GOMP_MAP_TO; - break; - case PRAGMA_OACC_CLAUSE_COPYOUT: - kind = GOMP_MAP_FROM; - break; - case PRAGMA_OACC_CLAUSE_CREATE: - kind = GOMP_MAP_ALLOC; - break; - case PRAGMA_OACC_CLAUSE_DELETE: - kind = GOMP_MAP_RELEASE; - break; - case PRAGMA_OACC_CLAUSE_DETACH: - kind = GOMP_MAP_DETACH; - break; - case PRAGMA_OACC_CLAUSE_DEVICE: - kind = GOMP_MAP_FORCE_TO; - break; - case PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT: - kind = GOMP_MAP_DEVICE_RESIDENT; - break; - case PRAGMA_OACC_CLAUSE_HOST: - kind = GOMP_MAP_FORCE_FROM; - break; - case PRAGMA_OACC_CLAUSE_LINK: - kind = GOMP_MAP_LINK; - break; - case PRAGMA_OACC_CLAUSE_NO_CREATE: - kind = GOMP_MAP_IF_PRESENT; - break; - case PRAGMA_OACC_CLAUSE_PRESENT: - kind = GOMP_MAP_FORCE_PRESENT; - break; - default: - gcc_unreachable (); - } - tree nl, c; - nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list, true); - - for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_SET_MAP_KIND (c, kind); - - return nl; -} - -/* OpenACC 2.0: - deviceptr ( variable-list ) */ - -static tree -c_parser_oacc_data_clause_deviceptr (c_parser *parser, tree list) -{ - location_t loc = c_parser_peek_token (parser)->location; - tree vars, t; - - /* Can't use OMP_CLAUSE_MAP here (that is, can't use the generic - c_parser_oacc_data_clause), as for PRAGMA_OACC_CLAUSE_DEVICEPTR, - variable-list must only allow for pointer variables. */ - vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); - for (t = vars; t && t; t = TREE_CHAIN (t)) - { - tree v = TREE_PURPOSE (t); - - /* FIXME diagnostics: Ideally we should keep individual - locations for all the variables in the var list to make the - following errors more precise. Perhaps - c_parser_omp_var_list_parens() should construct a list of - locations to go along with the var list. */ - - if (!VAR_P (v) && TREE_CODE (v) != PARM_DECL) - error_at (loc, "%qD is not a variable", v); - else if (TREE_TYPE (v) == error_mark_node) - ; - else if (!POINTER_TYPE_P (TREE_TYPE (v))) - error_at (loc, "%qD is not a pointer variable", v); - - tree u = build_omp_clause (loc, OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (u, GOMP_MAP_FORCE_DEVICEPTR); - OMP_CLAUSE_DECL (u) = v; - OMP_CLAUSE_CHAIN (u) = list; - list = u; - } - - return list; -} - -/* OpenACC 2.0, OpenMP 3.0: - collapse ( constant-expression ) */ - -static tree -c_parser_omp_clause_collapse (c_parser *parser, tree list) -{ - tree c, num = error_mark_node; - HOST_WIDE_INT n; - location_t loc; - - check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse"); - check_no_duplicate_clause (list, OMP_CLAUSE_TILE, "tile"); - - loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - num = c_parser_expr_no_commas (parser, NULL).value; - parens.skip_until_found_close (parser); - } - if (num == error_mark_node) - return list; - mark_exp_read (num); - num = c_fully_fold (num, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) - || !tree_fits_shwi_p (num) - || (n = tree_to_shwi (num)) <= 0 - || (int) n != n) - { - error_at (loc, - "collapse argument needs positive constant integer expression"); - return list; - } - c = build_omp_clause (loc, OMP_CLAUSE_COLLAPSE); - OMP_CLAUSE_COLLAPSE_EXPR (c) = num; - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenMP 2.5: - copyin ( variable-list ) */ - -static tree -c_parser_omp_clause_copyin (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list); -} - -/* OpenMP 2.5: - copyprivate ( variable-list ) */ - -static tree -c_parser_omp_clause_copyprivate (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list); -} - -/* OpenMP 2.5: - default ( none | shared ) - - OpenMP 5.1: - default ( private | firstprivate ) - - OpenACC: - default ( none | present ) */ - -static tree -c_parser_omp_clause_default (c_parser *parser, tree list, bool is_oacc) -{ - enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; - location_t loc = c_parser_peek_token (parser)->location; - tree c; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - switch (p[0]) - { - case 'n': - if (strcmp ("none", p) != 0) - goto invalid_kind; - kind = OMP_CLAUSE_DEFAULT_NONE; - break; - - case 'p': - if (is_oacc) - { - if (strcmp ("present", p) != 0) - goto invalid_kind; - kind = OMP_CLAUSE_DEFAULT_PRESENT; - } - else - { - if (strcmp ("private", p) != 0) - goto invalid_kind; - kind = OMP_CLAUSE_DEFAULT_PRIVATE; - } - break; - - case 'f': - if (strcmp ("firstprivate", p) != 0 || is_oacc) - goto invalid_kind; - kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; - break; - - case 's': - if (strcmp ("shared", p) != 0 || is_oacc) - goto invalid_kind; - kind = OMP_CLAUSE_DEFAULT_SHARED; - break; - - default: - goto invalid_kind; - } - - c_parser_consume_token (parser); - } - else - { - invalid_kind: - if (is_oacc) - c_parser_error (parser, "expected % or %"); - else - c_parser_error (parser, "expected %, %, " - "% or %"); - } - parens.skip_until_found_close (parser); - - if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) - return list; - - check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default"); - c = build_omp_clause (loc, OMP_CLAUSE_DEFAULT); - OMP_CLAUSE_CHAIN (c) = list; - OMP_CLAUSE_DEFAULT_KIND (c) = kind; - - return c; -} - -/* OpenMP 2.5: - firstprivate ( variable-list ) */ - -static tree -c_parser_omp_clause_firstprivate (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list); -} - -/* OpenMP 3.1: - final ( expression ) */ - -static tree -c_parser_omp_clause_final (c_parser *parser, tree list) -{ - location_t loc = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - matching_parens parens; - tree t, c; - if (!parens.require_open (parser)) - t = error_mark_node; - else - { - location_t eloc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - t = convert_lvalue_to_rvalue (eloc, expr, true, true).value; - t = c_objc_common_truthvalue_conversion (eloc, t); - t = c_fully_fold (t, false, NULL); - parens.skip_until_found_close (parser); - } - - check_no_duplicate_clause (list, OMP_CLAUSE_FINAL, "final"); - - c = build_omp_clause (loc, OMP_CLAUSE_FINAL); - OMP_CLAUSE_FINAL_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - else - c_parser_error (parser, "expected %<(%>"); - - return list; -} - -/* OpenACC, OpenMP 2.5: - if ( expression ) - - OpenMP 4.5: - if ( directive-name-modifier : expression ) - - directive-name-modifier: - parallel | task | taskloop | target data | target | target update - | target enter data | target exit data - - OpenMP 5.0: - directive-name-modifier: - ... | simd | cancel */ - -static tree -c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) -{ - location_t location = c_parser_peek_token (parser)->location; - enum tree_code if_modifier = ERROR_MARK; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - if (is_omp && c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - int n = 2; - if (strcmp (p, "cancel") == 0) - if_modifier = VOID_CST; - else if (strcmp (p, "parallel") == 0) - if_modifier = OMP_PARALLEL; - else if (strcmp (p, "simd") == 0) - if_modifier = OMP_SIMD; - else if (strcmp (p, "task") == 0) - if_modifier = OMP_TASK; - else if (strcmp (p, "taskloop") == 0) - if_modifier = OMP_TASKLOOP; - else if (strcmp (p, "target") == 0) - { - if_modifier = OMP_TARGET; - if (c_parser_peek_2nd_token (parser)->type == CPP_NAME) - { - p = IDENTIFIER_POINTER (c_parser_peek_2nd_token (parser)->value); - if (strcmp ("data", p) == 0) - if_modifier = OMP_TARGET_DATA; - else if (strcmp ("update", p) == 0) - if_modifier = OMP_TARGET_UPDATE; - else if (strcmp ("enter", p) == 0) - if_modifier = OMP_TARGET_ENTER_DATA; - else if (strcmp ("exit", p) == 0) - if_modifier = OMP_TARGET_EXIT_DATA; - if (if_modifier != OMP_TARGET) - { - n = 3; - c_parser_consume_token (parser); - } - else - { - location_t loc = c_parser_peek_2nd_token (parser)->location; - error_at (loc, "expected %, %, % " - "or %"); - if_modifier = ERROR_MARK; - } - if (if_modifier == OMP_TARGET_ENTER_DATA - || if_modifier == OMP_TARGET_EXIT_DATA) - { - if (c_parser_peek_2nd_token (parser)->type == CPP_NAME) - { - p = IDENTIFIER_POINTER - (c_parser_peek_2nd_token (parser)->value); - if (strcmp ("data", p) == 0) - n = 4; - } - if (n == 4) - c_parser_consume_token (parser); - else - { - location_t loc - = c_parser_peek_2nd_token (parser)->location; - error_at (loc, "expected %"); - if_modifier = ERROR_MARK; - } - } - } - } - if (if_modifier != ERROR_MARK) - { - if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) - { - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - else - { - if (n > 2) - { - location_t loc = c_parser_peek_2nd_token (parser)->location; - error_at (loc, "expected %<:%>"); - } - if_modifier = ERROR_MARK; - } - } - } - - location_t loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (loc, expr, true, true); - tree t = c_objc_common_truthvalue_conversion (loc, expr.value), c; - t = c_fully_fold (t, false, NULL); - parens.skip_until_found_close (parser); - - for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IF) - { - if (if_modifier != ERROR_MARK - && OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) - { - const char *p = NULL; - switch (if_modifier) - { - case VOID_CST: p = "cancel"; break; - case OMP_PARALLEL: p = "parallel"; break; - case OMP_SIMD: p = "simd"; break; - case OMP_TASK: p = "task"; break; - case OMP_TASKLOOP: p = "taskloop"; break; - case OMP_TARGET_DATA: p = "target data"; break; - case OMP_TARGET: p = "target"; break; - case OMP_TARGET_UPDATE: p = "target update"; break; - case OMP_TARGET_ENTER_DATA: p = "target enter data"; break; - case OMP_TARGET_EXIT_DATA: p = "target exit data"; break; - default: gcc_unreachable (); - } - error_at (location, "too many % clauses with %qs modifier", - p); - return list; - } - else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) - { - if (!is_omp) - error_at (location, "too many % clauses"); - else - error_at (location, "too many % clauses without modifier"); - return list; - } - else if (if_modifier == ERROR_MARK - || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK) - { - error_at (location, "if any % clause has modifier, then all " - "% clauses have to use modifier"); - return list; - } - } - - c = build_omp_clause (location, OMP_CLAUSE_IF); - OMP_CLAUSE_IF_MODIFIER (c) = if_modifier; - OMP_CLAUSE_IF_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenMP 2.5: - lastprivate ( variable-list ) - - OpenMP 5.0: - lastprivate ( [ lastprivate-modifier : ] variable-list ) */ - -static tree -c_parser_omp_clause_lastprivate (c_parser *parser, tree list) -{ - /* The clauses location. */ - location_t loc = c_parser_peek_token (parser)->location; - - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - bool conditional = false; - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) - { - const char *p - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "conditional") == 0) - { - conditional = true; - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - } - tree nlist = c_parser_omp_variable_list (parser, loc, - OMP_CLAUSE_LASTPRIVATE, list); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - if (conditional) - for (tree c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 1; - return nlist; - } - return list; -} - -/* OpenMP 3.1: - mergeable */ - -static tree -c_parser_omp_clause_mergeable (c_parser *parser ATTRIBUTE_UNUSED, tree list) -{ - tree c; - - /* FIXME: Should we allow duplicates? */ - check_no_duplicate_clause (list, OMP_CLAUSE_MERGEABLE, "mergeable"); - - c = build_omp_clause (c_parser_peek_token (parser)->location, - OMP_CLAUSE_MERGEABLE); - OMP_CLAUSE_CHAIN (c) = list; - - return c; -} - -/* OpenMP 2.5: - nowait */ - -static tree -c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) -{ - tree c; - location_t loc = c_parser_peek_token (parser)->location; - - check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait"); - - c = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenMP 2.5: - num_threads ( expression ) */ - -static tree -c_parser_omp_clause_num_threads (c_parser *parser, tree list) -{ - location_t num_threads_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - tree c, t = expr.value; - t = c_fully_fold (t, false, NULL); - - parens.skip_until_found_close (parser); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - { - c_parser_error (parser, "expected integer expression"); - return list; - } - - /* Attempt to statically determine when the number isn't positive. */ - c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, - build_int_cst (TREE_TYPE (t), 0)); - protected_set_expr_location (c, expr_loc); - if (c == boolean_true_node) - { - warning_at (expr_loc, 0, - "% value must be positive"); - t = integer_one_node; - } - - check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads"); - - c = build_omp_clause (num_threads_loc, OMP_CLAUSE_NUM_THREADS); - OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - - return list; -} - -/* OpenMP 4.5: - num_tasks ( expression ) - - OpenMP 5.1: - num_tasks ( strict : expression ) */ - -static tree -c_parser_omp_clause_num_tasks (c_parser *parser, tree list) -{ - location_t num_tasks_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - bool strict = false; - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COLON - && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), - "strict") == 0) - { - strict = true; - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - tree c, t = expr.value; - t = c_fully_fold (t, false, NULL); - - parens.skip_until_found_close (parser); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - { - c_parser_error (parser, "expected integer expression"); - return list; - } - - /* Attempt to statically determine when the number isn't positive. */ - c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, - build_int_cst (TREE_TYPE (t), 0)); - if (CAN_HAVE_LOCATION_P (c)) - SET_EXPR_LOCATION (c, expr_loc); - if (c == boolean_true_node) - { - warning_at (expr_loc, 0, "% value must be positive"); - t = integer_one_node; - } - - check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TASKS, "num_tasks"); - - c = build_omp_clause (num_tasks_loc, OMP_CLAUSE_NUM_TASKS); - OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; - OMP_CLAUSE_NUM_TASKS_STRICT (c) = strict; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - - return list; -} - -/* OpenMP 4.5: - grainsize ( expression ) - - OpenMP 5.1: - grainsize ( strict : expression ) */ - -static tree -c_parser_omp_clause_grainsize (c_parser *parser, tree list) -{ - location_t grainsize_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - bool strict = false; - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COLON - && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), - "strict") == 0) - { - strict = true; - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - tree c, t = expr.value; - t = c_fully_fold (t, false, NULL); - - parens.skip_until_found_close (parser); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - { - c_parser_error (parser, "expected integer expression"); - return list; - } - - /* Attempt to statically determine when the number isn't positive. */ - c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, - build_int_cst (TREE_TYPE (t), 0)); - if (CAN_HAVE_LOCATION_P (c)) - SET_EXPR_LOCATION (c, expr_loc); - if (c == boolean_true_node) - { - warning_at (expr_loc, 0, "% value must be positive"); - t = integer_one_node; - } - - check_no_duplicate_clause (list, OMP_CLAUSE_GRAINSIZE, "grainsize"); - - c = build_omp_clause (grainsize_loc, OMP_CLAUSE_GRAINSIZE); - OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; - OMP_CLAUSE_GRAINSIZE_STRICT (c) = strict; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - - return list; -} - -/* OpenMP 4.5: - priority ( expression ) */ - -static tree -c_parser_omp_clause_priority (c_parser *parser, tree list) -{ - location_t priority_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - tree c, t = expr.value; - t = c_fully_fold (t, false, NULL); - - parens.skip_until_found_close (parser); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - { - c_parser_error (parser, "expected integer expression"); - return list; - } - - /* Attempt to statically determine when the number isn't - non-negative. */ - c = fold_build2_loc (expr_loc, LT_EXPR, boolean_type_node, t, - build_int_cst (TREE_TYPE (t), 0)); - if (CAN_HAVE_LOCATION_P (c)) - SET_EXPR_LOCATION (c, expr_loc); - if (c == boolean_true_node) - { - warning_at (expr_loc, 0, "% value must be non-negative"); - t = integer_one_node; - } - - check_no_duplicate_clause (list, OMP_CLAUSE_PRIORITY, "priority"); - - c = build_omp_clause (priority_loc, OMP_CLAUSE_PRIORITY); - OMP_CLAUSE_PRIORITY_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - - return list; -} - -/* OpenMP 4.5: - hint ( expression ) */ - -static tree -c_parser_omp_clause_hint (c_parser *parser, tree list) -{ - location_t hint_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - tree c, t = expr.value; - t = c_fully_fold (t, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) - || TREE_CODE (t) != INTEGER_CST - || tree_int_cst_sgn (t) == -1) - { - c_parser_error (parser, "expected constant integer expression " - "with valid sync-hint value"); - return list; - } - parens.skip_until_found_close (parser); - check_no_duplicate_clause (list, OMP_CLAUSE_HINT, "hint"); - - c = build_omp_clause (hint_loc, OMP_CLAUSE_HINT); - OMP_CLAUSE_HINT_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - - return list; -} - -/* OpenMP 5.1: - filter ( integer-expression ) */ - -static tree -c_parser_omp_clause_filter (c_parser *parser, tree list) -{ - location_t hint_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - tree c, t = expr.value; - t = c_fully_fold (t, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - { - c_parser_error (parser, "expected integer expression"); - return list; - } - parens.skip_until_found_close (parser); - check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter"); - - c = build_omp_clause (hint_loc, OMP_CLAUSE_FILTER); - OMP_CLAUSE_FILTER_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - - return list; -} - -/* OpenMP 4.5: - defaultmap ( tofrom : scalar ) - - OpenMP 5.0: - defaultmap ( implicit-behavior [ : variable-category ] ) */ - -static tree -c_parser_omp_clause_defaultmap (c_parser *parser, tree list) -{ - location_t loc = c_parser_peek_token (parser)->location; - tree c; - const char *p; - enum omp_clause_defaultmap_kind behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; - enum omp_clause_defaultmap_kind category - = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) - p = "default"; - else if (!c_parser_next_token_is (parser, CPP_NAME)) - { - invalid_behavior: - c_parser_error (parser, "expected %, %, %, " - "%, %, % " - "or %"); - goto out_err; - } - else - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - switch (p[0]) - { - case 'a': - if (strcmp ("alloc", p) == 0) - behavior = OMP_CLAUSE_DEFAULTMAP_ALLOC; - else - goto invalid_behavior; - break; - - case 'd': - if (strcmp ("default", p) == 0) - behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; - else - goto invalid_behavior; - break; - - case 'f': - if (strcmp ("firstprivate", p) == 0) - behavior = OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE; - else if (strcmp ("from", p) == 0) - behavior = OMP_CLAUSE_DEFAULTMAP_FROM; - else - goto invalid_behavior; - break; - - case 'n': - if (strcmp ("none", p) == 0) - behavior = OMP_CLAUSE_DEFAULTMAP_NONE; - else - goto invalid_behavior; - break; - - case 't': - if (strcmp ("tofrom", p) == 0) - behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM; - else if (strcmp ("to", p) == 0) - behavior = OMP_CLAUSE_DEFAULTMAP_TO; - else - goto invalid_behavior; - break; - - default: - goto invalid_behavior; - } - c_parser_consume_token (parser); - - if (!c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - goto out_err; - if (!c_parser_next_token_is (parser, CPP_NAME)) - { - invalid_category: - c_parser_error (parser, "expected %, % or " - "%"); - goto out_err; - } - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - switch (p[0]) - { - case 'a': - if (strcmp ("aggregate", p) == 0) - category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE; - else - goto invalid_category; - break; - - case 'p': - if (strcmp ("pointer", p) == 0) - category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER; - else - goto invalid_category; - break; - - case 's': - if (strcmp ("scalar", p) == 0) - category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR; - else - goto invalid_category; - break; - - default: - goto invalid_category; - } - - c_parser_consume_token (parser); - } - parens.skip_until_found_close (parser); - - for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP - && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED - || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category - || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) - == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) - { - enum omp_clause_defaultmap_kind cat = category; - location_t loc = OMP_CLAUSE_LOCATION (c); - if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) - cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c); - p = NULL; - switch (cat) - { - case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: - p = NULL; - break; - case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: - p = "aggregate"; - break; - case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER: - p = "pointer"; - break; - case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: - p = "scalar"; - break; - default: - gcc_unreachable (); - } - if (p) - error_at (loc, "too many % clauses with %qs category", - p); - else - error_at (loc, "too many % clauses with unspecified " - "category"); - break; - } - - c = build_omp_clause (loc, OMP_CLAUSE_DEFAULTMAP); - OMP_CLAUSE_DEFAULTMAP_SET_KIND (c, behavior, category); - OMP_CLAUSE_CHAIN (c) = list; - return c; - - out_err: - parens.skip_until_found_close (parser); - return list; -} - -/* OpenACC 2.0: - use_device ( variable-list ) - - OpenMP 4.5: - use_device_ptr ( variable-list ) */ - -static tree -c_parser_omp_clause_use_device_ptr (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_USE_DEVICE_PTR, - list); -} - -/* OpenMP 5.0: - use_device_addr ( variable-list ) */ - -static tree -c_parser_omp_clause_use_device_addr (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_USE_DEVICE_ADDR, - list); -} - -/* OpenMP 4.5: - is_device_ptr ( variable-list ) */ - -static tree -c_parser_omp_clause_is_device_ptr (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_IS_DEVICE_PTR, list); -} - -/* OpenACC: - num_gangs ( expression ) - num_workers ( expression ) - vector_length ( expression ) */ - -static tree -c_parser_oacc_single_int_clause (c_parser *parser, omp_clause_code code, - tree list) -{ - location_t loc = c_parser_peek_token (parser)->location; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expression (parser); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - tree c, t = expr.value; - t = c_fully_fold (t, false, NULL); - - parens.skip_until_found_close (parser); - - if (t == error_mark_node) - return list; - else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - { - error_at (expr_loc, "%qs expression must be integral", - omp_clause_code_name[code]); - return list; - } - - /* Attempt to statically determine when the number isn't positive. */ - c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, - build_int_cst (TREE_TYPE (t), 0)); - protected_set_expr_location (c, expr_loc); - if (c == boolean_true_node) - { - warning_at (expr_loc, 0, - "%qs value must be positive", - omp_clause_code_name[code]); - t = integer_one_node; - } - - check_no_duplicate_clause (list, code, omp_clause_code_name[code]); - - c = build_omp_clause (loc, code); - OMP_CLAUSE_OPERAND (c, 0) = t; - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenACC: - - gang [( gang-arg-list )] - worker [( [num:] int-expr )] - vector [( [length:] int-expr )] - - where gang-arg is one of: - - [num:] int-expr - static: size-expr - - and size-expr may be: - - * - int-expr -*/ - -static tree -c_parser_oacc_shape_clause (c_parser *parser, location_t loc, - omp_clause_code kind, - const char *str, tree list) -{ - const char *id = "num"; - tree ops[2] = { NULL_TREE, NULL_TREE }, c; - - if (kind == OMP_CLAUSE_VECTOR) - id = "length"; - - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - c_parser_consume_token (parser); - - do - { - c_token *next = c_parser_peek_token (parser); - int idx = 0; - - /* Gang static argument. */ - if (kind == OMP_CLAUSE_GANG - && c_parser_next_token_is_keyword (parser, RID_STATIC)) - { - c_parser_consume_token (parser); - - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - goto cleanup_error; - - idx = 1; - if (ops[idx] != NULL_TREE) - { - c_parser_error (parser, "too many % arguments"); - goto cleanup_error; - } - - /* Check for the '*' argument. */ - if (c_parser_next_token_is (parser, CPP_MULT) - && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA - || c_parser_peek_2nd_token (parser)->type - == CPP_CLOSE_PAREN)) - { - c_parser_consume_token (parser); - ops[idx] = integer_minus_one_node; - - if (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - continue; - } - else - break; - } - } - /* Worker num: argument and vector length: arguments. */ - else if (c_parser_next_token_is (parser, CPP_NAME) - && strcmp (id, IDENTIFIER_POINTER (next->value)) == 0 - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) - { - c_parser_consume_token (parser); /* id */ - c_parser_consume_token (parser); /* ':' */ - } - - /* Now collect the actual argument. */ - if (ops[idx] != NULL_TREE) - { - c_parser_error (parser, "unexpected argument"); - goto cleanup_error; - } - - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr cexpr = c_parser_expr_no_commas (parser, NULL); - cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true); - tree expr = cexpr.value; - if (expr == error_mark_node) - goto cleanup_error; - - expr = c_fully_fold (expr, false, NULL); - - /* Attempt to statically determine when the number isn't a - positive integer. */ - - if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))) - { - c_parser_error (parser, "expected integer expression"); - return list; - } - - tree c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, expr, - build_int_cst (TREE_TYPE (expr), 0)); - if (c == boolean_true_node) - { - warning_at (loc, 0, - "%qs value must be positive", str); - expr = integer_one_node; - } - - ops[idx] = expr; - - if (kind == OMP_CLAUSE_GANG - && c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - continue; - } - break; - } - while (1); - - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - goto cleanup_error; - } - - check_no_duplicate_clause (list, kind, str); - - c = build_omp_clause (loc, kind); - - if (ops[1]) - OMP_CLAUSE_OPERAND (c, 1) = ops[1]; - - OMP_CLAUSE_OPERAND (c, 0) = ops[0]; - OMP_CLAUSE_CHAIN (c) = list; - - return c; - - cleanup_error: - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); - return list; -} - -/* OpenACC 2.5: - auto - finalize - independent - nohost - seq */ - -static tree -c_parser_oacc_simple_clause (location_t loc, enum omp_clause_code code, - tree list) -{ - check_no_duplicate_clause (list, code, omp_clause_code_name[code]); - - tree c = build_omp_clause (loc, code); - OMP_CLAUSE_CHAIN (c) = list; - - return c; -} - -/* OpenACC: - async [( int-expr )] */ - -static tree -c_parser_oacc_clause_async (c_parser *parser, tree list) -{ - tree c, t; - location_t loc = c_parser_peek_token (parser)->location; - - t = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL); - - if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) - { - c_parser_consume_token (parser); - - t = c_parser_expr_no_commas (parser, NULL).value; - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - c_parser_error (parser, "expected integer expression"); - else if (t == error_mark_node - || !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - return list; - } - else - t = c_fully_fold (t, false, NULL); - - check_no_duplicate_clause (list, OMP_CLAUSE_ASYNC, "async"); - - c = build_omp_clause (loc, OMP_CLAUSE_ASYNC); - OMP_CLAUSE_ASYNC_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - - return list; -} - -/* OpenACC 2.0: - tile ( size-expr-list ) */ - -static tree -c_parser_oacc_clause_tile (c_parser *parser, tree list) -{ - tree c, expr = error_mark_node; - location_t loc; - tree tile = NULL_TREE; - - check_no_duplicate_clause (list, OMP_CLAUSE_TILE, "tile"); - check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse"); - - loc = c_parser_peek_token (parser)->location; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return list; - - do - { - if (tile && !c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - return list; - - if (c_parser_next_token_is (parser, CPP_MULT) - && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA - || c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN)) - { - c_parser_consume_token (parser); - expr = integer_zero_node; - } - else - { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr cexpr = c_parser_expr_no_commas (parser, NULL); - cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true); - expr = cexpr.value; - - if (expr == error_mark_node) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return list; - } - - expr = c_fully_fold (expr, false, NULL); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) - || !tree_fits_shwi_p (expr) - || tree_to_shwi (expr) <= 0) - { - error_at (expr_loc, "% argument needs positive" - " integral constant"); - expr = integer_zero_node; - } - } - - tile = tree_cons (NULL_TREE, expr, tile); - } - while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)); - - /* Consume the trailing ')'. */ - c_parser_consume_token (parser); - - c = build_omp_clause (loc, OMP_CLAUSE_TILE); - tile = nreverse (tile); - OMP_CLAUSE_TILE_LIST (c) = tile; - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenACC: - wait [( int-expr-list )] */ - -static tree -c_parser_oacc_clause_wait (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - - if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) - list = c_parser_oacc_wait_list (parser, clause_loc, list); - else - { - tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT); - - OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL); - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - - return list; -} - - -/* OpenMP 5.0: - order ( concurrent ) - - OpenMP 5.1: - order ( order-modifier : concurrent ) - - order-modifier: - reproducible - unconstrained */ - -static tree -c_parser_omp_clause_order (c_parser *parser, tree list) -{ - location_t loc = c_parser_peek_token (parser)->location; - tree c; - const char *p; - bool unconstrained = false; - bool reproducible = false; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) - { - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "unconstrained") == 0) - unconstrained = true; - else if (strcmp (p, "reproducible") == 0) - reproducible = true; - else - { - c_parser_error (parser, "expected % or " - "%"); - goto out_err; - } - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - if (!c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected %"); - goto out_err; - } - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "concurrent") != 0) - { - c_parser_error (parser, "expected %"); - goto out_err; - } - c_parser_consume_token (parser); - parens.skip_until_found_close (parser); - check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order"); - c = build_omp_clause (loc, OMP_CLAUSE_ORDER); - OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = unconstrained; - OMP_CLAUSE_ORDER_REPRODUCIBLE (c) = reproducible; - OMP_CLAUSE_CHAIN (c) = list; - return c; - - out_err: - parens.skip_until_found_close (parser); - return list; -} - - -/* OpenMP 5.0: - bind ( teams | parallel | thread ) */ - -static tree -c_parser_omp_clause_bind (c_parser *parser, tree list) -{ - location_t loc = c_parser_peek_token (parser)->location; - tree c; - const char *p; - enum omp_clause_bind_kind kind = OMP_CLAUSE_BIND_THREAD; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - if (!c_parser_next_token_is (parser, CPP_NAME)) - { - invalid: - c_parser_error (parser, - "expected %, % or %"); - parens.skip_until_found_close (parser); - return list; - } - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "teams") == 0) - kind = OMP_CLAUSE_BIND_TEAMS; - else if (strcmp (p, "parallel") == 0) - kind = OMP_CLAUSE_BIND_PARALLEL; - else if (strcmp (p, "thread") != 0) - goto invalid; - c_parser_consume_token (parser); - parens.skip_until_found_close (parser); - /* check_no_duplicate_clause (list, OMP_CLAUSE_BIND, "bind"); */ - c = build_omp_clause (loc, OMP_CLAUSE_BIND); - OMP_CLAUSE_BIND_KIND (c) = kind; - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - - -/* OpenMP 2.5: - ordered - - OpenMP 4.5: - ordered ( constant-expression ) */ - -static tree -c_parser_omp_clause_ordered (c_parser *parser, tree list) -{ - check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered"); - - tree c, num = NULL_TREE; - HOST_WIDE_INT n; - location_t loc = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - matching_parens parens; - parens.consume_open (parser); - num = c_parser_expr_no_commas (parser, NULL).value; - parens.skip_until_found_close (parser); - } - if (num == error_mark_node) - return list; - if (num) - { - mark_exp_read (num); - num = c_fully_fold (num, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) - || !tree_fits_shwi_p (num) - || (n = tree_to_shwi (num)) <= 0 - || (int) n != n) - { - error_at (loc, "ordered argument needs positive " - "constant integer expression"); - return list; - } - } - c = build_omp_clause (loc, OMP_CLAUSE_ORDERED); - OMP_CLAUSE_ORDERED_EXPR (c) = num; - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenMP 2.5: - private ( variable-list ) */ - -static tree -c_parser_omp_clause_private (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list); -} - -/* OpenMP 2.5: - reduction ( reduction-operator : variable-list ) - - reduction-operator: - One of: + * - & ^ | && || - - OpenMP 3.1: - - reduction-operator: - One of: + * - & ^ | && || max min - - OpenMP 4.0: - - reduction-operator: - One of: + * - & ^ | && || - identifier - - OpenMP 5.0: - reduction ( reduction-modifier, reduction-operator : variable-list ) - in_reduction ( reduction-operator : variable-list ) - task_reduction ( reduction-operator : variable-list ) */ - -static tree -c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind, - bool is_omp, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - bool task = false; - bool inscan = false; - enum tree_code code = ERROR_MARK; - tree reduc_id = NULL_TREE; - - if (kind == OMP_CLAUSE_REDUCTION && is_omp) - { - if (c_parser_next_token_is_keyword (parser, RID_DEFAULT) - && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) - { - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - else if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) - { - const char *p - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "task") == 0) - task = true; - else if (strcmp (p, "inscan") == 0) - inscan = true; - if (task || inscan) - { - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - } - } - - switch (c_parser_peek_token (parser)->type) - { - case CPP_PLUS: - code = PLUS_EXPR; - break; - case CPP_MULT: - code = MULT_EXPR; - break; - case CPP_MINUS: - code = MINUS_EXPR; - break; - case CPP_AND: - code = BIT_AND_EXPR; - break; - case CPP_XOR: - code = BIT_XOR_EXPR; - break; - case CPP_OR: - code = BIT_IOR_EXPR; - break; - case CPP_AND_AND: - code = TRUTH_ANDIF_EXPR; - break; - case CPP_OR_OR: - code = TRUTH_ORIF_EXPR; - break; - case CPP_NAME: - { - const char *p - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "min") == 0) - { - code = MIN_EXPR; - break; - } - if (strcmp (p, "max") == 0) - { - code = MAX_EXPR; - break; - } - reduc_id = c_parser_peek_token (parser)->value; - break; - } - default: - c_parser_error (parser, - "expected %<+%>, %<*%>, %<-%>, %<&%>, " - "%<^%>, %<|%>, %<&&%>, %<||%> or identifier"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); - return list; - } - c_parser_consume_token (parser); - reduc_id = c_omp_reduction_id (code, reduc_id); - if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) - { - tree nl, c; - - nl = c_parser_omp_variable_list (parser, clause_loc, kind, list); - for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - { - tree d = OMP_CLAUSE_DECL (c), type; - if (TREE_CODE (d) != TREE_LIST) - type = TREE_TYPE (d); - else - { - int cnt = 0; - tree t; - for (t = d; TREE_CODE (t) == TREE_LIST; t = TREE_CHAIN (t)) - cnt++; - type = TREE_TYPE (t); - while (cnt > 0) - { - if (TREE_CODE (type) != POINTER_TYPE - && TREE_CODE (type) != ARRAY_TYPE) - break; - type = TREE_TYPE (type); - cnt--; - } - } - while (TREE_CODE (type) == ARRAY_TYPE) - type = TREE_TYPE (type); - OMP_CLAUSE_REDUCTION_CODE (c) = code; - if (task) - OMP_CLAUSE_REDUCTION_TASK (c) = 1; - else if (inscan) - OMP_CLAUSE_REDUCTION_INSCAN (c) = 1; - if (code == ERROR_MARK - || !(INTEGRAL_TYPE_P (type) - || TREE_CODE (type) == REAL_TYPE - || TREE_CODE (type) == COMPLEX_TYPE)) - OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) - = c_omp_reduction_lookup (reduc_id, - TYPE_MAIN_VARIANT (type)); - } - - list = nl; - } - parens.skip_until_found_close (parser); - } - return list; -} - -/* OpenMP 2.5: - schedule ( schedule-kind ) - schedule ( schedule-kind , expression ) - - schedule-kind: - static | dynamic | guided | runtime | auto - - OpenMP 4.5: - schedule ( schedule-modifier : schedule-kind ) - schedule ( schedule-modifier [ , schedule-modifier ] : schedule-kind , expression ) - - schedule-modifier: - simd - monotonic - nonmonotonic */ - -static tree -c_parser_omp_clause_schedule (c_parser *parser, tree list) -{ - tree c, t; - location_t loc = c_parser_peek_token (parser)->location; - int modifiers = 0, nmodifiers = 0; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE); - - location_t comma = UNKNOWN_LOCATION; - while (c_parser_next_token_is (parser, CPP_NAME)) - { - tree kind = c_parser_peek_token (parser)->value; - const char *p = IDENTIFIER_POINTER (kind); - if (strcmp ("simd", p) == 0) - OMP_CLAUSE_SCHEDULE_SIMD (c) = 1; - else if (strcmp ("monotonic", p) == 0) - modifiers |= OMP_CLAUSE_SCHEDULE_MONOTONIC; - else if (strcmp ("nonmonotonic", p) == 0) - modifiers |= OMP_CLAUSE_SCHEDULE_NONMONOTONIC; - else - break; - comma = UNKNOWN_LOCATION; - c_parser_consume_token (parser); - if (nmodifiers++ == 0 - && c_parser_next_token_is (parser, CPP_COMMA)) - { - comma = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - } - else - { - c_parser_require (parser, CPP_COLON, "expected %<:%>"); - break; - } - } - if (comma != UNKNOWN_LOCATION) - error_at (comma, "expected %<:%>"); - - if ((modifiers & (OMP_CLAUSE_SCHEDULE_MONOTONIC - | OMP_CLAUSE_SCHEDULE_NONMONOTONIC)) - == (OMP_CLAUSE_SCHEDULE_MONOTONIC - | OMP_CLAUSE_SCHEDULE_NONMONOTONIC)) - { - error_at (loc, "both % and % modifiers " - "specified"); - modifiers = 0; - } - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - tree kind = c_parser_peek_token (parser)->value; - const char *p = IDENTIFIER_POINTER (kind); - - switch (p[0]) - { - case 'd': - if (strcmp ("dynamic", p) != 0) - goto invalid_kind; - OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC; - break; - - case 'g': - if (strcmp ("guided", p) != 0) - goto invalid_kind; - OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED; - break; - - case 'r': - if (strcmp ("runtime", p) != 0) - goto invalid_kind; - OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME; - break; - - default: - goto invalid_kind; - } - } - else if (c_parser_next_token_is_keyword (parser, RID_STATIC)) - OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; - else if (c_parser_next_token_is_keyword (parser, RID_AUTO)) - OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO; - else - goto invalid_kind; - - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COMMA)) - { - location_t here; - c_parser_consume_token (parser); - - here = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (here, expr, false, true); - t = expr.value; - t = c_fully_fold (t, false, NULL); - - if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) - error_at (here, "schedule % does not take " - "a % parameter"); - else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO) - error_at (here, - "schedule % does not take " - "a % parameter"); - else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE) - { - /* Attempt to statically determine when the number isn't - positive. */ - tree s = fold_build2_loc (loc, LE_EXPR, boolean_type_node, t, - build_int_cst (TREE_TYPE (t), 0)); - protected_set_expr_location (s, loc); - if (s == boolean_true_node) - { - warning_at (loc, 0, - "chunk size value must be positive"); - t = integer_one_node; - } - OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; - } - else - c_parser_error (parser, "expected integer expression"); - - parens.skip_until_found_close (parser); - } - else - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<,%> or %<)%>"); - - OMP_CLAUSE_SCHEDULE_KIND (c) - = (enum omp_clause_schedule_kind) - (OMP_CLAUSE_SCHEDULE_KIND (c) | modifiers); - - check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule"); - OMP_CLAUSE_CHAIN (c) = list; - return c; - - invalid_kind: - c_parser_error (parser, "invalid schedule kind"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); - return list; -} - -/* OpenMP 2.5: - shared ( variable-list ) */ - -static tree -c_parser_omp_clause_shared (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list); -} - -/* OpenMP 3.0: - untied */ - -static tree -c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) -{ - tree c; - - /* FIXME: Should we allow duplicates? */ - check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied"); - - c = build_omp_clause (c_parser_peek_token (parser)->location, - OMP_CLAUSE_UNTIED); - OMP_CLAUSE_CHAIN (c) = list; - - return c; -} - -/* OpenMP 4.0: - inbranch - notinbranch */ - -static tree -c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED, - enum omp_clause_code code, tree list) -{ - check_no_duplicate_clause (list, code, omp_clause_code_name[code]); - - tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); - OMP_CLAUSE_CHAIN (c) = list; - - return c; -} - -/* OpenMP 4.0: - parallel - for - sections - taskgroup */ - -static tree -c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED, - enum omp_clause_code code, tree list) -{ - tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); - OMP_CLAUSE_CHAIN (c) = list; - - return c; -} - -/* OpenMP 4.5: - nogroup */ - -static tree -c_parser_omp_clause_nogroup (c_parser *parser ATTRIBUTE_UNUSED, tree list) -{ - check_no_duplicate_clause (list, OMP_CLAUSE_NOGROUP, "nogroup"); - tree c = build_omp_clause (c_parser_peek_token (parser)->location, - OMP_CLAUSE_NOGROUP); - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenMP 4.5: - simd - threads */ - -static tree -c_parser_omp_clause_orderedkind (c_parser *parser ATTRIBUTE_UNUSED, - enum omp_clause_code code, tree list) -{ - check_no_duplicate_clause (list, code, omp_clause_code_name[code]); - tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenMP 4.0: - num_teams ( expression ) - - OpenMP 5.1: - num_teams ( expression : expression ) */ - -static tree -c_parser_omp_clause_num_teams (c_parser *parser, tree list) -{ - location_t num_teams_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - location_t upper_loc = c_parser_peek_token (parser)->location; - location_t lower_loc = UNKNOWN_LOCATION; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (upper_loc, expr, false, true); - tree c, upper = expr.value, lower = NULL_TREE; - upper = c_fully_fold (upper, false, NULL); - - if (c_parser_next_token_is (parser, CPP_COLON)) - { - c_parser_consume_token (parser); - lower_loc = upper_loc; - lower = upper; - upper_loc = c_parser_peek_token (parser)->location; - expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (upper_loc, expr, false, true); - upper = expr.value; - upper = c_fully_fold (upper, false, NULL); - } - - parens.skip_until_found_close (parser); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (upper)) - || (lower && !INTEGRAL_TYPE_P (TREE_TYPE (lower)))) - { - c_parser_error (parser, "expected integer expression"); - return list; - } - - /* Attempt to statically determine when the number isn't positive. */ - c = fold_build2_loc (upper_loc, LE_EXPR, boolean_type_node, upper, - build_int_cst (TREE_TYPE (upper), 0)); - protected_set_expr_location (c, upper_loc); - if (c == boolean_true_node) - { - warning_at (upper_loc, 0, "% value must be positive"); - upper = integer_one_node; - } - if (lower) - { - c = fold_build2_loc (lower_loc, LE_EXPR, boolean_type_node, lower, - build_int_cst (TREE_TYPE (lower), 0)); - protected_set_expr_location (c, lower_loc); - if (c == boolean_true_node) - { - warning_at (lower_loc, 0, "% value must be positive"); - lower = NULL_TREE; - } - else if (TREE_CODE (lower) == INTEGER_CST - && TREE_CODE (upper) == INTEGER_CST - && tree_int_cst_lt (upper, lower)) - { - warning_at (lower_loc, 0, "% lower bound %qE bigger " - "than upper bound %qE", lower, upper); - lower = NULL_TREE; - } - } - - check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, "num_teams"); - - c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS); - OMP_CLAUSE_NUM_TEAMS_UPPER_EXPR (c) = upper; - OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c) = lower; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - - return list; -} - -/* OpenMP 4.0: - thread_limit ( expression ) */ - -static tree -c_parser_omp_clause_thread_limit (c_parser *parser, tree list) -{ - location_t num_thread_limit_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - tree c, t = expr.value; - t = c_fully_fold (t, false, NULL); - - parens.skip_until_found_close (parser); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - { - c_parser_error (parser, "expected integer expression"); - return list; - } - - /* Attempt to statically determine when the number isn't positive. */ - c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, - build_int_cst (TREE_TYPE (t), 0)); - protected_set_expr_location (c, expr_loc); - if (c == boolean_true_node) - { - warning_at (expr_loc, 0, "% value must be positive"); - t = integer_one_node; - } - - check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT, - "thread_limit"); - - c = build_omp_clause (num_thread_limit_loc, OMP_CLAUSE_THREAD_LIMIT); - OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - list = c; - } - - return list; -} - -/* OpenMP 4.0: - aligned ( variable-list ) - aligned ( variable-list : constant-expression ) */ - -static tree -c_parser_omp_clause_aligned (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - tree nl, c; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_ALIGNED, list); - - if (c_parser_next_token_is (parser, CPP_COLON)) - { - c_parser_consume_token (parser); - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - tree alignment = expr.value; - alignment = c_fully_fold (alignment, false, NULL); - if (TREE_CODE (alignment) != INTEGER_CST - || !INTEGRAL_TYPE_P (TREE_TYPE (alignment)) - || tree_int_cst_sgn (alignment) != 1) - { - error_at (clause_loc, "% clause alignment expression must " - "be positive constant integer expression"); - alignment = NULL_TREE; - } - - for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; - } - - parens.skip_until_found_close (parser); - return nl; -} - -/* OpenMP 5.0: - allocate ( variable-list ) - allocate ( expression : variable-list ) - - OpenMP 5.1: - allocate ( allocator-modifier : variable-list ) - allocate ( allocator-modifier , allocator-modifier : variable-list ) - - allocator-modifier: - allocator ( expression ) - align ( expression ) */ - -static tree -c_parser_omp_clause_allocate (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - tree nl, c; - tree allocator = NULL_TREE; - tree align = NULL_TREE; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - if ((c_parser_next_token_is_not (parser, CPP_NAME) - && c_parser_next_token_is_not (parser, CPP_KEYWORD)) - || (c_parser_peek_2nd_token (parser)->type != CPP_COMMA - && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN)) - { - bool has_modifiers = false; - tree orig_type = NULL_TREE; - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) - { - unsigned int n = 3; - const char *p - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if ((strcmp (p, "allocator") == 0 || strcmp (p, "align") == 0) - && c_parser_check_balanced_raw_token_sequence (parser, &n) - && (c_parser_peek_nth_token_raw (parser, n)->type - == CPP_CLOSE_PAREN)) - { - if (c_parser_peek_nth_token_raw (parser, n + 1)->type - == CPP_COLON) - has_modifiers = true; - else if (c_parser_peek_nth_token_raw (parser, n + 1)->type - == CPP_COMMA - && (c_parser_peek_nth_token_raw (parser, n + 2)->type - == CPP_NAME) - && (c_parser_peek_nth_token_raw (parser, n + 3)->type - == CPP_OPEN_PAREN)) - { - c_token *tok = c_parser_peek_nth_token_raw (parser, n + 2); - const char *q = IDENTIFIER_POINTER (tok->value); - n += 4; - if ((strcmp (q, "allocator") == 0 - || strcmp (q, "align") == 0) - && c_parser_check_balanced_raw_token_sequence (parser, - &n) - && (c_parser_peek_nth_token_raw (parser, n)->type - == CPP_CLOSE_PAREN) - && (c_parser_peek_nth_token_raw (parser, n + 1)->type - == CPP_COLON)) - has_modifiers = true; - } - } - if (has_modifiers) - { - c_parser_consume_token (parser); - matching_parens parens2;; - parens2.require_open (parser); - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - if (strcmp (p, "allocator") == 0) - { - allocator = expr.value; - allocator = c_fully_fold (allocator, false, NULL); - orig_type = expr.original_type - ? expr.original_type : TREE_TYPE (allocator); - orig_type = TYPE_MAIN_VARIANT (orig_type); - } - else - { - align = expr.value; - align = c_fully_fold (align, false, NULL); - } - parens2.skip_until_found_close (parser); - if (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - c_token *tok = c_parser_peek_token (parser); - const char *q = ""; - if (c_parser_next_token_is (parser, CPP_NAME)) - q = IDENTIFIER_POINTER (tok->value); - if (strcmp (q, "allocator") != 0 && strcmp (q, "align") != 0) - { - c_parser_error (parser, "expected % or " - "%"); - parens.skip_until_found_close (parser); - return list; - } - else if (strcmp (p, q) == 0) - { - error_at (tok->location, "duplicate %qs modifier", p); - parens.skip_until_found_close (parser); - return list; - } - c_parser_consume_token (parser); - if (!parens2.require_open (parser)) - { - parens.skip_until_found_close (parser); - return list; - } - expr_loc = c_parser_peek_token (parser)->location; - expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, - true); - if (strcmp (q, "allocator") == 0) - { - allocator = expr.value; - allocator = c_fully_fold (allocator, false, NULL); - orig_type = expr.original_type - ? expr.original_type : TREE_TYPE (allocator); - orig_type = TYPE_MAIN_VARIANT (orig_type); - } - else - { - align = expr.value; - align = c_fully_fold (align, false, NULL); - } - parens2.skip_until_found_close (parser); - } - } - } - if (!has_modifiers) - { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - allocator = expr.value; - allocator = c_fully_fold (allocator, false, NULL); - orig_type = expr.original_type - ? expr.original_type : TREE_TYPE (allocator); - orig_type = TYPE_MAIN_VARIANT (orig_type); - } - if (allocator - && (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) - || TREE_CODE (orig_type) != ENUMERAL_TYPE - || (TYPE_NAME (orig_type) - != get_identifier ("omp_allocator_handle_t")))) - { - error_at (clause_loc, "% clause allocator expression " - "has type %qT rather than " - "%", - TREE_TYPE (allocator)); - allocator = NULL_TREE; - } - if (align - && (!INTEGRAL_TYPE_P (TREE_TYPE (align)) - || !tree_fits_uhwi_p (align) - || !integer_pow2p (align))) - { - error_at (clause_loc, "% clause % modifier " - "argument needs to be positive constant " - "power of two integer expression"); - align = NULL_TREE; - } - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - { - parens.skip_until_found_close (parser); - return list; - } - } - - nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_ALLOCATE, list); - - if (allocator || align) - for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - { - OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; - OMP_CLAUSE_ALLOCATE_ALIGN (c) = align; - } - - parens.skip_until_found_close (parser); - return nl; -} - -/* OpenMP 4.0: - linear ( variable-list ) - linear ( variable-list : expression ) - - OpenMP 4.5: - linear ( modifier ( variable-list ) ) - linear ( modifier ( variable-list ) : expression ) */ - -static tree -c_parser_omp_clause_linear (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - tree nl, c, step; - enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - c_token *tok = c_parser_peek_token (parser); - const char *p = IDENTIFIER_POINTER (tok->value); - if (strcmp ("val", p) == 0) - kind = OMP_CLAUSE_LINEAR_VAL; - if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN) - kind = OMP_CLAUSE_LINEAR_DEFAULT; - if (kind != OMP_CLAUSE_LINEAR_DEFAULT) - { - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - } - - nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_LINEAR, list); - - if (kind != OMP_CLAUSE_LINEAR_DEFAULT) - parens.skip_until_found_close (parser); - - if (c_parser_next_token_is (parser, CPP_COLON)) - { - c_parser_consume_token (parser); - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - step = expr.value; - step = c_fully_fold (step, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) - { - error_at (clause_loc, "% clause step expression must " - "be integral"); - step = integer_one_node; - } - - } - else - step = integer_one_node; - - for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - { - OMP_CLAUSE_LINEAR_STEP (c) = step; - OMP_CLAUSE_LINEAR_KIND (c) = kind; - } - - parens.skip_until_found_close (parser); - return nl; -} - -/* OpenMP 5.0: - nontemporal ( variable-list ) */ - -static tree -c_parser_omp_clause_nontemporal (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_NONTEMPORAL, list); -} - -/* OpenMP 4.0: - safelen ( constant-expression ) */ - -static tree -c_parser_omp_clause_safelen (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - tree c, t; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - t = expr.value; - t = c_fully_fold (t, false, NULL); - if (TREE_CODE (t) != INTEGER_CST - || !INTEGRAL_TYPE_P (TREE_TYPE (t)) - || tree_int_cst_sgn (t) != 1) - { - error_at (clause_loc, "% clause expression must " - "be positive constant integer expression"); - t = NULL_TREE; - } - - parens.skip_until_found_close (parser); - if (t == NULL_TREE || t == error_mark_node) - return list; - - check_no_duplicate_clause (list, OMP_CLAUSE_SAFELEN, "safelen"); - - c = build_omp_clause (clause_loc, OMP_CLAUSE_SAFELEN); - OMP_CLAUSE_SAFELEN_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenMP 4.0: - simdlen ( constant-expression ) */ - -static tree -c_parser_omp_clause_simdlen (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - tree c, t; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - t = expr.value; - t = c_fully_fold (t, false, NULL); - if (TREE_CODE (t) != INTEGER_CST - || !INTEGRAL_TYPE_P (TREE_TYPE (t)) - || tree_int_cst_sgn (t) != 1) - { - error_at (clause_loc, "% clause expression must " - "be positive constant integer expression"); - t = NULL_TREE; - } - - parens.skip_until_found_close (parser); - if (t == NULL_TREE || t == error_mark_node) - return list; - - check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen"); - - c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN); - OMP_CLAUSE_SIMDLEN_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenMP 4.5: - vec: - identifier [+/- integer] - vec , identifier [+/- integer] -*/ - -static tree -c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc, - tree list) -{ - tree vec = NULL; - if (c_parser_next_token_is_not (parser, CPP_NAME) - || c_parser_peek_token (parser)->id_kind != C_ID_ID) - { - c_parser_error (parser, "expected identifier"); - return list; - } - - while (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_ID) - { - tree t = lookup_name (c_parser_peek_token (parser)->value); - tree addend = NULL; - - if (t == NULL_TREE) - { - undeclared_variable (c_parser_peek_token (parser)->location, - c_parser_peek_token (parser)->value); - t = error_mark_node; - } - - c_parser_consume_token (parser); - - bool neg = false; - if (c_parser_next_token_is (parser, CPP_MINUS)) - neg = true; - else if (!c_parser_next_token_is (parser, CPP_PLUS)) - { - addend = integer_zero_node; - neg = false; - goto add_to_vector; - } - c_parser_consume_token (parser); - - if (c_parser_next_token_is_not (parser, CPP_NUMBER)) - { - c_parser_error (parser, "expected integer"); - return list; - } - - addend = c_parser_peek_token (parser)->value; - if (TREE_CODE (addend) != INTEGER_CST) - { - c_parser_error (parser, "expected integer"); - return list; - } - c_parser_consume_token (parser); - - add_to_vector: - if (t != error_mark_node) - { - vec = tree_cons (addend, t, vec); - if (neg) - OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1; - } - - if (c_parser_next_token_is_not (parser, CPP_COMMA) - || c_parser_peek_2nd_token (parser)->type != CPP_NAME - || c_parser_peek_2nd_token (parser)->id_kind != C_ID_ID) - break; - - c_parser_consume_token (parser); - } - - if (vec == NULL_TREE) - return list; - - tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); - OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK; - OMP_CLAUSE_DECL (u) = nreverse (vec); - OMP_CLAUSE_CHAIN (u) = list; - return u; -} - -/* OpenMP 5.0: - iterators ( iterators-definition ) - - iterators-definition: - iterator-specifier - iterator-specifier , iterators-definition - - iterator-specifier: - identifier = range-specification - iterator-type identifier = range-specification - - range-specification: - begin : end - begin : end : step */ - -static tree -c_parser_omp_iterators (c_parser *parser) -{ - tree ret = NULL_TREE, *last = &ret; - c_parser_consume_token (parser); - - push_scope (); - - matching_parens parens; - if (!parens.require_open (parser)) - return error_mark_node; - - do - { - tree iter_type = NULL_TREE, type_expr = NULL_TREE; - if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) - { - struct c_type_name *type = c_parser_type_name (parser); - if (type != NULL) - iter_type = groktypename (type, &type_expr, NULL); - } - if (iter_type == NULL_TREE) - iter_type = integer_type_node; - - location_t loc = c_parser_peek_token (parser)->location; - if (!c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - break; - } - - tree id = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - - if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) - break; - - location_t eloc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (eloc, expr, true, false); - tree begin = expr.value; - - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - break; - - eloc = c_parser_peek_token (parser)->location; - expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (eloc, expr, true, false); - tree end = expr.value; - - tree step = integer_one_node; - if (c_parser_next_token_is (parser, CPP_COLON)) - { - c_parser_consume_token (parser); - eloc = c_parser_peek_token (parser)->location; - expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (eloc, expr, true, false); - step = expr.value; - } - - tree iter_var = build_decl (loc, VAR_DECL, id, iter_type); - DECL_ARTIFICIAL (iter_var) = 1; - DECL_CONTEXT (iter_var) = current_function_decl; - pushdecl (iter_var); - - *last = make_tree_vec (6); - TREE_VEC_ELT (*last, 0) = iter_var; - TREE_VEC_ELT (*last, 1) = begin; - TREE_VEC_ELT (*last, 2) = end; - TREE_VEC_ELT (*last, 3) = step; - last = &TREE_CHAIN (*last); - - if (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - continue; - } - break; - } - while (1); - - parens.skip_until_found_close (parser); - return ret ? ret : error_mark_node; -} - -/* OpenMP 5.0: - affinity ( [aff-modifier :] variable-list ) - aff-modifier: - iterator ( iterators-definition ) */ - -static tree -c_parser_omp_clause_affinity (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - tree nl, iterators = NULL_TREE; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - bool parse_iter = ((strcmp ("iterator", p) == 0) - && (c_parser_peek_2nd_token (parser)->type - == CPP_OPEN_PAREN)); - if (parse_iter) - { - unsigned n = 3; - parse_iter = (c_parser_check_balanced_raw_token_sequence (parser, &n) - && (c_parser_peek_nth_token_raw (parser, n)->type - == CPP_CLOSE_PAREN) - && (c_parser_peek_nth_token_raw (parser, n + 1)->type - == CPP_COLON)); - } - if (parse_iter) - { - iterators = c_parser_omp_iterators (parser); - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - { - if (iterators) - pop_scope (); - parens.skip_until_found_close (parser); - return list; - } - } - } - nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_AFFINITY, - list); - if (iterators) - { - tree block = pop_scope (); - if (iterators != error_mark_node) - { - TREE_VEC_ELT (iterators, 5) = block; - for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_DECL (c) = build_tree_list (iterators, - OMP_CLAUSE_DECL (c)); - } - } - - parens.skip_until_found_close (parser); - return nl; -} - - -/* OpenMP 4.0: - depend ( depend-kind: variable-list ) - - depend-kind: - in | out | inout - - OpenMP 4.5: - depend ( source ) - - depend ( sink : vec ) - - OpenMP 5.0: - depend ( depend-modifier , depend-kind: variable-list ) - - depend-kind: - in | out | inout | mutexinoutset | depobj - - depend-modifier: - iterator ( iterators-definition ) */ - -static tree -c_parser_omp_clause_depend (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST; - tree nl, c, iterators = NULL_TREE; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - do - { - if (c_parser_next_token_is_not (parser, CPP_NAME)) - goto invalid_kind; - - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp ("iterator", p) == 0 && iterators == NULL_TREE) - { - iterators = c_parser_omp_iterators (parser); - c_parser_require (parser, CPP_COMMA, "expected %<,%>"); - continue; - } - if (strcmp ("in", p) == 0) - kind = OMP_CLAUSE_DEPEND_IN; - else if (strcmp ("inout", p) == 0) - kind = OMP_CLAUSE_DEPEND_INOUT; - else if (strcmp ("mutexinoutset", p) == 0) - kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; - else if (strcmp ("out", p) == 0) - kind = OMP_CLAUSE_DEPEND_OUT; - else if (strcmp ("depobj", p) == 0) - kind = OMP_CLAUSE_DEPEND_DEPOBJ; - else if (strcmp ("sink", p) == 0) - kind = OMP_CLAUSE_DEPEND_SINK; - else if (strcmp ("source", p) == 0) - kind = OMP_CLAUSE_DEPEND_SOURCE; - else - goto invalid_kind; - break; - } - while (1); - - c_parser_consume_token (parser); - - if (iterators - && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK)) - { - pop_scope (); - error_at (clause_loc, "% modifier incompatible with %qs", - kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); - iterators = NULL_TREE; - } - - if (kind == OMP_CLAUSE_DEPEND_SOURCE) - { - c = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); - OMP_CLAUSE_DEPEND_KIND (c) = kind; - OMP_CLAUSE_DECL (c) = NULL_TREE; - OMP_CLAUSE_CHAIN (c) = list; - parens.skip_until_found_close (parser); - return c; - } - - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - goto resync_fail; - - if (kind == OMP_CLAUSE_DEPEND_SINK) - nl = c_parser_omp_clause_depend_sink (parser, clause_loc, list); - else - { - nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_DEPEND, list); - - if (iterators) - { - tree block = pop_scope (); - if (iterators == error_mark_node) - iterators = NULL_TREE; - else - TREE_VEC_ELT (iterators, 5) = block; - } - - for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - { - OMP_CLAUSE_DEPEND_KIND (c) = kind; - if (iterators) - OMP_CLAUSE_DECL (c) - = build_tree_list (iterators, OMP_CLAUSE_DECL (c)); - } - } - - parens.skip_until_found_close (parser); - return nl; - - invalid_kind: - c_parser_error (parser, "invalid depend kind"); - resync_fail: - parens.skip_until_found_close (parser); - if (iterators) - pop_scope (); - return list; -} - -/* OpenMP 4.0: - map ( map-kind: variable-list ) - map ( variable-list ) - - map-kind: - alloc | to | from | tofrom - - OpenMP 4.5: - map-kind: - alloc | to | from | tofrom | release | delete - - map ( always [,] map-kind: variable-list ) - - OpenMP 5.0: - map ( [map-type-modifier[,] ...] map-kind: variable-list ) - - map-type-modifier: - always | close */ - -static tree -c_parser_omp_clause_map (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - enum gomp_map_kind kind = GOMP_MAP_TOFROM; - tree nl, c; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - int pos = 1; - int map_kind_pos = 0; - while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME) - { - if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COLON) - { - map_kind_pos = pos; - break; - } - - if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA) - pos++; - pos++; - } - - int always_modifier = 0; - int close_modifier = 0; - for (int pos = 1; pos < map_kind_pos; ++pos) - { - c_token *tok = c_parser_peek_token (parser); - - if (tok->type == CPP_COMMA) - { - c_parser_consume_token (parser); - continue; - } - - const char *p = IDENTIFIER_POINTER (tok->value); - if (strcmp ("always", p) == 0) - { - if (always_modifier) - { - c_parser_error (parser, "too many % modifiers"); - parens.skip_until_found_close (parser); - return list; - } - always_modifier++; - } - else if (strcmp ("close", p) == 0) - { - if (close_modifier) - { - c_parser_error (parser, "too many % modifiers"); - parens.skip_until_found_close (parser); - return list; - } - close_modifier++; - } - else - { - c_parser_error (parser, "%<#pragma omp target%> with " - "modifier other than % or %" - "on % clause"); - parens.skip_until_found_close (parser); - return list; - } - - c_parser_consume_token (parser); - } - - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp ("alloc", p) == 0) - kind = GOMP_MAP_ALLOC; - else if (strcmp ("to", p) == 0) - kind = always_modifier ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO; - else if (strcmp ("from", p) == 0) - kind = always_modifier ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM; - else if (strcmp ("tofrom", p) == 0) - kind = always_modifier ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM; - else if (strcmp ("release", p) == 0) - kind = GOMP_MAP_RELEASE; - else if (strcmp ("delete", p) == 0) - kind = GOMP_MAP_DELETE; - else - { - c_parser_error (parser, "invalid map kind"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return list; - } - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - - nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list, - true); - - for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_SET_MAP_KIND (c, kind); - - parens.skip_until_found_close (parser); - return nl; -} - -/* OpenMP 4.0: - device ( expression ) - - OpenMP 5.0: - device ( [device-modifier :] integer-expression ) - - device-modifier: - ancestor | device_num */ - -static tree -c_parser_omp_clause_device (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - location_t expr_loc; - c_expr expr; - tree c, t; - bool ancestor = false; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) - { - c_token *tok = c_parser_peek_token (parser); - const char *p = IDENTIFIER_POINTER (tok->value); - if (strcmp ("ancestor", p) == 0) - { - /* A requires directive with the reverse_offload clause must be - specified. */ - if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0) - { - error_at (tok->location, "% device modifier not " - "preceded by % directive " - "with % clause"); - parens.skip_until_found_close (parser); - return list; - } - ancestor = true; - } - else if (strcmp ("device_num", p) == 0) - ; - else - { - error_at (tok->location, "expected % or %"); - parens.skip_until_found_close (parser); - return list; - } - c_parser_consume_token (parser); - c_parser_consume_token (parser); - } - - expr_loc = c_parser_peek_token (parser)->location; - expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - t = expr.value; - t = c_fully_fold (t, false, NULL); - - parens.skip_until_found_close (parser); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - { - c_parser_error (parser, "expected integer expression"); - return list; - } - if (ancestor && TREE_CODE (t) == INTEGER_CST && !integer_onep (t)) - { - error_at (expr_loc, "the % clause expression must evaluate to " - "%<1%>"); - return list; - } - - check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, "device"); - - c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE); - - OMP_CLAUSE_DEVICE_ID (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - OMP_CLAUSE_DEVICE_ANCESTOR (c) = ancestor; - - list = c; - return list; -} - -/* OpenMP 4.0: - dist_schedule ( static ) - dist_schedule ( static , expression ) */ - -static tree -c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) -{ - tree c, t = NULL_TREE; - location_t loc = c_parser_peek_token (parser)->location; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - if (!c_parser_next_token_is_keyword (parser, RID_STATIC)) - { - c_parser_error (parser, "invalid dist_schedule kind"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return list; - } - - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - t = expr.value; - t = c_fully_fold (t, false, NULL); - parens.skip_until_found_close (parser); - } - else - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<,%> or %<)%>"); - - /* check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE, - "dist_schedule"); */ - if (omp_find_clause (list, OMP_CLAUSE_DIST_SCHEDULE)) - warning_at (loc, 0, "too many %qs clauses", "dist_schedule"); - if (t == error_mark_node) - return list; - - c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE); - OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - return c; -} - -/* OpenMP 4.0: - proc_bind ( proc-bind-kind ) - - proc-bind-kind: - primary | master | close | spread - where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ - -static tree -c_parser_omp_clause_proc_bind (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - enum omp_clause_proc_bind_kind kind; - tree c; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp ("primary", p) == 0) - kind = OMP_CLAUSE_PROC_BIND_PRIMARY; - else if (strcmp ("master", p) == 0) - kind = OMP_CLAUSE_PROC_BIND_MASTER; - else if (strcmp ("close", p) == 0) - kind = OMP_CLAUSE_PROC_BIND_CLOSE; - else if (strcmp ("spread", p) == 0) - kind = OMP_CLAUSE_PROC_BIND_SPREAD; - else - goto invalid_kind; - } - else - goto invalid_kind; - - check_no_duplicate_clause (list, OMP_CLAUSE_PROC_BIND, "proc_bind"); - c_parser_consume_token (parser); - parens.skip_until_found_close (parser); - c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND); - OMP_CLAUSE_PROC_BIND_KIND (c) = kind; - OMP_CLAUSE_CHAIN (c) = list; - return c; - - invalid_kind: - c_parser_error (parser, "invalid proc_bind kind"); - parens.skip_until_found_close (parser); - return list; -} - -/* OpenMP 5.0: - device_type ( host | nohost | any ) */ - -static tree -c_parser_omp_clause_device_type (c_parser *parser, tree list) -{ - location_t clause_loc = c_parser_peek_token (parser)->location; - enum omp_clause_device_type_kind kind; - tree c; - - matching_parens parens; - if (!parens.require_open (parser)) - return list; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp ("host", p) == 0) - kind = OMP_CLAUSE_DEVICE_TYPE_HOST; - else if (strcmp ("nohost", p) == 0) - kind = OMP_CLAUSE_DEVICE_TYPE_NOHOST; - else if (strcmp ("any", p) == 0) - kind = OMP_CLAUSE_DEVICE_TYPE_ANY; - else - goto invalid_kind; - } - else - goto invalid_kind; - - /* check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE, - "device_type"); */ - c_parser_consume_token (parser); - parens.skip_until_found_close (parser); - c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE_TYPE); - OMP_CLAUSE_DEVICE_TYPE_KIND (c) = kind; - OMP_CLAUSE_CHAIN (c) = list; - return c; - - invalid_kind: - c_parser_error (parser, "expected %, % or %"); - parens.skip_until_found_close (parser); - return list; -} - -/* OpenMP 4.0: - to ( variable-list ) */ - -static tree -c_parser_omp_clause_to (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true); -} - -/* OpenMP 4.0: - from ( variable-list ) */ - -static tree -c_parser_omp_clause_from (c_parser *parser, tree list) -{ - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list, true); -} - -/* OpenMP 4.0: - uniform ( variable-list ) */ - -static tree -c_parser_omp_clause_uniform (c_parser *parser, tree list) -{ - /* The clauses location. */ - location_t loc = c_parser_peek_token (parser)->location; - - matching_parens parens; - if (parens.require_open (parser)) - { - list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM, - list); - parens.skip_until_found_close (parser); - } - return list; -} - -/* OpenMP 5.0: - detach ( event-handle ) */ - -static tree -c_parser_omp_clause_detach (c_parser *parser, tree list) -{ - matching_parens parens; - location_t clause_loc = c_parser_peek_token (parser)->location; - - if (!parens.require_open (parser)) - return list; - - if (c_parser_next_token_is_not (parser, CPP_NAME) - || c_parser_peek_token (parser)->id_kind != C_ID_ID) - { - c_parser_error (parser, "expected identifier"); - parens.skip_until_found_close (parser); - return list; - } - - tree t = lookup_name (c_parser_peek_token (parser)->value); - if (t == NULL_TREE) - { - undeclared_variable (c_parser_peek_token (parser)->location, - c_parser_peek_token (parser)->value); - parens.skip_until_found_close (parser); - return list; - } - c_parser_consume_token (parser); - - tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); - if (!INTEGRAL_TYPE_P (type) - || TREE_CODE (type) != ENUMERAL_TYPE - || TYPE_NAME (type) != get_identifier ("omp_event_handle_t")) - { - error_at (clause_loc, "% clause event handle " - "has type %qT rather than " - "%", - type); - parens.skip_until_found_close (parser); - return list; - } - - tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DETACH); - OMP_CLAUSE_DECL (u) = t; - OMP_CLAUSE_CHAIN (u) = list; - parens.skip_until_found_close (parser); - return u; -} - -/* Parse all OpenACC clauses. The set clauses allowed by the directive - is a bitmask in MASK. Return the list of clauses found. */ - -static tree -c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, - const char *where, bool finish_p = true) -{ - tree clauses = NULL; - bool first = true; - - while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - { - location_t here; - pragma_omp_clause c_kind; - const char *c_name; - tree prev = clauses; - - if (!first && c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - - here = c_parser_peek_token (parser)->location; - c_kind = c_parser_omp_clause_name (parser); - - switch (c_kind) - { - case PRAGMA_OACC_CLAUSE_ASYNC: - clauses = c_parser_oacc_clause_async (parser, clauses); - c_name = "async"; - break; - case PRAGMA_OACC_CLAUSE_AUTO: - clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_AUTO, - clauses); - c_name = "auto"; - break; - case PRAGMA_OACC_CLAUSE_ATTACH: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "attach"; - break; - case PRAGMA_OACC_CLAUSE_COLLAPSE: - clauses = c_parser_omp_clause_collapse (parser, clauses); - c_name = "collapse"; - break; - case PRAGMA_OACC_CLAUSE_COPY: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "copy"; - break; - case PRAGMA_OACC_CLAUSE_COPYIN: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "copyin"; - break; - case PRAGMA_OACC_CLAUSE_COPYOUT: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "copyout"; - break; - case PRAGMA_OACC_CLAUSE_CREATE: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "create"; - break; - case PRAGMA_OACC_CLAUSE_DELETE: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "delete"; - break; - case PRAGMA_OMP_CLAUSE_DEFAULT: - clauses = c_parser_omp_clause_default (parser, clauses, true); - c_name = "default"; - break; - case PRAGMA_OACC_CLAUSE_DETACH: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "detach"; - break; - case PRAGMA_OACC_CLAUSE_DEVICE: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "device"; - break; - case PRAGMA_OACC_CLAUSE_DEVICEPTR: - clauses = c_parser_oacc_data_clause_deviceptr (parser, clauses); - c_name = "deviceptr"; - break; - case PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "device_resident"; - break; - case PRAGMA_OACC_CLAUSE_FINALIZE: - clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_FINALIZE, - clauses); - c_name = "finalize"; - break; - case PRAGMA_OACC_CLAUSE_FIRSTPRIVATE: - clauses = c_parser_omp_clause_firstprivate (parser, clauses); - c_name = "firstprivate"; - break; - case PRAGMA_OACC_CLAUSE_GANG: - c_name = "gang"; - clauses = c_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_GANG, - c_name, clauses); - break; - case PRAGMA_OACC_CLAUSE_HOST: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "host"; - break; - case PRAGMA_OACC_CLAUSE_IF: - clauses = c_parser_omp_clause_if (parser, clauses, false); - c_name = "if"; - break; - case PRAGMA_OACC_CLAUSE_IF_PRESENT: - clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_IF_PRESENT, - clauses); - c_name = "if_present"; - break; - case PRAGMA_OACC_CLAUSE_INDEPENDENT: - clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_INDEPENDENT, - clauses); - c_name = "independent"; - break; - case PRAGMA_OACC_CLAUSE_LINK: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "link"; - break; - case PRAGMA_OACC_CLAUSE_NO_CREATE: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "no_create"; - break; - case PRAGMA_OACC_CLAUSE_NOHOST: - clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_NOHOST, - clauses); - c_name = "nohost"; - break; - case PRAGMA_OACC_CLAUSE_NUM_GANGS: - clauses = c_parser_oacc_single_int_clause (parser, - OMP_CLAUSE_NUM_GANGS, - clauses); - c_name = "num_gangs"; - break; - case PRAGMA_OACC_CLAUSE_NUM_WORKERS: - clauses = c_parser_oacc_single_int_clause (parser, - OMP_CLAUSE_NUM_WORKERS, - clauses); - c_name = "num_workers"; - break; - case PRAGMA_OACC_CLAUSE_PRESENT: - clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); - c_name = "present"; - break; - case PRAGMA_OACC_CLAUSE_PRIVATE: - clauses = c_parser_omp_clause_private (parser, clauses); - c_name = "private"; - break; - case PRAGMA_OACC_CLAUSE_REDUCTION: - clauses - = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION, - false, clauses); - c_name = "reduction"; - break; - case PRAGMA_OACC_CLAUSE_SEQ: - clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_SEQ, - clauses); - c_name = "seq"; - break; - case PRAGMA_OACC_CLAUSE_TILE: - clauses = c_parser_oacc_clause_tile (parser, clauses); - c_name = "tile"; - break; - case PRAGMA_OACC_CLAUSE_USE_DEVICE: - clauses = c_parser_omp_clause_use_device_ptr (parser, clauses); - c_name = "use_device"; - break; - case PRAGMA_OACC_CLAUSE_VECTOR: - c_name = "vector"; - clauses = c_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_VECTOR, - c_name, clauses); - break; - case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH: - clauses = c_parser_oacc_single_int_clause (parser, - OMP_CLAUSE_VECTOR_LENGTH, - clauses); - c_name = "vector_length"; - break; - case PRAGMA_OACC_CLAUSE_WAIT: - clauses = c_parser_oacc_clause_wait (parser, clauses); - c_name = "wait"; - break; - case PRAGMA_OACC_CLAUSE_WORKER: - c_name = "worker"; - clauses = c_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_WORKER, - c_name, clauses); - break; - default: - c_parser_error (parser, "expected %<#pragma acc%> clause"); - goto saw_error; - } - - first = false; - - if (((mask >> c_kind) & 1) == 0) - { - /* Remove the invalid clause(s) from the list to avoid - confusing the rest of the compiler. */ - clauses = prev; - error_at (here, "%qs is not valid for %qs", c_name, where); - } - } - - saw_error: - c_parser_skip_to_pragma_eol (parser); - - if (finish_p) - return c_finish_omp_clauses (clauses, C_ORT_ACC); - - return clauses; -} - -/* Parse all OpenMP clauses. The set clauses allowed by the directive - is a bitmask in MASK. Return the list of clauses found. - FINISH_P set if c_finish_omp_clauses should be called. - NESTED non-zero if clauses should be terminated by closing paren instead - of end of pragma. If it is 2, additionally commas are required in between - the clauses. */ - -static tree -c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, - const char *where, bool finish_p = true, - int nested = 0) -{ - tree clauses = NULL; - bool first = true; - - while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - { - location_t here; - pragma_omp_clause c_kind; - const char *c_name; - tree prev = clauses; - - if (nested && c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - break; - - if (!first) - { - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else if (nested == 2) - error_at (c_parser_peek_token (parser)->location, - "clauses in % trait should be separated " - "by %<,%>"); - } - - here = c_parser_peek_token (parser)->location; - c_kind = c_parser_omp_clause_name (parser); - - switch (c_kind) - { - case PRAGMA_OMP_CLAUSE_BIND: - clauses = c_parser_omp_clause_bind (parser, clauses); - c_name = "bind"; - break; - case PRAGMA_OMP_CLAUSE_COLLAPSE: - clauses = c_parser_omp_clause_collapse (parser, clauses); - c_name = "collapse"; - break; - case PRAGMA_OMP_CLAUSE_COPYIN: - clauses = c_parser_omp_clause_copyin (parser, clauses); - c_name = "copyin"; - break; - case PRAGMA_OMP_CLAUSE_COPYPRIVATE: - clauses = c_parser_omp_clause_copyprivate (parser, clauses); - c_name = "copyprivate"; - break; - case PRAGMA_OMP_CLAUSE_DEFAULT: - clauses = c_parser_omp_clause_default (parser, clauses, false); - c_name = "default"; - break; - case PRAGMA_OMP_CLAUSE_DETACH: - clauses = c_parser_omp_clause_detach (parser, clauses); - c_name = "detach"; - break; - case PRAGMA_OMP_CLAUSE_FILTER: - clauses = c_parser_omp_clause_filter (parser, clauses); - c_name = "filter"; - break; - case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: - clauses = c_parser_omp_clause_firstprivate (parser, clauses); - c_name = "firstprivate"; - break; - case PRAGMA_OMP_CLAUSE_FINAL: - clauses = c_parser_omp_clause_final (parser, clauses); - c_name = "final"; - break; - case PRAGMA_OMP_CLAUSE_GRAINSIZE: - clauses = c_parser_omp_clause_grainsize (parser, clauses); - c_name = "grainsize"; - break; - case PRAGMA_OMP_CLAUSE_HINT: - clauses = c_parser_omp_clause_hint (parser, clauses); - c_name = "hint"; - break; - case PRAGMA_OMP_CLAUSE_DEFAULTMAP: - clauses = c_parser_omp_clause_defaultmap (parser, clauses); - c_name = "defaultmap"; - break; - case PRAGMA_OMP_CLAUSE_IF: - clauses = c_parser_omp_clause_if (parser, clauses, true); - c_name = "if"; - break; - case PRAGMA_OMP_CLAUSE_IN_REDUCTION: - clauses - = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_IN_REDUCTION, - true, clauses); - c_name = "in_reduction"; - break; - case PRAGMA_OMP_CLAUSE_LASTPRIVATE: - clauses = c_parser_omp_clause_lastprivate (parser, clauses); - c_name = "lastprivate"; - break; - case PRAGMA_OMP_CLAUSE_MERGEABLE: - clauses = c_parser_omp_clause_mergeable (parser, clauses); - c_name = "mergeable"; - break; - case PRAGMA_OMP_CLAUSE_NOWAIT: - clauses = c_parser_omp_clause_nowait (parser, clauses); - c_name = "nowait"; - break; - case PRAGMA_OMP_CLAUSE_NUM_TASKS: - clauses = c_parser_omp_clause_num_tasks (parser, clauses); - c_name = "num_tasks"; - break; - case PRAGMA_OMP_CLAUSE_NUM_THREADS: - clauses = c_parser_omp_clause_num_threads (parser, clauses); - c_name = "num_threads"; - break; - case PRAGMA_OMP_CLAUSE_ORDER: - clauses = c_parser_omp_clause_order (parser, clauses); - c_name = "order"; - break; - case PRAGMA_OMP_CLAUSE_ORDERED: - clauses = c_parser_omp_clause_ordered (parser, clauses); - c_name = "ordered"; - break; - case PRAGMA_OMP_CLAUSE_PRIORITY: - clauses = c_parser_omp_clause_priority (parser, clauses); - c_name = "priority"; - break; - case PRAGMA_OMP_CLAUSE_PRIVATE: - clauses = c_parser_omp_clause_private (parser, clauses); - c_name = "private"; - break; - case PRAGMA_OMP_CLAUSE_REDUCTION: - clauses - = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION, - true, clauses); - c_name = "reduction"; - break; - case PRAGMA_OMP_CLAUSE_SCHEDULE: - clauses = c_parser_omp_clause_schedule (parser, clauses); - c_name = "schedule"; - break; - case PRAGMA_OMP_CLAUSE_SHARED: - clauses = c_parser_omp_clause_shared (parser, clauses); - c_name = "shared"; - break; - case PRAGMA_OMP_CLAUSE_TASK_REDUCTION: - clauses - = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_TASK_REDUCTION, - true, clauses); - c_name = "task_reduction"; - break; - case PRAGMA_OMP_CLAUSE_UNTIED: - clauses = c_parser_omp_clause_untied (parser, clauses); - c_name = "untied"; - break; - case PRAGMA_OMP_CLAUSE_INBRANCH: - clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH, - clauses); - c_name = "inbranch"; - break; - case PRAGMA_OMP_CLAUSE_NONTEMPORAL: - clauses = c_parser_omp_clause_nontemporal (parser, clauses); - c_name = "nontemporal"; - break; - case PRAGMA_OMP_CLAUSE_NOTINBRANCH: - clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH, - clauses); - c_name = "notinbranch"; - break; - case PRAGMA_OMP_CLAUSE_PARALLEL: - clauses - = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL, - clauses); - c_name = "parallel"; - if (!first) - { - clause_not_first: - error_at (here, "%qs must be the first clause of %qs", - c_name, where); - clauses = prev; - } - break; - case PRAGMA_OMP_CLAUSE_FOR: - clauses - = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR, - clauses); - c_name = "for"; - if (!first) - goto clause_not_first; - break; - case PRAGMA_OMP_CLAUSE_SECTIONS: - clauses - = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS, - clauses); - c_name = "sections"; - if (!first) - goto clause_not_first; - break; - case PRAGMA_OMP_CLAUSE_TASKGROUP: - clauses - = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP, - clauses); - c_name = "taskgroup"; - if (!first) - goto clause_not_first; - break; - case PRAGMA_OMP_CLAUSE_LINK: - clauses - = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LINK, clauses); - c_name = "link"; - break; - case PRAGMA_OMP_CLAUSE_TO: - if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0) - clauses - = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, - clauses); - else - clauses = c_parser_omp_clause_to (parser, clauses); - c_name = "to"; - break; - case PRAGMA_OMP_CLAUSE_FROM: - clauses = c_parser_omp_clause_from (parser, clauses); - c_name = "from"; - break; - case PRAGMA_OMP_CLAUSE_UNIFORM: - clauses = c_parser_omp_clause_uniform (parser, clauses); - c_name = "uniform"; - break; - case PRAGMA_OMP_CLAUSE_NUM_TEAMS: - clauses = c_parser_omp_clause_num_teams (parser, clauses); - c_name = "num_teams"; - break; - case PRAGMA_OMP_CLAUSE_THREAD_LIMIT: - clauses = c_parser_omp_clause_thread_limit (parser, clauses); - c_name = "thread_limit"; - break; - case PRAGMA_OMP_CLAUSE_ALIGNED: - clauses = c_parser_omp_clause_aligned (parser, clauses); - c_name = "aligned"; - break; - case PRAGMA_OMP_CLAUSE_ALLOCATE: - clauses = c_parser_omp_clause_allocate (parser, clauses); - c_name = "allocate"; - break; - case PRAGMA_OMP_CLAUSE_LINEAR: - clauses = c_parser_omp_clause_linear (parser, clauses); - c_name = "linear"; - break; - case PRAGMA_OMP_CLAUSE_AFFINITY: - clauses = c_parser_omp_clause_affinity (parser, clauses); - c_name = "affinity"; - break; - case PRAGMA_OMP_CLAUSE_DEPEND: - clauses = c_parser_omp_clause_depend (parser, clauses); - c_name = "depend"; - break; - case PRAGMA_OMP_CLAUSE_MAP: - clauses = c_parser_omp_clause_map (parser, clauses); - c_name = "map"; - break; - case PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR: - clauses = c_parser_omp_clause_use_device_ptr (parser, clauses); - c_name = "use_device_ptr"; - break; - case PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR: - clauses = c_parser_omp_clause_use_device_addr (parser, clauses); - c_name = "use_device_addr"; - break; - case PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR: - clauses = c_parser_omp_clause_is_device_ptr (parser, clauses); - c_name = "is_device_ptr"; - break; - case PRAGMA_OMP_CLAUSE_DEVICE: - clauses = c_parser_omp_clause_device (parser, clauses); - c_name = "device"; - break; - case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE: - clauses = c_parser_omp_clause_dist_schedule (parser, clauses); - c_name = "dist_schedule"; - break; - case PRAGMA_OMP_CLAUSE_PROC_BIND: - clauses = c_parser_omp_clause_proc_bind (parser, clauses); - c_name = "proc_bind"; - break; - case PRAGMA_OMP_CLAUSE_DEVICE_TYPE: - clauses = c_parser_omp_clause_device_type (parser, clauses); - c_name = "device_type"; - break; - case PRAGMA_OMP_CLAUSE_SAFELEN: - clauses = c_parser_omp_clause_safelen (parser, clauses); - c_name = "safelen"; - break; - case PRAGMA_OMP_CLAUSE_SIMDLEN: - clauses = c_parser_omp_clause_simdlen (parser, clauses); - c_name = "simdlen"; - break; - case PRAGMA_OMP_CLAUSE_NOGROUP: - clauses = c_parser_omp_clause_nogroup (parser, clauses); - c_name = "nogroup"; - break; - case PRAGMA_OMP_CLAUSE_THREADS: - clauses - = c_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_THREADS, - clauses); - c_name = "threads"; - break; - case PRAGMA_OMP_CLAUSE_SIMD: - clauses - = c_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_SIMD, - clauses); - c_name = "simd"; - break; - default: - c_parser_error (parser, "expected %<#pragma omp%> clause"); - goto saw_error; - } - - first = false; - - if (((mask >> c_kind) & 1) == 0) - { - /* Remove the invalid clause(s) from the list to avoid - confusing the rest of the compiler. */ - clauses = prev; - error_at (here, "%qs is not valid for %qs", c_name, where); - } - } - - saw_error: - if (!nested) - c_parser_skip_to_pragma_eol (parser); - - if (finish_p) - { - if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0) - return c_finish_omp_clauses (clauses, C_ORT_OMP_DECLARE_SIMD); - return c_finish_omp_clauses (clauses, C_ORT_OMP); - } - - return clauses; -} - -/* OpenACC 2.0, OpenMP 2.5: - structured-block: - statement - - In practice, we're also interested in adding the statement to an - outer node. So it is convenient if we work around the fact that - c_parser_statement calls add_stmt. */ - -static tree -c_parser_omp_structured_block (c_parser *parser, bool *if_p) -{ - tree stmt = push_stmt_list (); - c_parser_statement (parser, if_p); - return pop_stmt_list (stmt); -} - -/* OpenACC 2.0: - # pragma acc cache (variable-list) new-line - - LOC is the location of the #pragma token. -*/ - -static tree -c_parser_oacc_cache (location_t loc, c_parser *parser) -{ - tree stmt, clauses; - - clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE__CACHE_, NULL); - clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); - - c_parser_skip_to_pragma_eol (parser); - - stmt = make_node (OACC_CACHE); - TREE_TYPE (stmt) = void_type_node; - OACC_CACHE_CLAUSES (stmt) = clauses; - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); - - return stmt; -} - -/* OpenACC 2.0: - # pragma acc data oacc-data-clause[optseq] new-line - structured-block - - LOC is the location of the #pragma token. -*/ - -#define OACC_DATA_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT)) - -static tree -c_parser_oacc_data (location_t loc, c_parser *parser, bool *if_p) -{ - tree stmt, clauses, block; - - clauses = c_parser_oacc_all_clauses (parser, OACC_DATA_CLAUSE_MASK, - "#pragma acc data"); - - block = c_begin_omp_parallel (); - add_stmt (c_parser_omp_structured_block (parser, if_p)); - - stmt = c_finish_oacc_data (loc, clauses, block); - - return stmt; -} - -/* OpenACC 2.0: - # pragma acc declare oacc-data-clause[optseq] new-line -*/ - -#define OACC_DECLARE_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_LINK) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT)) - -static void -c_parser_oacc_declare (c_parser *parser) -{ - location_t pragma_loc = c_parser_peek_token (parser)->location; - tree clauses, stmt, t, decl; - - bool error = false; - - c_parser_consume_pragma (parser); - - clauses = c_parser_oacc_all_clauses (parser, OACC_DECLARE_CLAUSE_MASK, - "#pragma acc declare"); - if (!clauses) - { - error_at (pragma_loc, - "no valid clauses specified in %<#pragma acc declare%>"); - return; - } - - for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t)) - { - location_t loc = OMP_CLAUSE_LOCATION (t); - decl = OMP_CLAUSE_DECL (t); - if (!DECL_P (decl)) - { - error_at (loc, "array section in %<#pragma acc declare%>"); - error = true; - continue; - } - - switch (OMP_CLAUSE_MAP_KIND (t)) - { - case GOMP_MAP_FIRSTPRIVATE_POINTER: - case GOMP_MAP_ALLOC: - case GOMP_MAP_TO: - case GOMP_MAP_FORCE_DEVICEPTR: - case GOMP_MAP_DEVICE_RESIDENT: - break; - - case GOMP_MAP_LINK: - if (!global_bindings_p () - && (TREE_STATIC (decl) - || !DECL_EXTERNAL (decl))) - { - error_at (loc, - "%qD must be a global variable in " - "%<#pragma acc declare link%>", - decl); - error = true; - continue; - } - break; - - default: - if (global_bindings_p ()) - { - error_at (loc, "invalid OpenACC clause at file scope"); - error = true; - continue; - } - if (DECL_EXTERNAL (decl)) - { - error_at (loc, - "invalid use of % variable %qD " - "in %<#pragma acc declare%>", decl); - error = true; - continue; - } - else if (TREE_PUBLIC (decl)) - { - error_at (loc, - "invalid use of % variable %qD " - "in %<#pragma acc declare%>", decl); - error = true; - continue; - } - break; - } - - if (!c_check_in_current_scope (decl)) - { - error_at (loc, - "%qD must be a variable declared in the same scope as " - "%<#pragma acc declare%>", decl); - error = true; - continue; - } - - if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl)) - || lookup_attribute ("omp declare target link", - DECL_ATTRIBUTES (decl))) - { - error_at (loc, "variable %qD used more than once with " - "%<#pragma acc declare%>", decl); - error = true; - continue; - } - - if (!error) - { - tree id; - - if (OMP_CLAUSE_MAP_KIND (t) == GOMP_MAP_LINK) - id = get_identifier ("omp declare target link"); - else - id = get_identifier ("omp declare target"); - - DECL_ATTRIBUTES (decl) - = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (decl)); - - if (global_bindings_p ()) - { - symtab_node *node = symtab_node::get (decl); - if (node != NULL) - { - node->offloadable = 1; - if (ENABLE_OFFLOADING) - { - g->have_offload = true; - if (is_a (node)) - vec_safe_push (offload_vars, decl); - } - } - } - } - } - - if (error || global_bindings_p ()) - return; - - stmt = make_node (OACC_DECLARE); - TREE_TYPE (stmt) = void_type_node; - OACC_DECLARE_CLAUSES (stmt) = clauses; - SET_EXPR_LOCATION (stmt, pragma_loc); - - add_stmt (stmt); - - return; -} - -/* OpenACC 2.0: - # pragma acc enter data oacc-enter-data-clause[optseq] new-line - - or - - # pragma acc exit data oacc-exit-data-clause[optseq] new-line - - - LOC is the location of the #pragma token. -*/ - -#define OACC_ENTER_DATA_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) - -#define OACC_EXIT_DATA_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DELETE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DETACH) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FINALIZE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) - -static void -c_parser_oacc_enter_exit_data (c_parser *parser, bool enter) -{ - location_t loc = c_parser_peek_token (parser)->location; - tree clauses, stmt; - const char *p = ""; - - c_parser_consume_pragma (parser); - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - c_parser_consume_token (parser); - } - - if (strcmp (p, "data") != 0) - { - error_at (loc, "expected % after %<#pragma acc %s%>", - enter ? "enter" : "exit"); - parser->error = true; - c_parser_skip_to_pragma_eol (parser); - return; - } - - if (enter) - clauses = c_parser_oacc_all_clauses (parser, OACC_ENTER_DATA_CLAUSE_MASK, - "#pragma acc enter data"); - else - clauses = c_parser_oacc_all_clauses (parser, OACC_EXIT_DATA_CLAUSE_MASK, - "#pragma acc exit data"); - - if (omp_find_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE) - { - error_at (loc, "%<#pragma acc %s data%> has no data movement clause", - enter ? "enter" : "exit"); - return; - } - - stmt = enter ? make_node (OACC_ENTER_DATA) : make_node (OACC_EXIT_DATA); - TREE_TYPE (stmt) = void_type_node; - OMP_STANDALONE_CLAUSES (stmt) = clauses; - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); -} - - -/* OpenACC 2.0: - # pragma acc host_data oacc-data-clause[optseq] new-line - structured-block -*/ - -#define OACC_HOST_DATA_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_USE_DEVICE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) ) - -static tree -c_parser_oacc_host_data (location_t loc, c_parser *parser, bool *if_p) -{ - tree stmt, clauses, block; - - clauses = c_parser_oacc_all_clauses (parser, OACC_HOST_DATA_CLAUSE_MASK, - "#pragma acc host_data"); - - block = c_begin_omp_parallel (); - add_stmt (c_parser_omp_structured_block (parser, if_p)); - stmt = c_finish_oacc_host_data (loc, clauses, block); - return stmt; -} - - -/* OpenACC 2.0: - - # pragma acc loop oacc-loop-clause[optseq] new-line - structured-block - - LOC is the location of the #pragma token. -*/ - -#define OACC_LOOP_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COLLAPSE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_AUTO) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_INDEPENDENT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_TILE) ) -static tree -c_parser_oacc_loop (location_t loc, c_parser *parser, char *p_name, - omp_clause_mask mask, tree *cclauses, bool *if_p) -{ - bool is_parallel = ((mask >> PRAGMA_OACC_CLAUSE_REDUCTION) & 1) == 1; - - strcat (p_name, " loop"); - mask |= OACC_LOOP_CLAUSE_MASK; - - tree clauses = c_parser_oacc_all_clauses (parser, mask, p_name, - cclauses == NULL); - if (cclauses) - { - clauses = c_oacc_split_loop_clauses (clauses, cclauses, is_parallel); - if (*cclauses) - *cclauses = c_finish_omp_clauses (*cclauses, C_ORT_ACC); - if (clauses) - clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); - } - - tree block = c_begin_compound_stmt (true); - tree stmt = c_parser_omp_for_loop (loc, parser, OACC_LOOP, clauses, NULL, - if_p); - block = c_end_compound_stmt (loc, block, true); - add_stmt (block); - - return stmt; -} - -/* OpenACC 2.0: - # pragma acc kernels oacc-kernels-clause[optseq] new-line - structured-block - - or - - # pragma acc parallel oacc-parallel-clause[optseq] new-line - structured-block - - OpenACC 2.6: - - # pragma acc serial oacc-serial-clause[optseq] new-line - structured-block - - LOC is the location of the #pragma token. -*/ - -#define OACC_KERNELS_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) - -#define OACC_PARALLEL_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) - -#define OACC_SERIAL_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) - -static tree -c_parser_oacc_compute (location_t loc, c_parser *parser, - enum pragma_kind p_kind, char *p_name, bool *if_p) -{ - omp_clause_mask mask; - enum tree_code code; - switch (p_kind) - { - case PRAGMA_OACC_KERNELS: - strcat (p_name, " kernels"); - mask = OACC_KERNELS_CLAUSE_MASK; - code = OACC_KERNELS; - break; - case PRAGMA_OACC_PARALLEL: - strcat (p_name, " parallel"); - mask = OACC_PARALLEL_CLAUSE_MASK; - code = OACC_PARALLEL; - break; - case PRAGMA_OACC_SERIAL: - strcat (p_name, " serial"); - mask = OACC_SERIAL_CLAUSE_MASK; - code = OACC_SERIAL; - break; - default: - gcc_unreachable (); - } - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "loop") == 0) - { - c_parser_consume_token (parser); - tree block = c_begin_omp_parallel (); - tree clauses; - c_parser_oacc_loop (loc, parser, p_name, mask, &clauses, if_p); - return c_finish_omp_construct (loc, code, block, clauses); - } - } - - tree clauses = c_parser_oacc_all_clauses (parser, mask, p_name); - - tree block = c_begin_omp_parallel (); - add_stmt (c_parser_omp_structured_block (parser, if_p)); - - return c_finish_omp_construct (loc, code, block, clauses); -} - -/* OpenACC 2.0: - # pragma acc routine oacc-routine-clause[optseq] new-line - function-definition - - # pragma acc routine ( name ) oacc-routine-clause[optseq] new-line -*/ - -#define OACC_ROUTINE_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NOHOST) ) - -/* Parse an OpenACC routine directive. For named directives, we apply - immediately to the named function. For unnamed ones we then parse - a declaration or definition, which must be for a function. */ - -static void -c_parser_oacc_routine (c_parser *parser, enum pragma_context context) -{ - gcc_checking_assert (context == pragma_external); - - oacc_routine_data data; - data.error_seen = false; - data.fndecl_seen = false; - data.loc = c_parser_peek_token (parser)->location; - - c_parser_consume_pragma (parser); - - /* Look for optional '( name )'. */ - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - c_parser_consume_token (parser); /* '(' */ - - tree decl = NULL_TREE; - c_token *name_token = c_parser_peek_token (parser); - location_t name_loc = name_token->location; - if (name_token->type == CPP_NAME - && (name_token->id_kind == C_ID_ID - || name_token->id_kind == C_ID_TYPENAME)) - { - decl = lookup_name (name_token->value); - if (!decl) - error_at (name_loc, - "%qE has not been declared", name_token->value); - c_parser_consume_token (parser); - } - else - c_parser_error (parser, "expected function name"); - - if (!decl - || !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - { - c_parser_skip_to_pragma_eol (parser, false); - return; - } - - data.clauses - = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, - "#pragma acc routine"); - /* The clauses are in reverse order; fix that to make later diagnostic - emission easier. */ - data.clauses = nreverse (data.clauses); - - if (TREE_CODE (decl) != FUNCTION_DECL) - { - error_at (name_loc, "%qD does not refer to a function", decl); - return; - } - - c_finish_oacc_routine (&data, decl, false); - } - else /* No optional '( name )'. */ - { - data.clauses - = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, - "#pragma acc routine"); - /* The clauses are in reverse order; fix that to make later diagnostic - emission easier. */ - data.clauses = nreverse (data.clauses); - - /* Emit a helpful diagnostic if there's another pragma following this - one. Also don't allow a static assertion declaration, as in the - following we'll just parse a *single* "declaration or function - definition", and the static assertion counts an one. */ - if (c_parser_next_token_is (parser, CPP_PRAGMA) - || c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) - { - error_at (data.loc, - "%<#pragma acc routine%> not immediately followed by" - " function declaration or definition"); - /* ..., and then just keep going. */ - return; - } - - /* We only have to consider the pragma_external case here. */ - if (c_parser_next_token_is (parser, CPP_KEYWORD) - && c_parser_peek_token (parser)->keyword == RID_EXTENSION) - { - int ext = disable_extension_diagnostics (); - do - c_parser_consume_token (parser); - while (c_parser_next_token_is (parser, CPP_KEYWORD) - && c_parser_peek_token (parser)->keyword == RID_EXTENSION); - c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, NULL, false, NULL, &data); - restore_extension_diagnostics (ext); - } - else - c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, NULL, false, NULL, &data); - } -} - -/* Finalize an OpenACC routine pragma, applying it to FNDECL. - IS_DEFN is true if we're applying it to the definition. */ - -static void -c_finish_oacc_routine (struct oacc_routine_data *data, tree fndecl, - bool is_defn) -{ - /* Keep going if we're in error reporting mode. */ - if (data->error_seen - || fndecl == error_mark_node) - return; - - if (data->fndecl_seen) - { - error_at (data->loc, - "%<#pragma acc routine%> not immediately followed by" - " a single function declaration or definition"); - data->error_seen = true; - return; - } - if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) - { - error_at (data->loc, - "%<#pragma acc routine%> not immediately followed by" - " function declaration or definition"); - data->error_seen = true; - return; - } - - int compatible - = oacc_verify_routine_clauses (fndecl, &data->clauses, data->loc, - "#pragma acc routine"); - if (compatible < 0) - { - data->error_seen = true; - return; - } - if (compatible > 0) - { - } - else - { - if (TREE_USED (fndecl) || (!is_defn && DECL_SAVED_TREE (fndecl))) - { - error_at (data->loc, - TREE_USED (fndecl) - ? G_("%<#pragma acc routine%> must be applied before use") - : G_("%<#pragma acc routine%> must be applied before" - " definition")); - data->error_seen = true; - return; - } - - /* Set the routine's level of parallelism. */ - tree dims = oacc_build_routine_dims (data->clauses); - oacc_replace_fn_attrib (fndecl, dims); - - /* Add an "omp declare target" attribute. */ - DECL_ATTRIBUTES (fndecl) - = tree_cons (get_identifier ("omp declare target"), - data->clauses, DECL_ATTRIBUTES (fndecl)); - } - - /* Remember that we've used this "#pragma acc routine". */ - data->fndecl_seen = true; -} - -/* OpenACC 2.0: - # pragma acc update oacc-update-clause[optseq] new-line -*/ - -#define OACC_UPDATE_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_HOST) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) - -static void -c_parser_oacc_update (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - - c_parser_consume_pragma (parser); - - tree clauses = c_parser_oacc_all_clauses (parser, OACC_UPDATE_CLAUSE_MASK, - "#pragma acc update"); - if (omp_find_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE) - { - error_at (loc, - "%<#pragma acc update%> must contain at least one " - "% or % or % clause"); - return; - } - - if (parser->error) - return; - - tree stmt = make_node (OACC_UPDATE); - TREE_TYPE (stmt) = void_type_node; - OACC_UPDATE_CLAUSES (stmt) = clauses; - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); -} - -/* OpenACC 2.0: - # pragma acc wait [(intseq)] oacc-wait-clause[optseq] new-line - - LOC is the location of the #pragma token. -*/ - -#define OACC_WAIT_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) ) - -static tree -c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name) -{ - tree clauses, list = NULL_TREE, stmt = NULL_TREE; - - if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) - list = c_parser_oacc_wait_list (parser, loc, list); - - strcpy (p_name, " wait"); - clauses = c_parser_oacc_all_clauses (parser, OACC_WAIT_CLAUSE_MASK, p_name); - stmt = c_finish_oacc_wait (loc, list, clauses); - add_stmt (stmt); - - return stmt; -} - -/* OpenMP 5.0: - # pragma omp allocate (list) [allocator(allocator)] */ - -static void -c_parser_omp_allocate (location_t loc, c_parser *parser) -{ - tree allocator = NULL_TREE; - tree nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ALLOCATE, NULL_TREE); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - matching_parens parens; - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - c_parser_consume_token (parser); - if (strcmp ("allocator", p) != 0) - error_at (c_parser_peek_token (parser)->location, - "expected %"); - else if (parens.require_open (parser)) - { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - allocator = expr.value; - allocator = c_fully_fold (allocator, false, NULL); - tree orig_type - = expr.original_type ? expr.original_type : TREE_TYPE (allocator); - orig_type = TYPE_MAIN_VARIANT (orig_type); - if (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) - || TREE_CODE (orig_type) != ENUMERAL_TYPE - || TYPE_NAME (orig_type) - != get_identifier ("omp_allocator_handle_t")) - { - error_at (expr_loc, "% clause allocator expression " - "has type %qT rather than " - "%", - TREE_TYPE (allocator)); - allocator = NULL_TREE; - } - parens.skip_until_found_close (parser); - } - } - c_parser_skip_to_pragma_eol (parser); - - if (allocator) - for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; - - sorry_at (loc, "%<#pragma omp allocate%> not yet supported"); -} - -/* OpenMP 2.5: - # pragma omp atomic new-line - expression-stmt - - expression-stmt: - x binop= expr | x++ | ++x | x-- | --x - binop: - +, *, -, /, &, ^, |, <<, >> - - where x is an lvalue expression with scalar type. - - OpenMP 3.1: - # pragma omp atomic new-line - update-stmt - - # pragma omp atomic read new-line - read-stmt - - # pragma omp atomic write new-line - write-stmt - - # pragma omp atomic update new-line - update-stmt - - # pragma omp atomic capture new-line - capture-stmt - - # pragma omp atomic capture new-line - capture-block - - read-stmt: - v = x - write-stmt: - x = expr - update-stmt: - expression-stmt | x = x binop expr - capture-stmt: - v = expression-stmt - capture-block: - { v = x; update-stmt; } | { update-stmt; v = x; } - - OpenMP 4.0: - update-stmt: - expression-stmt | x = x binop expr | x = expr binop x - capture-stmt: - v = update-stmt - capture-block: - { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } - - OpenMP 5.1: - # pragma omp atomic compare new-line - conditional-update-atomic - - # pragma omp atomic compare capture new-line - conditional-update-capture-atomic - - conditional-update-atomic: - cond-expr-stmt | cond-update-stmt - cond-expr-stmt: - x = expr ordop x ? expr : x; - x = x ordop expr ? expr : x; - x = x == e ? d : x; - cond-update-stmt: - if (expr ordop x) { x = expr; } - if (x ordop expr) { x = expr; } - if (x == e) { x = d; } - ordop: - <, > - conditional-update-capture-atomic: - v = cond-expr-stmt - { v = x; cond-expr-stmt } - { cond-expr-stmt v = x; } - { v = x; cond-update-stmt } - { cond-update-stmt v = x; } - if (x == e) { x = d; } else { v = x; } - { r = x == e; if (r) { x = d; } } - { r = x == e; if (r) { x = d; } else { v = x; } } - - where x, r and v are lvalue expressions with scalar type, - expr, e and d are expressions with scalar type and e might be - the same as v. - - LOC is the location of the #pragma token. */ - -static void -c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) -{ - tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, r = NULL_TREE; - tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; - tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE; - enum tree_code code = ERROR_MARK, opcode = NOP_EXPR; - enum omp_memory_order memory_order = OMP_MEMORY_ORDER_UNSPECIFIED; - struct c_expr expr; - location_t eloc; - bool structured_block = false; - bool swapped = false; - bool non_lvalue_p; - bool first = true; - tree clauses = NULL_TREE; - bool capture = false; - bool compare = false; - bool weak = false; - enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED; - bool no_semicolon = false; - bool extra_scope = false; - - while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - { - if (!first - && c_parser_next_token_is (parser, CPP_COMMA) - && c_parser_peek_2nd_token (parser)->type == CPP_NAME) - c_parser_consume_token (parser); - - first = false; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - location_t cloc = c_parser_peek_token (parser)->location; - enum tree_code new_code = ERROR_MARK; - enum omp_memory_order new_memory_order - = OMP_MEMORY_ORDER_UNSPECIFIED; - bool new_capture = false; - bool new_compare = false; - bool new_weak = false; - enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED; - - if (!strcmp (p, "read")) - new_code = OMP_ATOMIC_READ; - else if (!strcmp (p, "write")) - new_code = NOP_EXPR; - else if (!strcmp (p, "update")) - new_code = OMP_ATOMIC; - else if (openacc && !strcmp (p, "capture")) - new_code = OMP_ATOMIC_CAPTURE_NEW; - else if (openacc) - { - p = NULL; - error_at (cloc, "expected %, %, %, " - "or % clause"); - } - else if (!strcmp (p, "capture")) - new_capture = true; - else if (!strcmp (p, "compare")) - new_compare = true; - else if (!strcmp (p, "weak")) - new_weak = true; - else if (!strcmp (p, "fail")) - { - matching_parens parens; - - c_parser_consume_token (parser); - if (!parens.require_open (parser)) - continue; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *q - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - if (!strcmp (q, "seq_cst")) - new_fail = OMP_MEMORY_ORDER_SEQ_CST; - else if (!strcmp (q, "acquire")) - new_fail = OMP_MEMORY_ORDER_ACQUIRE; - else if (!strcmp (q, "relaxed")) - new_fail = OMP_MEMORY_ORDER_RELAXED; - } - - if (new_fail != OMP_MEMORY_ORDER_UNSPECIFIED) - { - c_parser_consume_token (parser); - if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) - error_at (cloc, "too many %qs clauses", "fail"); - else - fail = new_fail; - } - else - c_parser_error (parser, "expected %, % " - "or %"); - parens.skip_until_found_close (parser); - continue; - } - else if (!strcmp (p, "seq_cst")) - new_memory_order = OMP_MEMORY_ORDER_SEQ_CST; - else if (!strcmp (p, "acq_rel")) - new_memory_order = OMP_MEMORY_ORDER_ACQ_REL; - else if (!strcmp (p, "release")) - new_memory_order = OMP_MEMORY_ORDER_RELEASE; - else if (!strcmp (p, "acquire")) - new_memory_order = OMP_MEMORY_ORDER_ACQUIRE; - else if (!strcmp (p, "relaxed")) - new_memory_order = OMP_MEMORY_ORDER_RELAXED; - else if (!strcmp (p, "hint")) - { - c_parser_consume_token (parser); - clauses = c_parser_omp_clause_hint (parser, clauses); - continue; - } - else - { - p = NULL; - error_at (cloc, "expected %, %, %, " - "%, %, %, %, " - "%, %, %, " - "% or % clause"); - } - if (p) - { - if (new_code != ERROR_MARK) - { - /* OpenACC permits 'update capture'. */ - if (openacc - && code == OMP_ATOMIC - && new_code == OMP_ATOMIC_CAPTURE_NEW) - code = new_code; - else if (code != ERROR_MARK) - error_at (cloc, "too many atomic clauses"); - else - code = new_code; - } - else if (new_memory_order != OMP_MEMORY_ORDER_UNSPECIFIED) - { - if (memory_order != OMP_MEMORY_ORDER_UNSPECIFIED) - error_at (cloc, "too many memory order clauses"); - else - memory_order = new_memory_order; - } - else if (new_capture) - { - if (capture) - error_at (cloc, "too many %qs clauses", "capture"); - else - capture = true; - } - else if (new_compare) - { - if (compare) - error_at (cloc, "too many %qs clauses", "compare"); - else - compare = true; - } - else if (new_weak) - { - if (weak) - error_at (cloc, "too many %qs clauses", "weak"); - else - weak = true; - } - c_parser_consume_token (parser); - continue; - } - } - break; - } - c_parser_skip_to_pragma_eol (parser); - - if (code == ERROR_MARK) - code = OMP_ATOMIC; - if (capture) - { - if (code != OMP_ATOMIC) - error_at (loc, "%qs clause is incompatible with % or % " - "clauses", "capture"); - else - code = OMP_ATOMIC_CAPTURE_NEW; - } - if (compare && code != OMP_ATOMIC && code != OMP_ATOMIC_CAPTURE_NEW) - { - error_at (loc, "%qs clause is incompatible with % or % " - "clauses", "compare"); - compare = false; - } - if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare) - { - error_at (loc, "%qs clause requires %qs clause", "fail", "compare"); - fail = OMP_MEMORY_ORDER_UNSPECIFIED; - } - if (weak && !compare) - { - error_at (loc, "%qs clause requires %qs clause", "weak", "compare"); - weak = false; - } - if (openacc) - memory_order = OMP_MEMORY_ORDER_RELAXED; - else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED) - { - omp_requires_mask - = (enum omp_requires) (omp_requires_mask - | OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED); - switch ((enum omp_memory_order) - (omp_requires_mask & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER)) - { - case OMP_MEMORY_ORDER_UNSPECIFIED: - case OMP_MEMORY_ORDER_RELAXED: - memory_order = OMP_MEMORY_ORDER_RELAXED; - break; - case OMP_MEMORY_ORDER_SEQ_CST: - memory_order = OMP_MEMORY_ORDER_SEQ_CST; - break; - case OMP_MEMORY_ORDER_ACQ_REL: - switch (code) - { - case OMP_ATOMIC_READ: - memory_order = OMP_MEMORY_ORDER_ACQUIRE; - break; - case NOP_EXPR: /* atomic write */ - memory_order = OMP_MEMORY_ORDER_RELEASE; - break; - default: - memory_order = OMP_MEMORY_ORDER_ACQ_REL; - break; - } - break; - default: - gcc_unreachable (); - } - } - else - switch (code) - { - case OMP_ATOMIC_READ: - if (memory_order == OMP_MEMORY_ORDER_RELEASE) - { - error_at (loc, "%<#pragma omp atomic read%> incompatible with " - "% clause"); - memory_order = OMP_MEMORY_ORDER_SEQ_CST; - } - else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) - memory_order = OMP_MEMORY_ORDER_ACQUIRE; - break; - case NOP_EXPR: /* atomic write */ - if (memory_order == OMP_MEMORY_ORDER_ACQUIRE) - { - error_at (loc, "%<#pragma omp atomic write%> incompatible with " - "% clause"); - memory_order = OMP_MEMORY_ORDER_SEQ_CST; - } - else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) - memory_order = OMP_MEMORY_ORDER_RELEASE; - break; - default: - break; - } - if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) - memory_order - = (enum omp_memory_order) (memory_order - | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT)); - - switch (code) - { - case OMP_ATOMIC_READ: - case NOP_EXPR: /* atomic write */ - v = c_parser_cast_expression (parser, NULL).value; - non_lvalue_p = !lvalue_p (v); - v = c_fully_fold (v, false, NULL, true); - if (v == error_mark_node) - goto saw_error; - if (non_lvalue_p) - v = non_lvalue (v); - loc = c_parser_peek_token (parser)->location; - if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) - goto saw_error; - if (code == NOP_EXPR) - { - lhs = c_parser_expression (parser).value; - lhs = c_fully_fold (lhs, false, NULL); - if (lhs == error_mark_node) - goto saw_error; - } - else - { - lhs = c_parser_cast_expression (parser, NULL).value; - non_lvalue_p = !lvalue_p (lhs); - lhs = c_fully_fold (lhs, false, NULL, true); - if (lhs == error_mark_node) - goto saw_error; - if (non_lvalue_p) - lhs = non_lvalue (lhs); - } - if (code == NOP_EXPR) - { - /* atomic write is represented by OMP_ATOMIC with NOP_EXPR - opcode. */ - code = OMP_ATOMIC; - rhs = lhs; - lhs = v; - v = NULL_TREE; - } - goto done; - case OMP_ATOMIC_CAPTURE_NEW: - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - { - c_parser_consume_token (parser); - structured_block = true; - } - else if (compare - && c_parser_next_token_is_keyword (parser, RID_IF)) - break; - else - { - v = c_parser_cast_expression (parser, NULL).value; - non_lvalue_p = !lvalue_p (v); - v = c_fully_fold (v, false, NULL, true); - if (v == error_mark_node) - goto saw_error; - if (non_lvalue_p) - v = non_lvalue (v); - if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) - goto saw_error; - if (compare && c_parser_next_token_is_keyword (parser, RID_IF)) - { - eloc = c_parser_peek_token (parser)->location; - error_at (eloc, "expected expression"); - goto saw_error; - } - } - break; - default: - break; - } - - /* For structured_block case we don't know yet whether - old or new x should be captured. */ -restart: - if (compare && c_parser_next_token_is_keyword (parser, RID_IF)) - { - c_parser_consume_token (parser); - - matching_parens parens; - if (!parens.require_open (parser)) - goto saw_error; - eloc = c_parser_peek_token (parser)->location; - c_expr cmp_expr; - if (r) - { - cmp_expr = c_parser_cast_expression (parser, NULL); - cmp_expr = default_function_array_conversion (eloc, cmp_expr); - } - else - cmp_expr = c_parser_binary_expression (parser, NULL, void_list_node); - parens.skip_until_found_close (parser); - if (cmp_expr.value == error_mark_node) - goto saw_error; - if (r) - { - if (!c_tree_equal (cmp_expr.value, unfolded_lhs)) - goto bad_if; - cmp_expr.value = rhs1; - rhs1 = NULL_TREE; - gcc_assert (TREE_CODE (cmp_expr.value) == EQ_EXPR); - } - if (TREE_CODE (cmp_expr.value) == EQ_EXPR) - ; - else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW) - { - error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), - "expected %<==%> comparison in % condition"); - goto saw_error; - } - else if (TREE_CODE (cmp_expr.value) != GT_EXPR - && TREE_CODE (cmp_expr.value) != LT_EXPR) - { - error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), - "expected %<==%>, %<<%> or %<>%> comparison in % " - "condition"); - goto saw_error; - } - if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) - goto saw_error; - - extra_scope = true; - eloc = c_parser_peek_token (parser)->location; - expr = c_parser_cast_expression (parser, NULL); - lhs = expr.value; - expr = default_function_array_conversion (eloc, expr); - unfolded_lhs = expr.value; - lhs = c_fully_fold (lhs, false, NULL, true); - orig_lhs = lhs; - if (lhs == error_mark_node) - goto saw_error; - if (!lvalue_p (unfolded_lhs)) - lhs = non_lvalue (lhs); - if (!c_parser_next_token_is (parser, CPP_EQ)) - { - c_parser_error (parser, "expected %<=%>"); - goto saw_error; - } - c_parser_consume_token (parser); - eloc = c_parser_peek_token (parser)->location; - expr = c_parser_expr_no_commas (parser, NULL); - rhs1 = expr.value; - - if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) - goto saw_error; - - if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>")) - goto saw_error; - - extra_scope = false; - no_semicolon = true; - - if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), unfolded_lhs)) - { - if (TREE_CODE (cmp_expr.value) == EQ_EXPR) - { - opcode = COND_EXPR; - rhs = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1), - false, NULL, true); - rhs1 = c_fully_fold (rhs1, false, NULL, true); - } - else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), rhs1)) - { - opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR - ? MIN_EXPR : MAX_EXPR); - rhs = c_fully_fold (rhs1, false, NULL, true); - rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 0), - false, NULL, true); - } - else - goto bad_if; - } - else if (TREE_CODE (cmp_expr.value) == EQ_EXPR) - goto bad_if; - else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), unfolded_lhs) - && c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), rhs1)) - { - opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR - ? MAX_EXPR : MIN_EXPR); - rhs = c_fully_fold (rhs1, false, NULL, true); - rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1), - false, NULL, true); - } - else - { - bad_if: - c_parser_error (parser, - "invalid form of %<#pragma omp atomic compare%>"); - goto saw_error; - } - - if (c_parser_next_token_is_keyword (parser, RID_ELSE)) - { - if (code != OMP_ATOMIC_CAPTURE_NEW - || (structured_block && r == NULL_TREE) - || TREE_CODE (cmp_expr.value) != EQ_EXPR) - { - eloc = c_parser_peek_token (parser)->location; - error_at (eloc, "unexpected %"); - goto saw_error; - } - - c_parser_consume_token (parser); - - if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) - goto saw_error; - - extra_scope = true; - v = c_parser_cast_expression (parser, NULL).value; - non_lvalue_p = !lvalue_p (v); - v = c_fully_fold (v, false, NULL, true); - if (v == error_mark_node) - goto saw_error; - if (non_lvalue_p) - v = non_lvalue (v); - if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) - goto saw_error; - - expr = c_parser_expr_no_commas (parser, NULL); - - if (!c_tree_equal (expr.value, unfolded_lhs)) - goto bad_if; - - if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) - goto saw_error; - - if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>")) - goto saw_error; - - extra_scope = false; - code = OMP_ATOMIC_CAPTURE_OLD; - if (r == NULL_TREE) - /* Signal to c_finish_omp_atomic that in - if (x == e) { x = d; } else { v = x; } - case the store to v should be conditional. */ - r = void_list_node; - } - else if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) - { - c_parser_require_keyword (parser, RID_ELSE, "expected %"); - goto saw_error; - } - else if (code == OMP_ATOMIC_CAPTURE_NEW - && r != NULL_TREE - && v == NULL_TREE) - code = OMP_ATOMIC; - goto stmt_done; - } - eloc = c_parser_peek_token (parser)->location; - expr = c_parser_cast_expression (parser, NULL); - lhs = expr.value; - expr = default_function_array_conversion (eloc, expr); - unfolded_lhs = expr.value; - lhs = c_fully_fold (lhs, false, NULL, true); - orig_lhs = lhs; - switch (TREE_CODE (lhs)) - { - invalid_compare: - error_at (eloc, "invalid form of %"); - /* FALLTHRU */ - case ERROR_MARK: - saw_error: - c_parser_skip_to_end_of_block_or_statement (parser); - if (extra_scope && c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - c_parser_consume_token (parser); - if (structured_block) - { - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - c_parser_consume_token (parser); - else if (code == OMP_ATOMIC_CAPTURE_NEW) - { - c_parser_skip_to_end_of_block_or_statement (parser); - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - c_parser_consume_token (parser); - } - } - return; - - case POSTINCREMENT_EXPR: - if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) - code = OMP_ATOMIC_CAPTURE_OLD; - /* FALLTHROUGH */ - case PREINCREMENT_EXPR: - lhs = TREE_OPERAND (lhs, 0); - unfolded_lhs = NULL_TREE; - opcode = PLUS_EXPR; - rhs = integer_one_node; - if (compare) - goto invalid_compare; - break; - - case POSTDECREMENT_EXPR: - if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) - code = OMP_ATOMIC_CAPTURE_OLD; - /* FALLTHROUGH */ - case PREDECREMENT_EXPR: - lhs = TREE_OPERAND (lhs, 0); - unfolded_lhs = NULL_TREE; - opcode = MINUS_EXPR; - rhs = integer_one_node; - if (compare) - goto invalid_compare; - break; - - case COMPOUND_EXPR: - if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR - && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR - && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR - && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0) - && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND - (TREE_OPERAND (lhs, 1), 0), 0))) - == BOOLEAN_TYPE) - /* Undo effects of boolean_increment for post {in,de}crement. */ - lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0); - /* FALLTHRU */ - case MODIFY_EXPR: - if (TREE_CODE (lhs) == MODIFY_EXPR - && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE) - { - /* Undo effects of boolean_increment. */ - if (integer_onep (TREE_OPERAND (lhs, 1))) - { - /* This is pre or post increment. */ - rhs = TREE_OPERAND (lhs, 1); - lhs = TREE_OPERAND (lhs, 0); - unfolded_lhs = NULL_TREE; - opcode = NOP_EXPR; - if (code == OMP_ATOMIC_CAPTURE_NEW - && !structured_block - && TREE_CODE (orig_lhs) == COMPOUND_EXPR) - code = OMP_ATOMIC_CAPTURE_OLD; - if (compare) - goto invalid_compare; - break; - } - if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR - && TREE_OPERAND (lhs, 0) - == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) - { - /* This is pre or post decrement. */ - rhs = TREE_OPERAND (lhs, 1); - lhs = TREE_OPERAND (lhs, 0); - unfolded_lhs = NULL_TREE; - opcode = NOP_EXPR; - if (code == OMP_ATOMIC_CAPTURE_NEW - && !structured_block - && TREE_CODE (orig_lhs) == COMPOUND_EXPR) - code = OMP_ATOMIC_CAPTURE_OLD; - if (compare) - goto invalid_compare; - break; - } - } - /* FALLTHRU */ - default: - if (!lvalue_p (unfolded_lhs)) - lhs = non_lvalue (lhs); - if (compare && !c_parser_next_token_is (parser, CPP_EQ)) - { - c_parser_error (parser, "expected %<=%>"); - goto saw_error; - } - switch (c_parser_peek_token (parser)->type) - { - case CPP_MULT_EQ: - opcode = MULT_EXPR; - break; - case CPP_DIV_EQ: - opcode = TRUNC_DIV_EXPR; - break; - case CPP_PLUS_EQ: - opcode = PLUS_EXPR; - break; - case CPP_MINUS_EQ: - opcode = MINUS_EXPR; - break; - case CPP_LSHIFT_EQ: - opcode = LSHIFT_EXPR; - break; - case CPP_RSHIFT_EQ: - opcode = RSHIFT_EXPR; - break; - case CPP_AND_EQ: - opcode = BIT_AND_EXPR; - break; - case CPP_OR_EQ: - opcode = BIT_IOR_EXPR; - break; - case CPP_XOR_EQ: - opcode = BIT_XOR_EXPR; - break; - case CPP_EQ: - c_parser_consume_token (parser); - eloc = c_parser_peek_token (parser)->location; - expr = c_parser_expr_no_commas (parser, NULL, unfolded_lhs); - rhs1 = expr.value; - switch (TREE_CODE (rhs1)) - { - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case RDIV_EXPR: - case PLUS_EXPR: - case MINUS_EXPR: - case LSHIFT_EXPR: - case RSHIFT_EXPR: - case BIT_AND_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - if (compare) - break; - if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs)) - { - opcode = TREE_CODE (rhs1); - rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, - true); - rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL, - true); - goto stmt_done; - } - if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs)) - { - opcode = TREE_CODE (rhs1); - rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL, - true); - rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, - true); - swapped = !commutative_tree_code (opcode); - goto stmt_done; - } - break; - case COND_EXPR: - if (!compare) - break; - if (TREE_CODE (TREE_OPERAND (rhs1, 0)) != GT_EXPR - && TREE_CODE (TREE_OPERAND (rhs1, 0)) != LT_EXPR - && TREE_CODE (TREE_OPERAND (rhs1, 0)) != EQ_EXPR) - break; - if (!TREE_OPERAND (rhs1, 1)) - break; - if (!c_tree_equal (TREE_OPERAND (rhs1, 2), unfolded_lhs)) - break; - if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0), - unfolded_lhs)) - { - if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR) - { - opcode = COND_EXPR; - rhs = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, - 0), 1), - false, NULL, true); - rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, - NULL, true); - goto stmt_done; - } - if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), - TREE_OPERAND (rhs1, 1))) - { - opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR - ? MIN_EXPR : MAX_EXPR); - rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, - true); - rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, - 0), 0), - false, NULL, true); - goto stmt_done; - } - } - else if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR) - break; - else if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), - unfolded_lhs)) - { - if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0), - TREE_OPERAND (rhs1, 1))) - { - opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR - ? MAX_EXPR : MIN_EXPR); - rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, - true); - rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, - 0), 1), - false, NULL, true); - goto stmt_done; - } - } - break; - case EQ_EXPR: - if (!compare - || code != OMP_ATOMIC_CAPTURE_NEW - || !structured_block - || v - || r) - break; - if (c_parser_next_token_is (parser, CPP_SEMICOLON) - && c_parser_peek_2nd_token (parser)->keyword == RID_IF) - { - r = lhs; - lhs = NULL_TREE; - c_parser_consume_token (parser); - goto restart; - } - break; - case ERROR_MARK: - goto saw_error; - default: - break; - } - if (c_parser_peek_token (parser)->type == CPP_SEMICOLON) - { - if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) - { - code = OMP_ATOMIC_CAPTURE_OLD; - v = lhs; - lhs = NULL_TREE; - expr = default_function_array_read_conversion (eloc, expr); - unfolded_lhs1 = expr.value; - lhs1 = c_fully_fold (unfolded_lhs1, false, NULL, true); - rhs1 = NULL_TREE; - c_parser_consume_token (parser); - goto restart; - } - if (structured_block && !compare) - { - opcode = NOP_EXPR; - expr = default_function_array_read_conversion (eloc, expr); - rhs = c_fully_fold (expr.value, false, NULL, true); - rhs1 = NULL_TREE; - goto stmt_done; - } - } - c_parser_error (parser, "invalid form of %<#pragma omp atomic%>"); - goto saw_error; - default: - c_parser_error (parser, - "invalid operator for %<#pragma omp atomic%>"); - goto saw_error; - } - - /* Arrange to pass the location of the assignment operator to - c_finish_omp_atomic. */ - loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - eloc = c_parser_peek_token (parser)->location; - expr = c_parser_expression (parser); - expr = default_function_array_read_conversion (eloc, expr); - rhs = expr.value; - rhs = c_fully_fold (rhs, false, NULL, true); - break; - } -stmt_done: - if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW && r == NULL_TREE) - { - if (!no_semicolon - && !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) - goto saw_error; - no_semicolon = false; - v = c_parser_cast_expression (parser, NULL).value; - non_lvalue_p = !lvalue_p (v); - v = c_fully_fold (v, false, NULL, true); - if (v == error_mark_node) - goto saw_error; - if (non_lvalue_p) - v = non_lvalue (v); - if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) - goto saw_error; - eloc = c_parser_peek_token (parser)->location; - expr = c_parser_cast_expression (parser, NULL); - lhs1 = expr.value; - expr = default_function_array_read_conversion (eloc, expr); - unfolded_lhs1 = expr.value; - lhs1 = c_fully_fold (lhs1, false, NULL, true); - if (lhs1 == error_mark_node) - goto saw_error; - if (!lvalue_p (unfolded_lhs1)) - lhs1 = non_lvalue (lhs1); - } - if (structured_block) - { - if (!no_semicolon) - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); - } -done: - if (weak && opcode != COND_EXPR) - { - error_at (loc, "% clause requires atomic equality comparison"); - weak = false; - } - if (unfolded_lhs && unfolded_lhs1 - && !c_tree_equal (unfolded_lhs, unfolded_lhs1)) - { - error ("%<#pragma omp atomic capture%> uses two different " - "expressions for memory"); - stmt = error_mark_node; - } - else - stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, r, - swapped, memory_order, weak); - if (stmt != error_mark_node) - add_stmt (stmt); - - if (!structured_block && !no_semicolon) - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); -} - - -/* OpenMP 2.5: - # pragma omp barrier new-line -*/ - -static void -c_parser_omp_barrier (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); - - c_finish_omp_barrier (loc); -} - -/* OpenMP 2.5: - # pragma omp critical [(name)] new-line - structured-block - - OpenMP 4.5: - # pragma omp critical [(name) [hint(expression)]] new-line - - LOC is the location of the #pragma itself. */ - -#define OMP_CRITICAL_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HINT) ) - -static tree -c_parser_omp_critical (location_t loc, c_parser *parser, bool *if_p) -{ - tree stmt, name = NULL_TREE, clauses = NULL_TREE; - - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - name = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - } - else - c_parser_error (parser, "expected identifier"); - - if (c_parser_next_token_is (parser, CPP_COMMA) - && c_parser_peek_2nd_token (parser)->type == CPP_NAME) - c_parser_consume_token (parser); - } - clauses = c_parser_omp_all_clauses (parser, OMP_CRITICAL_CLAUSE_MASK, - "#pragma omp critical"); - stmt = c_parser_omp_structured_block (parser, if_p); - return c_finish_omp_critical (loc, stmt, name, clauses); -} - -/* OpenMP 5.0: - # pragma omp depobj ( depobj ) depobj-clause new-line - - depobj-clause: - depend (dependence-type : locator) - destroy - update (dependence-type) - - dependence-type: - in - out - inout - mutexinout */ - -static void -c_parser_omp_depobj (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_pragma (parser); - matching_parens parens; - if (!parens.require_open (parser)) - { - c_parser_skip_to_pragma_eol (parser); - return; - } - - tree depobj = c_parser_expr_no_commas (parser, NULL).value; - if (depobj != error_mark_node) - { - if (!lvalue_p (depobj)) - { - error_at (EXPR_LOC_OR_LOC (depobj, loc), - "% expression is not lvalue expression"); - depobj = error_mark_node; - } - else - { - tree addr = build_unary_op (EXPR_LOC_OR_LOC (depobj, loc), ADDR_EXPR, - depobj, false); - if (addr == error_mark_node) - depobj = error_mark_node; - else - depobj = build_indirect_ref (EXPR_LOC_OR_LOC (depobj, loc), - addr, RO_UNARY_STAR); - } - } - - parens.skip_until_found_close (parser); - tree clause = NULL_TREE; - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE; - location_t c_loc = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - c_parser_consume_token (parser); - if (!strcmp ("depend", p)) - { - clause = c_parser_omp_clause_depend (parser, NULL_TREE); - clause = c_finish_omp_clauses (clause, C_ORT_OMP); - if (!clause) - clause = error_mark_node; - } - else if (!strcmp ("destroy", p)) - kind = OMP_CLAUSE_DEPEND_LAST; - else if (!strcmp ("update", p)) - { - matching_parens c_parens; - if (c_parens.require_open (parser)) - { - location_t c2_loc = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p2 - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - c_parser_consume_token (parser); - if (!strcmp ("in", p2)) - kind = OMP_CLAUSE_DEPEND_IN; - else if (!strcmp ("out", p2)) - kind = OMP_CLAUSE_DEPEND_OUT; - else if (!strcmp ("inout", p2)) - kind = OMP_CLAUSE_DEPEND_INOUT; - else if (!strcmp ("mutexinoutset", p2)) - kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; - } - if (kind == OMP_CLAUSE_DEPEND_SOURCE) - { - clause = error_mark_node; - error_at (c2_loc, "expected %, %, % or " - "%"); - } - c_parens.skip_until_found_close (parser); - } - else - clause = error_mark_node; - } - } - if (!clause && kind == OMP_CLAUSE_DEPEND_SOURCE) - { - clause = error_mark_node; - error_at (c_loc, "expected %, % or % clause"); - } - c_parser_skip_to_pragma_eol (parser); - - c_finish_omp_depobj (loc, depobj, kind, clause); -} - - -/* OpenMP 2.5: - # pragma omp flush flush-vars[opt] new-line - - flush-vars: - ( variable-list ) - - OpenMP 5.0: - # pragma omp flush memory-order-clause new-line */ - -static void -c_parser_omp_flush (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_pragma (parser); - enum memmodel mo = MEMMODEL_LAST; - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - if (!strcmp (p, "seq_cst")) - mo = MEMMODEL_SEQ_CST; - else if (!strcmp (p, "acq_rel")) - mo = MEMMODEL_ACQ_REL; - else if (!strcmp (p, "release")) - mo = MEMMODEL_RELEASE; - else if (!strcmp (p, "acquire")) - mo = MEMMODEL_ACQUIRE; - else - error_at (c_parser_peek_token (parser)->location, - "expected %, %, % or " - "%"); - c_parser_consume_token (parser); - } - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - if (mo != MEMMODEL_LAST) - error_at (c_parser_peek_token (parser)->location, - "% list specified together with memory order " - "clause"); - c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); - } - else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - c_parser_error (parser, "expected %<(%> or end of line"); - c_parser_skip_to_pragma_eol (parser); - - c_finish_omp_flush (loc, mo); -} - -/* Parse an OpenMP structured block sequence. KIND is the corresponding - separating directive. */ - -static tree -c_parser_omp_structured_block_sequence (c_parser *parser, - enum pragma_kind kind) -{ - tree stmt = push_stmt_list (); - c_parser_statement (parser, NULL); - do - { - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - break; - if (c_parser_next_token_is (parser, CPP_EOF)) - break; - - if (kind != PRAGMA_NONE - && c_parser_peek_token (parser)->pragma_kind == kind) - break; - c_parser_statement (parser, NULL); - } - while (1); - return pop_stmt_list (stmt); -} - -/* OpenMP 5.0: - - scan-loop-body: - { structured-block scan-directive structured-block } */ - -static void -c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed) -{ - tree substmt; - location_t loc; - tree clauses = NULL_TREE; - - loc = c_parser_peek_token (parser)->location; - if (!open_brace_parsed - && !c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) - { - /* Avoid skipping until the end of the block. */ - parser->error = false; - return; - } - - substmt = c_parser_omp_structured_block_sequence (parser, PRAGMA_OMP_SCAN); - substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE); - SET_EXPR_LOCATION (substmt, loc); - add_stmt (substmt); - - loc = c_parser_peek_token (parser)->location; - if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SCAN) - { - enum omp_clause_code clause = OMP_CLAUSE_ERROR; - - c_parser_consume_pragma (parser); - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "inclusive") == 0) - clause = OMP_CLAUSE_INCLUSIVE; - else if (strcmp (p, "exclusive") == 0) - clause = OMP_CLAUSE_EXCLUSIVE; - } - if (clause != OMP_CLAUSE_ERROR) - { - c_parser_consume_token (parser); - clauses = c_parser_omp_var_list_parens (parser, clause, NULL_TREE); - } - else - c_parser_error (parser, "expected % or " - "% clause"); - c_parser_skip_to_pragma_eol (parser); - } - else - error ("expected %<#pragma omp scan%>"); - - clauses = c_finish_omp_clauses (clauses, C_ORT_OMP); - substmt = c_parser_omp_structured_block_sequence (parser, PRAGMA_NONE); - substmt = build2 (OMP_SCAN, void_type_node, substmt, clauses); - SET_EXPR_LOCATION (substmt, loc); - add_stmt (substmt); - - c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, - "expected %<}%>"); -} - -/* Parse the restricted form of loop statements allowed by OpenACC and OpenMP. - The real trick here is to determine the loop control variable early - so that we can push a new decl if necessary to make it private. - LOC is the location of the "acc" or "omp" in "#pragma acc" or "#pragma omp", - respectively. */ - -static tree -c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, - tree clauses, tree *cclauses, bool *if_p) -{ - tree decl, cond, incr, body, init, stmt, cl; - unsigned char save_in_statement; - tree declv, condv, incrv, initv, ret = NULL_TREE; - tree pre_body = NULL_TREE, this_pre_body; - tree ordered_cl = NULL_TREE; - bool fail = false, open_brace_parsed = false; - int i, collapse = 1, ordered = 0, count, nbraces = 0; - location_t for_loc; - bool tiling = false; - bool inscan = false; - vec *for_block = make_tree_vector (); - - for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) - if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) - collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); - else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_TILE) - { - tiling = true; - collapse = list_length (OMP_CLAUSE_TILE_LIST (cl)); - } - else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED - && OMP_CLAUSE_ORDERED_EXPR (cl)) - { - ordered_cl = cl; - ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (cl)); - } - else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_REDUCTION - && OMP_CLAUSE_REDUCTION_INSCAN (cl) - && (code == OMP_SIMD || code == OMP_FOR)) - inscan = true; - - if (ordered && ordered < collapse) - { - error_at (OMP_CLAUSE_LOCATION (ordered_cl), - "% clause parameter is less than %"); - OMP_CLAUSE_ORDERED_EXPR (ordered_cl) - = build_int_cst (NULL_TREE, collapse); - ordered = collapse; - } - if (ordered) - { - for (tree *pc = &clauses; *pc; ) - if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR) - { - error_at (OMP_CLAUSE_LOCATION (*pc), - "% clause may not be specified together " - "with % clause with a parameter"); - *pc = OMP_CLAUSE_CHAIN (*pc); - } - else - pc = &OMP_CLAUSE_CHAIN (*pc); - } - - gcc_assert (tiling || (collapse >= 1 && ordered >= 0)); - count = ordered ? ordered : collapse; - - declv = make_tree_vec (count); - initv = make_tree_vec (count); - condv = make_tree_vec (count); - incrv = make_tree_vec (count); - - if (!c_parser_next_token_is_keyword (parser, RID_FOR)) - { - c_parser_error (parser, "for statement expected"); - return NULL; - } - for_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - - /* Forbid break/continue in the loop initializer, condition, and - increment expressions. */ - save_in_statement = in_statement; - in_statement = IN_OMP_BLOCK; - - for (i = 0; i < count; i++) - { - int bracecount = 0; - - matching_parens parens; - if (!parens.require_open (parser)) - goto pop_scopes; - - /* Parse the initialization declaration or expression. */ - if (c_parser_next_tokens_start_declaration (parser)) - { - if (i > 0) - vec_safe_push (for_block, c_begin_compound_stmt (true)); - this_pre_body = push_stmt_list (); - c_in_omp_for = true; - c_parser_declaration_or_fndef (parser, true, true, true, true, true); - c_in_omp_for = false; - if (this_pre_body) - { - this_pre_body = pop_stmt_list (this_pre_body); - if (pre_body) - { - tree t = pre_body; - pre_body = push_stmt_list (); - add_stmt (t); - add_stmt (this_pre_body); - pre_body = pop_stmt_list (pre_body); - } - else - pre_body = this_pre_body; - } - decl = check_for_loop_decls (for_loc, flag_isoc99); - if (decl == NULL) - goto error_init; - if (DECL_INITIAL (decl) == error_mark_node) - decl = error_mark_node; - init = decl; - } - else if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_EQ) - { - struct c_expr decl_exp; - struct c_expr init_exp; - location_t init_loc; - - decl_exp = c_parser_postfix_expression (parser); - decl = decl_exp.value; - - c_parser_require (parser, CPP_EQ, "expected %<=%>"); - - init_loc = c_parser_peek_token (parser)->location; - init_exp = c_parser_expr_no_commas (parser, NULL); - init_exp = default_function_array_read_conversion (init_loc, - init_exp); - c_in_omp_for = true; - init = build_modify_expr (init_loc, decl, decl_exp.original_type, - NOP_EXPR, init_loc, init_exp.value, - init_exp.original_type); - c_in_omp_for = false; - init = c_process_expr_stmt (init_loc, init); - - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - } - else - { - error_init: - c_parser_error (parser, - "expected iteration declaration or initialization"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - fail = true; - goto parse_next; - } - - /* Parse the loop condition. */ - cond = NULL_TREE; - if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) - { - location_t cond_loc = c_parser_peek_token (parser)->location; - c_in_omp_for = true; - struct c_expr cond_expr - = c_parser_binary_expression (parser, NULL, NULL_TREE); - c_in_omp_for = false; - - cond = cond_expr.value; - cond = c_objc_common_truthvalue_conversion (cond_loc, cond); - switch (cond_expr.original_code) - { - case GT_EXPR: - case GE_EXPR: - case LT_EXPR: - case LE_EXPR: - break; - case NE_EXPR: - if (code != OACC_LOOP) - break; - /* FALLTHRU. */ - default: - /* Can't be cond = error_mark_node, because we want to preserve - the location until c_finish_omp_for. */ - cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node); - break; - } - protected_set_expr_location (cond, cond_loc); - } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - - /* Parse the increment expression. */ - incr = NULL_TREE; - if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) - { - location_t incr_loc = c_parser_peek_token (parser)->location; - - incr = c_process_expr_stmt (incr_loc, - c_parser_expression (parser).value); - } - parens.skip_until_found_close (parser); - - if (decl == NULL || decl == error_mark_node || init == error_mark_node) - fail = true; - else - { - TREE_VEC_ELT (declv, i) = decl; - TREE_VEC_ELT (initv, i) = init; - TREE_VEC_ELT (condv, i) = cond; - TREE_VEC_ELT (incrv, i) = incr; - } - - parse_next: - if (i == count - 1) - break; - - /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed - in between the collapsed for loops to be still considered perfectly - nested. Hopefully the final version clarifies this. - For now handle (multiple) {'s and empty statements. */ - do - { - if (c_parser_next_token_is_keyword (parser, RID_FOR)) - { - c_parser_consume_token (parser); - break; - } - else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - { - c_parser_consume_token (parser); - bracecount++; - } - else if (bracecount - && c_parser_next_token_is (parser, CPP_SEMICOLON)) - c_parser_consume_token (parser); - else - { - c_parser_error (parser, "not enough perfectly nested loops"); - if (bracecount) - { - open_brace_parsed = true; - bracecount--; - } - fail = true; - count = 0; - break; - } - } - while (1); - - nbraces += bracecount; - } - - if (nbraces) - if_p = NULL; - - in_statement = IN_OMP_FOR; - body = push_stmt_list (); - - if (inscan) - c_parser_omp_scan_loop_body (parser, open_brace_parsed); - else if (open_brace_parsed) - { - location_t here = c_parser_peek_token (parser)->location; - stmt = c_begin_compound_stmt (true); - c_parser_compound_statement_nostart (parser); - add_stmt (c_end_compound_stmt (here, stmt, true)); - } - else - add_stmt (c_parser_c99_block_statement (parser, if_p)); - - body = pop_stmt_list (body); - in_statement = save_in_statement; - - while (nbraces) - { - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - c_parser_consume_token (parser); - nbraces--; - } - else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - c_parser_consume_token (parser); - else - { - c_parser_error (parser, "collapsed loops not perfectly nested"); - while (nbraces) - { - location_t here = c_parser_peek_token (parser)->location; - stmt = c_begin_compound_stmt (true); - add_stmt (body); - c_parser_compound_statement_nostart (parser); - body = c_end_compound_stmt (here, stmt, true); - nbraces--; - } - goto pop_scopes; - } - } - - /* Only bother calling c_finish_omp_for if we haven't already generated - an error from the initialization parsing. */ - if (!fail) - { - c_in_omp_for = true; - stmt = c_finish_omp_for (loc, code, declv, NULL, initv, condv, - incrv, body, pre_body, true); - c_in_omp_for = false; - - /* Check for iterators appearing in lb, b or incr expressions. */ - if (stmt && !c_omp_check_loop_iv (stmt, declv, NULL)) - stmt = NULL_TREE; - - if (stmt) - { - add_stmt (stmt); - - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++) - { - tree init = TREE_VEC_ELT (OMP_FOR_INIT (stmt), i); - gcc_assert (TREE_CODE (init) == MODIFY_EXPR); - tree decl = TREE_OPERAND (init, 0); - tree cond = TREE_VEC_ELT (OMP_FOR_COND (stmt), i); - gcc_assert (COMPARISON_CLASS_P (cond)); - gcc_assert (TREE_OPERAND (cond, 0) == decl); - - tree op0 = TREE_OPERAND (init, 1); - if (!OMP_FOR_NON_RECTANGULAR (stmt) - || TREE_CODE (op0) != TREE_VEC) - TREE_OPERAND (init, 1) = c_fully_fold (op0, false, NULL); - else - { - TREE_VEC_ELT (op0, 1) - = c_fully_fold (TREE_VEC_ELT (op0, 1), false, NULL); - TREE_VEC_ELT (op0, 2) - = c_fully_fold (TREE_VEC_ELT (op0, 2), false, NULL); - } - - tree op1 = TREE_OPERAND (cond, 1); - if (!OMP_FOR_NON_RECTANGULAR (stmt) - || TREE_CODE (op1) != TREE_VEC) - TREE_OPERAND (cond, 1) = c_fully_fold (op1, false, NULL); - else - { - TREE_VEC_ELT (op1, 1) - = c_fully_fold (TREE_VEC_ELT (op1, 1), false, NULL); - TREE_VEC_ELT (op1, 2) - = c_fully_fold (TREE_VEC_ELT (op1, 2), false, NULL); - } - } - - if (cclauses != NULL - && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL) - { - tree *c; - for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) - if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE - && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE) - c = &OMP_CLAUSE_CHAIN (*c); - else - { - for (i = 0; i < count; i++) - if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c)) - break; - if (i == count) - c = &OMP_CLAUSE_CHAIN (*c); - else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE) - { - error_at (loc, - "iteration variable %qD should not be firstprivate", - OMP_CLAUSE_DECL (*c)); - *c = OMP_CLAUSE_CHAIN (*c); - } - else - { - /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */ - tree l = *c; - *c = OMP_CLAUSE_CHAIN (*c); - if (code == OMP_SIMD) - { - OMP_CLAUSE_CHAIN (l) - = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; - cclauses[C_OMP_CLAUSE_SPLIT_FOR] = l; - } - else - { - OMP_CLAUSE_CHAIN (l) = clauses; - clauses = l; - } - } - } - } - OMP_FOR_CLAUSES (stmt) = clauses; - } - ret = stmt; - } -pop_scopes: - while (!for_block->is_empty ()) - { - /* FIXME diagnostics: LOC below should be the actual location of - this particular for block. We need to build a list of - locations to go along with FOR_BLOCK. */ - stmt = c_end_compound_stmt (loc, for_block->pop (), true); - add_stmt (stmt); - } - release_tree_vector (for_block); - return ret; -} - -/* Helper function for OpenMP parsing, split clauses and call - finish_omp_clauses on each of the set of clauses afterwards. */ - -static void -omp_split_clauses (location_t loc, enum tree_code code, - omp_clause_mask mask, tree clauses, tree *cclauses) -{ - int i; - c_omp_split_clauses (loc, code, mask, clauses, cclauses); - for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) - if (cclauses[i]) - cclauses[i] = c_finish_omp_clauses (cclauses[i], - i == C_OMP_CLAUSE_SPLIT_TARGET - ? C_ORT_OMP_TARGET : C_ORT_OMP); -} - -/* OpenMP 5.0: - #pragma omp loop loop-clause[optseq] new-line - for-loop - - LOC is the location of the #pragma token. -*/ - -#define OMP_LOOP_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_BIND) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) - -static tree -c_parser_omp_loop (location_t loc, c_parser *parser, - char *p_name, omp_clause_mask mask, tree *cclauses, - bool *if_p) -{ - tree block, clauses, ret; - - strcat (p_name, " loop"); - mask |= OMP_LOOP_CLAUSE_MASK; - - clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - if (cclauses) - { - omp_split_clauses (loc, OMP_LOOP, mask, clauses, cclauses); - clauses = cclauses[C_OMP_CLAUSE_SPLIT_LOOP]; - } - - block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (loc, parser, OMP_LOOP, clauses, cclauses, if_p); - block = c_end_compound_stmt (loc, block, true); - add_stmt (block); - - return ret; -} - -/* OpenMP 4.0: - #pragma omp simd simd-clause[optseq] new-line - for-loop - - LOC is the location of the #pragma token. -*/ - -#define OMP_SIMD_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONTEMPORAL) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) - -static tree -c_parser_omp_simd (location_t loc, c_parser *parser, - char *p_name, omp_clause_mask mask, tree *cclauses, - bool *if_p) -{ - tree block, clauses, ret; - - strcat (p_name, " simd"); - mask |= OMP_SIMD_CLAUSE_MASK; - - clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - if (cclauses) - { - omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); - clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; - tree c = omp_find_clause (cclauses[C_OMP_CLAUSE_SPLIT_FOR], - OMP_CLAUSE_ORDERED); - if (c && OMP_CLAUSE_ORDERED_EXPR (c)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% clause with parameter may not be specified " - "on %qs construct", p_name); - OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE; - } - } - - block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, cclauses, if_p); - block = c_end_compound_stmt (loc, block, true); - add_stmt (block); - - return ret; -} - -/* OpenMP 2.5: - #pragma omp for for-clause[optseq] new-line - for-loop - - OpenMP 4.0: - #pragma omp for simd for-simd-clause[optseq] new-line - for-loop - - LOC is the location of the #pragma token. -*/ - -#define OMP_FOR_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) - -static tree -c_parser_omp_for (location_t loc, c_parser *parser, - char *p_name, omp_clause_mask mask, tree *cclauses, - bool *if_p) -{ - tree block, clauses, ret; - - strcat (p_name, " for"); - mask |= OMP_FOR_CLAUSE_MASK; - /* parallel for{, simd} disallows nowait clause, but for - target {teams distribute ,}parallel for{, simd} it should be accepted. */ - if (cclauses && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) == 0) - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); - /* Composite distribute parallel for{, simd} disallows ordered clause. */ - if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - if (strcmp (p, "simd") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; - - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, - if_p); - block = c_begin_compound_stmt (true); - ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, if_p); - block = c_end_compound_stmt (loc, block, true); - if (ret == NULL_TREE) - return ret; - ret = make_node (OMP_FOR); - TREE_TYPE (ret) = void_type_node; - OMP_FOR_BODY (ret) = block; - OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; - SET_EXPR_LOCATION (ret, loc); - add_stmt (ret); - return ret; - } - } - if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; - } - - /* Composite distribute parallel for disallows linear clause. */ - if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR); - - clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - if (cclauses) - { - omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); - clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; - } - - block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (loc, parser, OMP_FOR, clauses, cclauses, if_p); - block = c_end_compound_stmt (loc, block, true); - add_stmt (block); - - return ret; -} - -static tree c_parser_omp_taskloop (location_t, c_parser *, char *, - omp_clause_mask, tree *, bool *); - -/* OpenMP 2.5: - # pragma omp master new-line - structured-block - - LOC is the location of the #pragma token. -*/ - -static tree -c_parser_omp_master (location_t loc, c_parser *parser, - char *p_name, omp_clause_mask mask, tree *cclauses, - bool *if_p) -{ - tree block, clauses, ret; - - strcat (p_name, " master"); - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - if (strcmp (p, "taskloop") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; - - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, - if_p); - block = c_begin_compound_stmt (true); - ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, - if_p); - block = c_end_compound_stmt (loc, block, true); - if (ret == NULL_TREE) - return ret; - ret = c_finish_omp_master (loc, block); - OMP_MASTER_COMBINED (ret) = 1; - return ret; - } - } - if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; - } - - if (cclauses) - { - clauses = c_parser_omp_all_clauses (parser, mask, p_name, false); - omp_split_clauses (loc, OMP_MASTER, mask, clauses, cclauses); - } - else - c_parser_skip_to_pragma_eol (parser); - - return c_finish_omp_master (loc, c_parser_omp_structured_block (parser, - if_p)); -} - -/* OpenMP 5.1: - # pragma omp masked masked-clauses new-line - structured-block - - LOC is the location of the #pragma token. -*/ - -#define OMP_MASKED_CLAUSE_MASK \ - (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) - -static tree -c_parser_omp_masked (location_t loc, c_parser *parser, - char *p_name, omp_clause_mask mask, tree *cclauses, - bool *if_p) -{ - tree block, clauses, ret; - - strcat (p_name, " masked"); - mask |= OMP_MASKED_CLAUSE_MASK; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - if (strcmp (p, "taskloop") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; - - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, - if_p); - block = c_begin_compound_stmt (true); - ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, - if_p); - block = c_end_compound_stmt (loc, block, true); - if (ret == NULL_TREE) - return ret; - ret = c_finish_omp_masked (loc, block, - cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); - OMP_MASKED_COMBINED (ret) = 1; - return ret; - } - } - if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; - } - - clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - if (cclauses) - { - omp_split_clauses (loc, OMP_MASKED, mask, clauses, cclauses); - clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; - } - - return c_finish_omp_masked (loc, c_parser_omp_structured_block (parser, - if_p), - clauses); -} - -/* OpenMP 2.5: - # pragma omp ordered new-line - structured-block - - OpenMP 4.5: - # pragma omp ordered ordered-clauses new-line - structured-block - - # pragma omp ordered depend-clauses new-line */ - -#define OMP_ORDERED_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD)) - -#define OMP_ORDERED_DEPEND_CLAUSE_MASK \ - (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) - -static bool -c_parser_omp_ordered (c_parser *parser, enum pragma_context context, - bool *if_p) -{ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_pragma (parser); - - if (context != pragma_stmt && context != pragma_compound) - { - c_parser_error (parser, "expected declaration specifiers"); - c_parser_skip_to_pragma_eol (parser, false); - return false; - } - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - if (!strcmp ("depend", p)) - { - if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return false; - } - if (context == pragma_stmt) - { - error_at (loc, - "%<#pragma omp ordered%> with % clause may " - "only be used in compound statements"); - c_parser_skip_to_pragma_eol (parser, false); - return true; - } - - tree clauses - = c_parser_omp_all_clauses (parser, - OMP_ORDERED_DEPEND_CLAUSE_MASK, - "#pragma omp ordered"); - c_finish_omp_ordered (loc, clauses, NULL_TREE); - return false; - } - } - - tree clauses = c_parser_omp_all_clauses (parser, OMP_ORDERED_CLAUSE_MASK, - "#pragma omp ordered"); - - if (!flag_openmp /* flag_openmp_simd */ - && omp_find_clause (clauses, OMP_CLAUSE_SIMD) == NULL_TREE) - return false; - - c_finish_omp_ordered (loc, clauses, - c_parser_omp_structured_block (parser, if_p)); - return true; -} - -/* OpenMP 2.5: - - section-scope: - { section-sequence } - - section-sequence: - section-directive[opt] structured-block - section-sequence section-directive structured-block - - OpenMP 5.1 allows structured-block-sequence instead of structured-block. - - SECTIONS_LOC is the location of the #pragma omp sections. */ - -static tree -c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) -{ - tree stmt, substmt; - bool error_suppress = false; - location_t loc; - - loc = c_parser_peek_token (parser)->location; - if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) - { - /* Avoid skipping until the end of the block. */ - parser->error = false; - return NULL_TREE; - } - - stmt = push_stmt_list (); - - if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION) - { - substmt = c_parser_omp_structured_block_sequence (parser, - PRAGMA_OMP_SECTION); - substmt = build1 (OMP_SECTION, void_type_node, substmt); - SET_EXPR_LOCATION (substmt, loc); - add_stmt (substmt); - } - - while (1) - { - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - break; - if (c_parser_next_token_is (parser, CPP_EOF)) - break; - - loc = c_parser_peek_token (parser)->location; - if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) - { - c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); - error_suppress = false; - } - else if (!error_suppress) - { - error_at (loc, "expected %<#pragma omp section%> or %<}%>"); - error_suppress = true; - } - - substmt = c_parser_omp_structured_block_sequence (parser, - PRAGMA_OMP_SECTION); - substmt = build1 (OMP_SECTION, void_type_node, substmt); - SET_EXPR_LOCATION (substmt, loc); - add_stmt (substmt); - } - c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, - "expected %<#pragma omp section%> or %<}%>"); - - substmt = pop_stmt_list (stmt); - - stmt = make_node (OMP_SECTIONS); - SET_EXPR_LOCATION (stmt, sections_loc); - TREE_TYPE (stmt) = void_type_node; - OMP_SECTIONS_BODY (stmt) = substmt; - - return add_stmt (stmt); -} - -/* OpenMP 2.5: - # pragma omp sections sections-clause[optseq] newline - sections-scope - - LOC is the location of the #pragma token. -*/ - -#define OMP_SECTIONS_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) - -static tree -c_parser_omp_sections (location_t loc, c_parser *parser, - char *p_name, omp_clause_mask mask, tree *cclauses) -{ - tree block, clauses, ret; - - strcat (p_name, " sections"); - mask |= OMP_SECTIONS_CLAUSE_MASK; - if (cclauses) - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); - - clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - if (cclauses) - { - omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses); - clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; - } - - block = c_begin_compound_stmt (true); - ret = c_parser_omp_sections_scope (loc, parser); - if (ret) - OMP_SECTIONS_CLAUSES (ret) = clauses; - block = c_end_compound_stmt (loc, block, true); - add_stmt (block); - - return ret; -} - -/* OpenMP 2.5: - # pragma omp parallel parallel-clause[optseq] new-line - structured-block - # pragma omp parallel for parallel-for-clause[optseq] new-line - structured-block - # pragma omp parallel sections parallel-sections-clause[optseq] new-line - structured-block - - OpenMP 4.0: - # pragma omp parallel for simd parallel-for-simd-clause[optseq] new-line - structured-block - - LOC is the location of the #pragma token. -*/ - -#define OMP_PARALLEL_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) - -static tree -c_parser_omp_parallel (location_t loc, c_parser *parser, - char *p_name, omp_clause_mask mask, tree *cclauses, - bool *if_p) -{ - tree stmt, clauses, block; - - strcat (p_name, " parallel"); - mask |= OMP_PARALLEL_CLAUSE_MASK; - /* #pragma omp target parallel{, for, for simd} disallow copyin clause. */ - if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) != 0 - && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0) - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN); - - if (c_parser_next_token_is_keyword (parser, RID_FOR)) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; - - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - return c_parser_omp_for (loc, parser, p_name, mask, cclauses, if_p); - block = c_begin_omp_parallel (); - tree ret = c_parser_omp_for (loc, parser, p_name, mask, cclauses, if_p); - stmt - = c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], - block); - if (ret == NULL_TREE) - return ret; - OMP_PARALLEL_COMBINED (stmt) = 1; - return stmt; - } - /* When combined with distribute, parallel has to be followed by for. - #pragma omp target parallel is allowed though. */ - else if (cclauses - && (mask & (OMP_CLAUSE_MASK_1 - << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) - { - error_at (loc, "expected % after %qs", p_name); - c_parser_skip_to_pragma_eol (parser); - return NULL_TREE; - } - else if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (cclauses == NULL && strcmp (p, "masked") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - cclauses = cclauses_buf; - - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - return c_parser_omp_masked (loc, parser, p_name, mask, cclauses, - if_p); - block = c_begin_omp_parallel (); - tree ret = c_parser_omp_masked (loc, parser, p_name, mask, cclauses, - if_p); - stmt = c_finish_omp_parallel (loc, - cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], - block); - if (ret == NULL) - return ret; - /* masked does have just filter clause, but during gimplification - isn't represented by a gimplification omp context, so for - #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, - so that - #pragma omp parallel masked - #pragma omp taskloop simd lastprivate (x) - isn't confused with - #pragma omp parallel masked taskloop simd lastprivate (x) */ - if (OMP_MASKED_COMBINED (ret)) - OMP_PARALLEL_COMBINED (stmt) = 1; - return stmt; - } - else if (cclauses == NULL && strcmp (p, "master") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - cclauses = cclauses_buf; - - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - return c_parser_omp_master (loc, parser, p_name, mask, cclauses, - if_p); - block = c_begin_omp_parallel (); - tree ret = c_parser_omp_master (loc, parser, p_name, mask, cclauses, - if_p); - stmt = c_finish_omp_parallel (loc, - cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], - block); - if (ret == NULL) - return ret; - /* master doesn't have any clauses and during gimplification - isn't represented by a gimplification omp context, so for - #pragma omp parallel master don't set OMP_PARALLEL_COMBINED, - so that - #pragma omp parallel master - #pragma omp taskloop simd lastprivate (x) - isn't confused with - #pragma omp parallel master taskloop simd lastprivate (x) */ - if (OMP_MASTER_COMBINED (ret)) - OMP_PARALLEL_COMBINED (stmt) = 1; - return stmt; - } - else if (strcmp (p, "loop") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; - - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - return c_parser_omp_loop (loc, parser, p_name, mask, cclauses, - if_p); - block = c_begin_omp_parallel (); - tree ret = c_parser_omp_loop (loc, parser, p_name, mask, cclauses, - if_p); - stmt - = c_finish_omp_parallel (loc, - cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], - block); - if (ret == NULL_TREE) - return ret; - OMP_PARALLEL_COMBINED (stmt) = 1; - return stmt; - } - else if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; - } - else if (cclauses == NULL && strcmp (p, "sections") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - cclauses = cclauses_buf; - - c_parser_consume_token (parser); - block = c_begin_omp_parallel (); - c_parser_omp_sections (loc, parser, p_name, mask, cclauses); - stmt = c_finish_omp_parallel (loc, - cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], - block); - OMP_PARALLEL_COMBINED (stmt) = 1; - return stmt; - } - } - else if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; - } - - clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - if (cclauses) - { - omp_split_clauses (loc, OMP_PARALLEL, mask, clauses, cclauses); - clauses = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; - } - - block = c_begin_omp_parallel (); - c_parser_statement (parser, if_p); - stmt = c_finish_omp_parallel (loc, clauses, block); - - return stmt; -} - -/* OpenMP 2.5: - # pragma omp single single-clause[optseq] new-line - structured-block - - LOC is the location of the #pragma. -*/ - -#define OMP_SINGLE_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) - -static tree -c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) -{ - tree stmt = make_node (OMP_SINGLE); - SET_EXPR_LOCATION (stmt, loc); - TREE_TYPE (stmt) = void_type_node; - - OMP_SINGLE_CLAUSES (stmt) - = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, - "#pragma omp single"); - OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); - - return add_stmt (stmt); -} - -/* OpenMP 5.1: - # pragma omp scope scope-clause[optseq] new-line - structured-block - - LOC is the location of the #pragma. -*/ - -#define OMP_SCOPE_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) - -static tree -c_parser_omp_scope (location_t loc, c_parser *parser, bool *if_p) -{ - tree stmt = make_node (OMP_SCOPE); - SET_EXPR_LOCATION (stmt, loc); - TREE_TYPE (stmt) = void_type_node; - - OMP_SCOPE_CLAUSES (stmt) - = c_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, - "#pragma omp scope"); - OMP_SCOPE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); - - return add_stmt (stmt); -} - -/* OpenMP 3.0: - # pragma omp task task-clause[optseq] new-line - - LOC is the location of the #pragma. -*/ - -#define OMP_TASK_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_AFFINITY)) - -static tree -c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p) -{ - tree clauses, block; - - clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, - "#pragma omp task"); - - block = c_begin_omp_task (); - c_parser_statement (parser, if_p); - return c_finish_omp_task (loc, clauses, block); -} - -/* OpenMP 3.0: - # pragma omp taskwait new-line - - OpenMP 5.0: - # pragma omp taskwait taskwait-clause[optseq] new-line -*/ - -#define OMP_TASKWAIT_CLAUSE_MASK \ - (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) - -static void -c_parser_omp_taskwait (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_pragma (parser); - - tree clauses - = c_parser_omp_all_clauses (parser, OMP_TASKWAIT_CLAUSE_MASK, - "#pragma omp taskwait"); - - if (clauses) - { - tree stmt = make_node (OMP_TASK); - TREE_TYPE (stmt) = void_node; - OMP_TASK_CLAUSES (stmt) = clauses; - OMP_TASK_BODY (stmt) = NULL_TREE; - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); - } - else - c_finish_omp_taskwait (loc); -} - -/* OpenMP 3.1: - # pragma omp taskyield new-line -*/ - -static void -c_parser_omp_taskyield (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); - - c_finish_omp_taskyield (loc); -} - -/* OpenMP 4.0: - # pragma omp taskgroup new-line - - OpenMP 5.0: - # pragma omp taskgroup taskgroup-clause[optseq] new-line -*/ - -#define OMP_TASKGROUP_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASK_REDUCTION)) - -static tree -c_parser_omp_taskgroup (location_t loc, c_parser *parser, bool *if_p) -{ - tree clauses = c_parser_omp_all_clauses (parser, OMP_TASKGROUP_CLAUSE_MASK, - "#pragma omp taskgroup"); - - tree body = c_parser_omp_structured_block (parser, if_p); - return c_finish_omp_taskgroup (loc, body, clauses); -} - -/* OpenMP 4.0: - # pragma omp cancel cancel-clause[optseq] new-line - - LOC is the location of the #pragma. -*/ - -#define OMP_CANCEL_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) - -static void -c_parser_omp_cancel (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - - c_parser_consume_pragma (parser); - tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, - "#pragma omp cancel"); - - c_finish_omp_cancel (loc, clauses); -} - -/* OpenMP 4.0: - # pragma omp cancellation point cancelpt-clause[optseq] new-line - - LOC is the location of the #pragma. -*/ - -#define OMP_CANCELLATION_POINT_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) - -static bool -c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) -{ - location_t loc = c_parser_peek_token (parser)->location; - tree clauses; - bool point_seen = false; - - c_parser_consume_pragma (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "point") == 0) - { - c_parser_consume_token (parser); - point_seen = true; - } - } - if (!point_seen) - { - c_parser_error (parser, "expected %"); - c_parser_skip_to_pragma_eol (parser); - return false; - } - - if (context != pragma_compound) - { - if (context == pragma_stmt) - error_at (loc, - "%<#pragma %s%> may only be used in compound statements", - "omp cancellation point"); - else - c_parser_error (parser, "expected declaration specifiers"); - c_parser_skip_to_pragma_eol (parser, false); - return true; - } - - clauses - = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK, - "#pragma omp cancellation point"); - - c_finish_omp_cancellation_point (loc, clauses); - return true; -} - -/* OpenMP 4.0: - #pragma omp distribute distribute-clause[optseq] new-line - for-loop */ - -#define OMP_DISTRIBUTE_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) - -static tree -c_parser_omp_distribute (location_t loc, c_parser *parser, - char *p_name, omp_clause_mask mask, tree *cclauses, - bool *if_p) -{ - tree clauses, block, ret; - - strcat (p_name, " distribute"); - mask |= OMP_DISTRIBUTE_CLAUSE_MASK; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - bool simd = false; - bool parallel = false; - - if (strcmp (p, "simd") == 0) - simd = true; - else - parallel = strcmp (p, "parallel") == 0; - if (parallel || simd) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - { - if (simd) - return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, - if_p); - else - return c_parser_omp_parallel (loc, parser, p_name, mask, - cclauses, if_p); - } - block = c_begin_compound_stmt (true); - if (simd) - ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, - if_p); - else - ret = c_parser_omp_parallel (loc, parser, p_name, mask, cclauses, - if_p); - block = c_end_compound_stmt (loc, block, true); - if (ret == NULL) - return ret; - ret = make_node (OMP_DISTRIBUTE); - TREE_TYPE (ret) = void_type_node; - OMP_FOR_BODY (ret) = block; - OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; - SET_EXPR_LOCATION (ret, loc); - add_stmt (ret); - return ret; - } - } - if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; - } - - clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - if (cclauses) - { - omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses); - clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; - } - - block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (loc, parser, OMP_DISTRIBUTE, clauses, NULL, - if_p); - block = c_end_compound_stmt (loc, block, true); - add_stmt (block); - - return ret; -} - -/* OpenMP 4.0: - # pragma omp teams teams-clause[optseq] new-line - structured-block */ - -#define OMP_TEAMS_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) - -static tree -c_parser_omp_teams (location_t loc, c_parser *parser, - char *p_name, omp_clause_mask mask, tree *cclauses, - bool *if_p) -{ - tree clauses, block, ret; - - strcat (p_name, " teams"); - mask |= OMP_TEAMS_CLAUSE_MASK; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "distribute") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; - - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - return c_parser_omp_distribute (loc, parser, p_name, mask, - cclauses, if_p); - block = c_begin_omp_parallel (); - ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses, - if_p); - block = c_end_compound_stmt (loc, block, true); - if (ret == NULL) - return ret; - clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; - ret = make_node (OMP_TEAMS); - TREE_TYPE (ret) = void_type_node; - OMP_TEAMS_CLAUSES (ret) = clauses; - OMP_TEAMS_BODY (ret) = block; - OMP_TEAMS_COMBINED (ret) = 1; - SET_EXPR_LOCATION (ret, loc); - return add_stmt (ret); - } - else if (strcmp (p, "loop") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; - - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - return c_parser_omp_loop (loc, parser, p_name, mask, cclauses, - if_p); - block = c_begin_omp_parallel (); - ret = c_parser_omp_loop (loc, parser, p_name, mask, cclauses, if_p); - block = c_end_compound_stmt (loc, block, true); - if (ret == NULL) - return ret; - clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; - ret = make_node (OMP_TEAMS); - TREE_TYPE (ret) = void_type_node; - OMP_TEAMS_CLAUSES (ret) = clauses; - OMP_TEAMS_BODY (ret) = block; - OMP_TEAMS_COMBINED (ret) = 1; - SET_EXPR_LOCATION (ret, loc); - return add_stmt (ret); - } - } - if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; - } - - clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - if (cclauses) - { - omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses); - clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; - } - - tree stmt = make_node (OMP_TEAMS); - TREE_TYPE (stmt) = void_type_node; - OMP_TEAMS_CLAUSES (stmt) = clauses; - block = c_begin_omp_parallel (); - add_stmt (c_parser_omp_structured_block (parser, if_p)); - OMP_TEAMS_BODY (stmt) = c_end_compound_stmt (loc, block, true); - SET_EXPR_LOCATION (stmt, loc); - - return add_stmt (stmt); -} - -/* OpenMP 4.0: - # pragma omp target data target-data-clause[optseq] new-line - structured-block */ - -#define OMP_TARGET_DATA_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR)) - -static tree -c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p) -{ - tree clauses - = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, - "#pragma omp target data"); - c_omp_adjust_map_clauses (clauses, false); - int map_seen = 0; - for (tree *pc = &clauses; *pc;) - { - if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) - switch (OMP_CLAUSE_MAP_KIND (*pc)) - { - case GOMP_MAP_TO: - case GOMP_MAP_ALWAYS_TO: - case GOMP_MAP_FROM: - case GOMP_MAP_ALWAYS_FROM: - case GOMP_MAP_TOFROM: - case GOMP_MAP_ALWAYS_TOFROM: - case GOMP_MAP_ALLOC: - map_seen = 3; - break; - case GOMP_MAP_FIRSTPRIVATE_POINTER: - case GOMP_MAP_ALWAYS_POINTER: - case GOMP_MAP_ATTACH_DETACH: - break; - default: - map_seen |= 1; - error_at (OMP_CLAUSE_LOCATION (*pc), - "%<#pragma omp target data%> with map-type other " - "than %, %, % or % " - "on % clause"); - *pc = OMP_CLAUSE_CHAIN (*pc); - continue; - } - else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_PTR - || OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_ADDR) - map_seen = 3; - pc = &OMP_CLAUSE_CHAIN (*pc); - } - - if (map_seen != 3) - { - if (map_seen == 0) - error_at (loc, - "%<#pragma omp target data%> must contain at least " - "one %, % or % " - "clause"); - return NULL_TREE; - } - - tree stmt = make_node (OMP_TARGET_DATA); - TREE_TYPE (stmt) = void_type_node; - OMP_TARGET_DATA_CLAUSES (stmt) = clauses; - keep_next_level (); - tree block = c_begin_compound_stmt (true); - add_stmt (c_parser_omp_structured_block (parser, if_p)); - OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true); - - SET_EXPR_LOCATION (stmt, loc); - return add_stmt (stmt); -} - -/* OpenMP 4.0: - # pragma omp target update target-update-clause[optseq] new-line */ - -#define OMP_TARGET_UPDATE_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) - -static bool -c_parser_omp_target_update (location_t loc, c_parser *parser, - enum pragma_context context) -{ - if (context == pragma_stmt) - { - error_at (loc, "%<#pragma %s%> may only be used in compound statements", - "omp target update"); - c_parser_skip_to_pragma_eol (parser, false); - return true; - } - - tree clauses - = c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK, - "#pragma omp target update"); - if (omp_find_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE - && omp_find_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE) - { - error_at (loc, - "%<#pragma omp target update%> must contain at least one " - "% or % clauses"); - return false; - } - - tree stmt = make_node (OMP_TARGET_UPDATE); - TREE_TYPE (stmt) = void_type_node; - OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); - return false; -} - -/* OpenMP 4.5: - # pragma omp target enter data target-data-clause[optseq] new-line */ - -#define OMP_TARGET_ENTER_DATA_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) - -static bool -c_parser_omp_target_enter_data (location_t loc, c_parser *parser, - enum pragma_context context) -{ - bool data_seen = false; - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "data") == 0) - { - c_parser_consume_token (parser); - data_seen = true; - } - } - if (!data_seen) - { - c_parser_error (parser, "expected %"); - c_parser_skip_to_pragma_eol (parser); - return false; - } - - if (context == pragma_stmt) - { - error_at (loc, "%<#pragma %s%> may only be used in compound statements", - "omp target enter data"); - c_parser_skip_to_pragma_eol (parser, false); - return true; - } - - tree clauses - = c_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK, - "#pragma omp target enter data"); - c_omp_adjust_map_clauses (clauses, false); - int map_seen = 0; - for (tree *pc = &clauses; *pc;) - { - if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) - switch (OMP_CLAUSE_MAP_KIND (*pc)) - { - case GOMP_MAP_TO: - case GOMP_MAP_ALWAYS_TO: - case GOMP_MAP_ALLOC: - map_seen = 3; - break; - case GOMP_MAP_FIRSTPRIVATE_POINTER: - case GOMP_MAP_ALWAYS_POINTER: - case GOMP_MAP_ATTACH_DETACH: - break; - default: - map_seen |= 1; - error_at (OMP_CLAUSE_LOCATION (*pc), - "%<#pragma omp target enter data%> with map-type other " - "than % or % on % clause"); - *pc = OMP_CLAUSE_CHAIN (*pc); - continue; - } - pc = &OMP_CLAUSE_CHAIN (*pc); - } - - if (map_seen != 3) - { - if (map_seen == 0) - error_at (loc, - "%<#pragma omp target enter data%> must contain at least " - "one % clause"); - return true; - } - - tree stmt = make_node (OMP_TARGET_ENTER_DATA); - TREE_TYPE (stmt) = void_type_node; - OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); - return true; -} - -/* OpenMP 4.5: - # pragma omp target exit data target-data-clause[optseq] new-line */ - -#define OMP_TARGET_EXIT_DATA_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) - -static bool -c_parser_omp_target_exit_data (location_t loc, c_parser *parser, - enum pragma_context context) -{ - bool data_seen = false; - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "data") == 0) - { - c_parser_consume_token (parser); - data_seen = true; - } - } - if (!data_seen) - { - c_parser_error (parser, "expected %"); - c_parser_skip_to_pragma_eol (parser); - return false; - } - - if (context == pragma_stmt) - { - error_at (loc, "%<#pragma %s%> may only be used in compound statements", - "omp target exit data"); - c_parser_skip_to_pragma_eol (parser, false); - return true; - } - - tree clauses - = c_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK, - "#pragma omp target exit data"); - c_omp_adjust_map_clauses (clauses, false); - int map_seen = 0; - for (tree *pc = &clauses; *pc;) - { - if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) - switch (OMP_CLAUSE_MAP_KIND (*pc)) - { - case GOMP_MAP_FROM: - case GOMP_MAP_ALWAYS_FROM: - case GOMP_MAP_RELEASE: - case GOMP_MAP_DELETE: - map_seen = 3; - break; - case GOMP_MAP_FIRSTPRIVATE_POINTER: - case GOMP_MAP_ALWAYS_POINTER: - case GOMP_MAP_ATTACH_DETACH: - break; - default: - map_seen |= 1; - error_at (OMP_CLAUSE_LOCATION (*pc), - "%<#pragma omp target exit data%> with map-type other " - "than %, % or % on %" - " clause"); - *pc = OMP_CLAUSE_CHAIN (*pc); - continue; - } - pc = &OMP_CLAUSE_CHAIN (*pc); - } - - if (map_seen != 3) - { - if (map_seen == 0) - error_at (loc, - "%<#pragma omp target exit data%> must contain at least one " - "% clause"); - return true; - } - - tree stmt = make_node (OMP_TARGET_EXIT_DATA); - TREE_TYPE (stmt) = void_type_node; - OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); - return true; -} - -/* OpenMP 4.0: - # pragma omp target target-clause[optseq] new-line - structured-block */ - -#define OMP_TARGET_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)) - -static bool -c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) -{ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_pragma (parser); - tree *pc = NULL, stmt, block; - - if (context != pragma_stmt && context != pragma_compound) - { - c_parser_error (parser, "expected declaration specifiers"); - c_parser_skip_to_pragma_eol (parser); - return false; - } - - if (flag_openmp) - omp_requires_mask - = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - enum tree_code ccode = ERROR_MARK; - - if (strcmp (p, "teams") == 0) - ccode = OMP_TEAMS; - else if (strcmp (p, "parallel") == 0) - ccode = OMP_PARALLEL; - else if (strcmp (p, "simd") == 0) - ccode = OMP_SIMD; - if (ccode != ERROR_MARK) - { - tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; - char p_name[sizeof ("#pragma omp target teams distribute " - "parallel for simd")]; - - c_parser_consume_token (parser); - strcpy (p_name, "#pragma omp target"); - if (!flag_openmp) /* flag_openmp_simd */ - { - tree stmt; - switch (ccode) - { - case OMP_TEAMS: - stmt = c_parser_omp_teams (loc, parser, p_name, - OMP_TARGET_CLAUSE_MASK, - cclauses, if_p); - break; - case OMP_PARALLEL: - stmt = c_parser_omp_parallel (loc, parser, p_name, - OMP_TARGET_CLAUSE_MASK, - cclauses, if_p); - break; - case OMP_SIMD: - stmt = c_parser_omp_simd (loc, parser, p_name, - OMP_TARGET_CLAUSE_MASK, - cclauses, if_p); - break; - default: - gcc_unreachable (); - } - return stmt != NULL_TREE; - } - keep_next_level (); - tree block = c_begin_compound_stmt (true), ret; - switch (ccode) - { - case OMP_TEAMS: - ret = c_parser_omp_teams (loc, parser, p_name, - OMP_TARGET_CLAUSE_MASK, cclauses, - if_p); - break; - case OMP_PARALLEL: - ret = c_parser_omp_parallel (loc, parser, p_name, - OMP_TARGET_CLAUSE_MASK, cclauses, - if_p); - break; - case OMP_SIMD: - ret = c_parser_omp_simd (loc, parser, p_name, - OMP_TARGET_CLAUSE_MASK, cclauses, - if_p); - break; - default: - gcc_unreachable (); - } - block = c_end_compound_stmt (loc, block, true); - if (ret == NULL_TREE) - return false; - if (ccode == OMP_TEAMS) - /* For combined target teams, ensure the num_teams and - thread_limit clause expressions are evaluated on the host, - before entering the target construct. */ - for (tree c = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; - c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREAD_LIMIT) - for (int i = 0; - i <= (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS); ++i) - if (OMP_CLAUSE_OPERAND (c, i) - && TREE_CODE (OMP_CLAUSE_OPERAND (c, i)) != INTEGER_CST) - { - tree expr = OMP_CLAUSE_OPERAND (c, i); - tree tmp = create_tmp_var_raw (TREE_TYPE (expr)); - expr = build4 (TARGET_EXPR, TREE_TYPE (expr), tmp, - expr, NULL_TREE, NULL_TREE); - add_stmt (expr); - OMP_CLAUSE_OPERAND (c, i) = expr; - tree tc = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (tc) = tmp; - OMP_CLAUSE_CHAIN (tc) - = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; - cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = tc; - } - tree stmt = make_node (OMP_TARGET); - TREE_TYPE (stmt) = void_type_node; - OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; - c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); - OMP_TARGET_BODY (stmt) = block; - OMP_TARGET_COMBINED (stmt) = 1; - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); - pc = &OMP_TARGET_CLAUSES (stmt); - goto check_clauses; - } - else if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return false; - } - else if (strcmp (p, "data") == 0) - { - c_parser_consume_token (parser); - c_parser_omp_target_data (loc, parser, if_p); - return true; - } - else if (strcmp (p, "enter") == 0) - { - c_parser_consume_token (parser); - return c_parser_omp_target_enter_data (loc, parser, context); - } - else if (strcmp (p, "exit") == 0) - { - c_parser_consume_token (parser); - return c_parser_omp_target_exit_data (loc, parser, context); - } - else if (strcmp (p, "update") == 0) - { - c_parser_consume_token (parser); - return c_parser_omp_target_update (loc, parser, context); - } - } - if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return false; - } - - stmt = make_node (OMP_TARGET); - TREE_TYPE (stmt) = void_type_node; - - OMP_TARGET_CLAUSES (stmt) - = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, - "#pragma omp target", false); - for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) - { - tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_DECL (nc) = OMP_CLAUSE_DECL (c); - OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_ALWAYS_TOFROM); - OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = nc; - } - OMP_TARGET_CLAUSES (stmt) - = c_finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET); - c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); - - pc = &OMP_TARGET_CLAUSES (stmt); - keep_next_level (); - block = c_begin_compound_stmt (true); - add_stmt (c_parser_omp_structured_block (parser, if_p)); - OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true); - - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); - -check_clauses: - while (*pc) - { - if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) - switch (OMP_CLAUSE_MAP_KIND (*pc)) - { - case GOMP_MAP_TO: - case GOMP_MAP_ALWAYS_TO: - case GOMP_MAP_FROM: - case GOMP_MAP_ALWAYS_FROM: - case GOMP_MAP_TOFROM: - case GOMP_MAP_ALWAYS_TOFROM: - case GOMP_MAP_ALLOC: - case GOMP_MAP_FIRSTPRIVATE_POINTER: - case GOMP_MAP_ALWAYS_POINTER: - case GOMP_MAP_ATTACH_DETACH: - break; - default: - error_at (OMP_CLAUSE_LOCATION (*pc), - "%<#pragma omp target%> with map-type other " - "than %, %, % or % " - "on % clause"); - *pc = OMP_CLAUSE_CHAIN (*pc); - continue; - } - pc = &OMP_CLAUSE_CHAIN (*pc); - } - cfun->has_omp_target = true; - return true; -} - -/* OpenMP 4.0: - # pragma omp declare simd declare-simd-clauses[optseq] new-line - - OpenMP 5.0: - # pragma omp declare variant (identifier) match(context-selector) new-line - */ - -#define OMP_DECLARE_SIMD_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) - -static void -c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) -{ - c_token *token = c_parser_peek_token (parser); - gcc_assert (token->type == CPP_NAME); - tree kind = token->value; - gcc_assert (strcmp (IDENTIFIER_POINTER (kind), "simd") == 0 - || strcmp (IDENTIFIER_POINTER (kind), "variant") == 0); - - auto_vec clauses; - while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - { - c_token *token = c_parser_peek_token (parser); - if (token->type == CPP_EOF) - { - c_parser_skip_to_pragma_eol (parser); - return; - } - clauses.safe_push (*token); - c_parser_consume_token (parser); - } - clauses.safe_push (*c_parser_peek_token (parser)); - c_parser_skip_to_pragma_eol (parser); - - while (c_parser_next_token_is (parser, CPP_PRAGMA)) - { - if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_DECLARE - || c_parser_peek_2nd_token (parser)->type != CPP_NAME - || c_parser_peek_2nd_token (parser)->value != kind) - { - error ("%<#pragma omp declare %s%> must be followed by " - "function declaration or definition or another " - "%<#pragma omp declare %s%>", - IDENTIFIER_POINTER (kind), IDENTIFIER_POINTER (kind)); - return; - } - c_parser_consume_pragma (parser); - while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - { - c_token *token = c_parser_peek_token (parser); - if (token->type == CPP_EOF) - { - c_parser_skip_to_pragma_eol (parser); - return; - } - clauses.safe_push (*token); - c_parser_consume_token (parser); - } - clauses.safe_push (*c_parser_peek_token (parser)); - c_parser_skip_to_pragma_eol (parser); - } - - /* Make sure nothing tries to read past the end of the tokens. */ - c_token eof_token; - memset (&eof_token, 0, sizeof (eof_token)); - eof_token.type = CPP_EOF; - clauses.safe_push (eof_token); - clauses.safe_push (eof_token); - - switch (context) - { - case pragma_external: - if (c_parser_next_token_is (parser, CPP_KEYWORD) - && c_parser_peek_token (parser)->keyword == RID_EXTENSION) - { - int ext = disable_extension_diagnostics (); - do - c_parser_consume_token (parser); - while (c_parser_next_token_is (parser, CPP_KEYWORD) - && c_parser_peek_token (parser)->keyword == RID_EXTENSION); - c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, &clauses); - restore_extension_diagnostics (ext); - } - else - c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, &clauses); - break; - case pragma_struct: - case pragma_param: - case pragma_stmt: - error ("%<#pragma omp declare %s%> must be followed by " - "function declaration or definition", - IDENTIFIER_POINTER (kind)); - break; - case pragma_compound: - if (c_parser_next_token_is (parser, CPP_KEYWORD) - && c_parser_peek_token (parser)->keyword == RID_EXTENSION) - { - int ext = disable_extension_diagnostics (); - do - c_parser_consume_token (parser); - while (c_parser_next_token_is (parser, CPP_KEYWORD) - && c_parser_peek_token (parser)->keyword == RID_EXTENSION); - if (c_parser_next_tokens_start_declaration (parser)) - { - c_parser_declaration_or_fndef (parser, true, true, true, true, - true, NULL, &clauses); - restore_extension_diagnostics (ext); - break; - } - restore_extension_diagnostics (ext); - } - else if (c_parser_next_tokens_start_declaration (parser)) - { - c_parser_declaration_or_fndef (parser, true, true, true, true, true, - NULL, &clauses); - break; - } - error ("%<#pragma omp declare %s%> must be followed by " - "function declaration or definition", - IDENTIFIER_POINTER (kind)); - break; - default: - gcc_unreachable (); - } -} - -static const char *const omp_construct_selectors[] = { - "simd", "target", "teams", "parallel", "for", NULL }; -static const char *const omp_device_selectors[] = { - "kind", "isa", "arch", NULL }; -static const char *const omp_implementation_selectors[] = { - "vendor", "extension", "atomic_default_mem_order", "unified_address", - "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL }; -static const char *const omp_user_selectors[] = { - "condition", NULL }; - -/* OpenMP 5.0: - - trait-selector: - trait-selector-name[([trait-score:]trait-property[,trait-property[,...]])] - - trait-score: - score(score-expression) */ - -static tree -c_parser_omp_context_selector (c_parser *parser, tree set, tree parms) -{ - tree ret = NULL_TREE; - do - { - tree selector; - if (c_parser_next_token_is (parser, CPP_KEYWORD) - || c_parser_next_token_is (parser, CPP_NAME)) - selector = c_parser_peek_token (parser)->value; - else - { - c_parser_error (parser, "expected trait selector name"); - return error_mark_node; - } - - tree properties = NULL_TREE; - const char *const *selectors = NULL; - bool allow_score = true; - bool allow_user = false; - int property_limit = 0; - enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST, - CTX_PROPERTY_ID, CTX_PROPERTY_EXPR, - CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE; - switch (IDENTIFIER_POINTER (set)[0]) - { - case 'c': /* construct */ - selectors = omp_construct_selectors; - allow_score = false; - property_limit = 1; - property_kind = CTX_PROPERTY_SIMD; - break; - case 'd': /* device */ - selectors = omp_device_selectors; - allow_score = false; - allow_user = true; - property_limit = 3; - property_kind = CTX_PROPERTY_NAME_LIST; - break; - case 'i': /* implementation */ - selectors = omp_implementation_selectors; - allow_user = true; - property_limit = 3; - property_kind = CTX_PROPERTY_NAME_LIST; - break; - case 'u': /* user */ - selectors = omp_user_selectors; - property_limit = 1; - property_kind = CTX_PROPERTY_EXPR; - break; - default: - gcc_unreachable (); - } - for (int i = 0; ; i++) - { - if (selectors[i] == NULL) - { - if (allow_user) - { - property_kind = CTX_PROPERTY_USER; - break; - } - else - { - error_at (c_parser_peek_token (parser)->location, - "selector %qs not allowed for context selector " - "set %qs", IDENTIFIER_POINTER (selector), - IDENTIFIER_POINTER (set)); - c_parser_consume_token (parser); - return error_mark_node; - } - } - if (i == property_limit) - property_kind = CTX_PROPERTY_NONE; - if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0) - break; - } - if (property_kind == CTX_PROPERTY_NAME_LIST - && IDENTIFIER_POINTER (set)[0] == 'i' - && strcmp (IDENTIFIER_POINTER (selector), - "atomic_default_mem_order") == 0) - property_kind = CTX_PROPERTY_ID; - - c_parser_consume_token (parser); - - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - if (property_kind == CTX_PROPERTY_NONE) - { - error_at (c_parser_peek_token (parser)->location, - "selector %qs does not accept any properties", - IDENTIFIER_POINTER (selector)); - return error_mark_node; - } - - matching_parens parens; - parens.require_open (parser); - - c_token *token = c_parser_peek_token (parser); - if (allow_score - && c_parser_next_token_is (parser, CPP_NAME) - && strcmp (IDENTIFIER_POINTER (token->value), "score") == 0 - && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) - { - c_parser_consume_token (parser); - - matching_parens parens2; - parens2.require_open (parser); - tree score = c_parser_expr_no_commas (parser, NULL).value; - parens2.skip_until_found_close (parser); - c_parser_require (parser, CPP_COLON, "expected %<:%>"); - if (score != error_mark_node) - { - mark_exp_read (score); - score = c_fully_fold (score, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (score)) - || TREE_CODE (score) != INTEGER_CST) - error_at (token->location, "score argument must be " - "constant integer expression"); - else if (tree_int_cst_sgn (score) < 0) - error_at (token->location, "score argument must be " - "non-negative"); - else - properties = tree_cons (get_identifier (" score"), - score, properties); - } - token = c_parser_peek_token (parser); - } - - switch (property_kind) - { - tree t; - case CTX_PROPERTY_USER: - do - { - t = c_parser_expr_no_commas (parser, NULL).value; - if (TREE_CODE (t) == STRING_CST) - properties = tree_cons (NULL_TREE, t, properties); - else if (t != error_mark_node) - { - mark_exp_read (t); - t = c_fully_fold (t, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) - || !tree_fits_shwi_p (t)) - error_at (token->location, "property must be " - "constant integer expression or string " - "literal"); - else - properties = tree_cons (NULL_TREE, t, properties); - } - else - return error_mark_node; - - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - while (1); - break; - case CTX_PROPERTY_ID: - if (c_parser_next_token_is (parser, CPP_KEYWORD) - || c_parser_next_token_is (parser, CPP_NAME)) - { - tree prop = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - properties = tree_cons (prop, NULL_TREE, properties); - } - else - { - c_parser_error (parser, "expected identifier"); - return error_mark_node; - } - break; - case CTX_PROPERTY_NAME_LIST: - do - { - tree prop = NULL_TREE, value = NULL_TREE; - if (c_parser_next_token_is (parser, CPP_KEYWORD) - || c_parser_next_token_is (parser, CPP_NAME)) - { - prop = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - } - else if (c_parser_next_token_is (parser, CPP_STRING)) - value = c_parser_string_literal (parser, false, - false).value; - else - { - c_parser_error (parser, "expected identifier or " - "string literal"); - return error_mark_node; - } - - properties = tree_cons (prop, value, properties); - - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - while (1); - break; - case CTX_PROPERTY_EXPR: - t = c_parser_expr_no_commas (parser, NULL).value; - if (t != error_mark_node) - { - mark_exp_read (t); - t = c_fully_fold (t, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) - || !tree_fits_shwi_p (t)) - error_at (token->location, "property must be " - "constant integer expression"); - else - properties = tree_cons (NULL_TREE, t, properties); - } - else - return error_mark_node; - break; - case CTX_PROPERTY_SIMD: - if (parms == NULL_TREE) - { - error_at (token->location, "properties for % " - "selector may not be specified in " - "%"); - return error_mark_node; - } - tree c; - c = c_parser_omp_all_clauses (parser, - OMP_DECLARE_SIMD_CLAUSE_MASK, - "simd", true, 2); - c = c_omp_declare_simd_clauses_to_numbers (parms - == error_mark_node - ? NULL_TREE : parms, - c); - properties = c; - break; - default: - gcc_unreachable (); - } - - parens.skip_until_found_close (parser); - properties = nreverse (properties); - } - else if (property_kind == CTX_PROPERTY_NAME_LIST - || property_kind == CTX_PROPERTY_ID - || property_kind == CTX_PROPERTY_EXPR) - { - c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"); - return error_mark_node; - } - - ret = tree_cons (selector, properties, ret); - - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - while (1); - - return nreverse (ret); -} - -/* OpenMP 5.0: - - trait-set-selector[,trait-set-selector[,...]] - - trait-set-selector: - trait-set-selector-name = { trait-selector[, trait-selector[, ...]] } - - trait-set-selector-name: - constructor - device - implementation - user */ - -static tree -c_parser_omp_context_selector_specification (c_parser *parser, tree parms) -{ - tree ret = NULL_TREE; - do - { - const char *setp = ""; - if (c_parser_next_token_is (parser, CPP_NAME)) - setp = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - switch (setp[0]) - { - case 'c': - if (strcmp (setp, "construct") == 0) - setp = NULL; - break; - case 'd': - if (strcmp (setp, "device") == 0) - setp = NULL; - break; - case 'i': - if (strcmp (setp, "implementation") == 0) - setp = NULL; - break; - case 'u': - if (strcmp (setp, "user") == 0) - setp = NULL; - break; - default: - break; - } - if (setp) - { - c_parser_error (parser, "expected %, %, " - "% or %"); - return error_mark_node; - } - - tree set = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - - if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) - return error_mark_node; - - matching_braces braces; - if (!braces.require_open (parser)) - return error_mark_node; - - tree selectors = c_parser_omp_context_selector (parser, set, parms); - if (selectors == error_mark_node) - ret = error_mark_node; - else if (ret != error_mark_node) - ret = tree_cons (set, selectors, ret); - - braces.skip_until_found_close (parser); - - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - while (1); - - if (ret == error_mark_node) - return ret; - return nreverse (ret); -} - -/* Finalize #pragma omp declare variant after FNDECL has been parsed, and put - that into "omp declare variant base" attribute. */ - -static void -c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) -{ - matching_parens parens; - if (!parens.require_open (parser)) - { - fail: - c_parser_skip_to_pragma_eol (parser, false); - return; - } - - if (c_parser_next_token_is_not (parser, CPP_NAME) - || c_parser_peek_token (parser)->id_kind != C_ID_ID) - { - c_parser_error (parser, "expected identifier"); - goto fail; - } - - c_token *token = c_parser_peek_token (parser); - tree variant = lookup_name (token->value); - - if (variant == NULL_TREE) - { - undeclared_variable (token->location, token->value); - variant = error_mark_node; - } - - c_parser_consume_token (parser); - - parens.require_close (parser); - - const char *clause = ""; - location_t match_loc = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_NAME)) - clause = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (clause, "match")) - { - c_parser_error (parser, "expected %"); - goto fail; - } - - c_parser_consume_token (parser); - - if (!parens.require_open (parser)) - goto fail; - - if (parms == NULL_TREE) - parms = error_mark_node; - - tree ctx = c_parser_omp_context_selector_specification (parser, parms); - if (ctx == error_mark_node) - goto fail; - ctx = omp_check_context_selector (match_loc, ctx); - if (ctx != error_mark_node && variant != error_mark_node) - { - if (TREE_CODE (variant) != FUNCTION_DECL) - { - error_at (token->location, "variant %qD is not a function", variant); - variant = error_mark_node; - } - else if (omp_get_context_selector (ctx, "construct", "simd") == NULL_TREE - && !comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant))) - { - error_at (token->location, "variant %qD and base %qD have " - "incompatible types", variant, fndecl); - variant = error_mark_node; - } - else if (fndecl_built_in_p (variant) - && (strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), - "__builtin_", strlen ("__builtin_")) == 0 - || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), - "__sync_", strlen ("__sync_")) == 0 - || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), - "__atomic_", strlen ("__atomic_")) == 0)) - { - error_at (token->location, "variant %qD is a built-in", variant); - variant = error_mark_node; - } - if (variant != error_mark_node) - { - C_DECL_USED (variant) = 1; - tree construct = omp_get_context_selector (ctx, "construct", NULL); - omp_mark_declare_variant (match_loc, variant, construct); - if (omp_context_selector_matches (ctx)) - { - tree attr - = tree_cons (get_identifier ("omp declare variant base"), - build_tree_list (variant, ctx), - DECL_ATTRIBUTES (fndecl)); - DECL_ATTRIBUTES (fndecl) = attr; - } - } - } - - parens.require_close (parser); - c_parser_skip_to_pragma_eol (parser); -} - -/* Finalize #pragma omp declare simd or #pragma omp declare variant - clauses after FNDECL has been parsed, and put that into "omp declare simd" - or "omp declare variant base" attribute. */ - -static void -c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms, - vec *pclauses) -{ - vec &clauses = *pclauses; - - /* Normally first token is CPP_NAME "simd" or "variant". CPP_EOF there - indicates error has been reported and CPP_PRAGMA that - c_finish_omp_declare_simd has already processed the tokens. */ - if (clauses.exists () && clauses[0].type == CPP_EOF) - return; - const char *kind = "simd"; - if (clauses.exists () - && (clauses[0].type == CPP_NAME || clauses[0].type == CPP_PRAGMA)) - kind = IDENTIFIER_POINTER (clauses[0].value); - gcc_assert (strcmp (kind, "simd") == 0 || strcmp (kind, "variant") == 0); - if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) - { - error ("%<#pragma omp declare %s%> not immediately followed by " - "a function declaration or definition", kind); - clauses[0].type = CPP_EOF; - return; - } - if (clauses.exists () && clauses[0].type != CPP_NAME) - { - error_at (DECL_SOURCE_LOCATION (fndecl), - "%<#pragma omp declare %s%> not immediately followed by " - "a single function declaration or definition", kind); - clauses[0].type = CPP_EOF; - return; - } - - if (parms == NULL_TREE) - parms = DECL_ARGUMENTS (fndecl); - - unsigned int tokens_avail = parser->tokens_avail; - gcc_assert (parser->tokens == &parser->tokens_buf[0]); - - parser->tokens = clauses.address (); - parser->tokens_avail = clauses.length (); - - /* c_parser_omp_declare_simd pushed 2 extra CPP_EOF tokens at the end. */ - while (parser->tokens_avail > 3) - { - c_token *token = c_parser_peek_token (parser); - gcc_assert (token->type == CPP_NAME - && strcmp (IDENTIFIER_POINTER (token->value), kind) == 0); - c_parser_consume_token (parser); - parser->in_pragma = true; - - if (strcmp (kind, "simd") == 0) - { - tree c; - c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, - "#pragma omp declare simd"); - c = c_omp_declare_simd_clauses_to_numbers (parms, c); - if (c != NULL_TREE) - c = tree_cons (NULL_TREE, c, NULL_TREE); - c = build_tree_list (get_identifier ("omp declare simd"), c); - TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl); - DECL_ATTRIBUTES (fndecl) = c; - } - else - { - gcc_assert (strcmp (kind, "variant") == 0); - c_finish_omp_declare_variant (parser, fndecl, parms); - } - } - - parser->tokens = &parser->tokens_buf[0]; - parser->tokens_avail = tokens_avail; - if (clauses.exists ()) - clauses[0].type = CPP_PRAGMA; -} - - -/* OpenMP 4.0: - # pragma omp declare target new-line - declarations and definitions - # pragma omp end declare target new-line - - OpenMP 4.5: - # pragma omp declare target ( extended-list ) new-line - - # pragma omp declare target declare-target-clauses[seq] new-line */ - -#define OMP_DECLARE_TARGET_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE)) - -static void -c_parser_omp_declare_target (c_parser *parser) -{ - tree clauses = NULL_TREE; - int device_type = 0; - bool only_device_type = true; - if (c_parser_next_token_is (parser, CPP_NAME)) - clauses = c_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, - "#pragma omp declare target"); - else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, - clauses); - clauses = c_finish_omp_clauses (clauses, C_ORT_OMP); - c_parser_skip_to_pragma_eol (parser); - } - else - { - c_parser_skip_to_pragma_eol (parser); - current_omp_declare_target_attribute++; - return; - } - for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE) - device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c); - for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) - { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE) - continue; - tree t = OMP_CLAUSE_DECL (c), id; - tree at1 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (t)); - tree at2 = lookup_attribute ("omp declare target link", - DECL_ATTRIBUTES (t)); - only_device_type = false; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK) - { - id = get_identifier ("omp declare target link"); - std::swap (at1, at2); - } - else - id = get_identifier ("omp declare target"); - if (at2) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD specified both in declare target % and %" - " clauses", t); - continue; - } - if (!at1) - { - DECL_ATTRIBUTES (t) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); - if (TREE_CODE (t) != FUNCTION_DECL && !is_global_var (t)) - continue; - - symtab_node *node = symtab_node::get (t); - if (node != NULL) - { - node->offloadable = 1; - if (ENABLE_OFFLOADING) - { - g->have_offload = true; - if (is_a (node)) - vec_safe_push (offload_vars, t); - } - } - } - if (TREE_CODE (t) != FUNCTION_DECL) - continue; - if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0) - { - tree at3 = lookup_attribute ("omp declare target host", - DECL_ATTRIBUTES (t)); - if (at3 == NULL_TREE) - { - id = get_identifier ("omp declare target host"); - DECL_ATTRIBUTES (t) - = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); - } - } - if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0) - { - tree at3 = lookup_attribute ("omp declare target nohost", - DECL_ATTRIBUTES (t)); - if (at3 == NULL_TREE) - { - id = get_identifier ("omp declare target nohost"); - DECL_ATTRIBUTES (t) - = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); - } - } - } - if (device_type && only_device_type) - warning_at (OMP_CLAUSE_LOCATION (clauses), 0, - "directive with only % clauses ignored"); -} - -static void -c_parser_omp_end_declare_target (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_pragma (parser); - if (c_parser_next_token_is (parser, CPP_NAME) - && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), - "declare") == 0) - { - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME) - && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), - "target") == 0) - c_parser_consume_token (parser); - else - { - c_parser_error (parser, "expected %"); - c_parser_skip_to_pragma_eol (parser); - return; - } - } - else - { - c_parser_error (parser, "expected %"); - c_parser_skip_to_pragma_eol (parser); - return; - } - c_parser_skip_to_pragma_eol (parser); - if (!current_omp_declare_target_attribute) - error_at (loc, "%<#pragma omp end declare target%> without corresponding " - "%<#pragma omp declare target%>"); - else - current_omp_declare_target_attribute--; -} - - -/* OpenMP 4.0 - #pragma omp declare reduction (reduction-id : typename-list : expression) \ - initializer-clause[opt] new-line - - initializer-clause: - initializer (omp_priv = initializer) - initializer (function-name (argument-list)) */ - -static void -c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) -{ - unsigned int tokens_avail = 0, i; - vec types = vNULL; - vec clauses = vNULL; - enum tree_code reduc_code = ERROR_MARK; - tree reduc_id = NULL_TREE; - tree type; - location_t rloc = c_parser_peek_token (parser)->location; - - if (context == pragma_struct || context == pragma_param) - { - error ("%<#pragma omp declare reduction%> not at file or block scope"); - goto fail; - } - - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - goto fail; - - switch (c_parser_peek_token (parser)->type) - { - case CPP_PLUS: - reduc_code = PLUS_EXPR; - break; - case CPP_MULT: - reduc_code = MULT_EXPR; - break; - case CPP_MINUS: - reduc_code = MINUS_EXPR; - break; - case CPP_AND: - reduc_code = BIT_AND_EXPR; - break; - case CPP_XOR: - reduc_code = BIT_XOR_EXPR; - break; - case CPP_OR: - reduc_code = BIT_IOR_EXPR; - break; - case CPP_AND_AND: - reduc_code = TRUTH_ANDIF_EXPR; - break; - case CPP_OR_OR: - reduc_code = TRUTH_ORIF_EXPR; - break; - case CPP_NAME: - const char *p; - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "min") == 0) - { - reduc_code = MIN_EXPR; - break; - } - if (strcmp (p, "max") == 0) - { - reduc_code = MAX_EXPR; - break; - } - reduc_id = c_parser_peek_token (parser)->value; - break; - default: - c_parser_error (parser, - "expected %<+%>, %<*%>, %<-%>, %<&%>, " - "%<^%>, %<|%>, %<&&%>, %<||%> or identifier"); - goto fail; - } - - tree orig_reduc_id, reduc_decl; - orig_reduc_id = reduc_id; - reduc_id = c_omp_reduction_id (reduc_code, reduc_id); - reduc_decl = c_omp_reduction_decl (reduc_id); - c_parser_consume_token (parser); - - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - goto fail; - - while (true) - { - location_t loc = c_parser_peek_token (parser)->location; - struct c_type_name *ctype = c_parser_type_name (parser); - if (ctype != NULL) - { - type = groktypename (ctype, NULL, NULL); - if (type == error_mark_node) - ; - else if ((INTEGRAL_TYPE_P (type) - || TREE_CODE (type) == REAL_TYPE - || TREE_CODE (type) == COMPLEX_TYPE) - && orig_reduc_id == NULL_TREE) - error_at (loc, "predeclared arithmetic type in " - "%<#pragma omp declare reduction%>"); - else if (TREE_CODE (type) == FUNCTION_TYPE - || TREE_CODE (type) == ARRAY_TYPE) - error_at (loc, "function or array type in " - "%<#pragma omp declare reduction%>"); - else if (TYPE_ATOMIC (type)) - error_at (loc, "%<_Atomic%> qualified type in " - "%<#pragma omp declare reduction%>"); - else if (TYPE_QUALS_NO_ADDR_SPACE (type)) - error_at (loc, "const, volatile or restrict qualified type in " - "%<#pragma omp declare reduction%>"); - else - { - tree t; - for (t = DECL_INITIAL (reduc_decl); t; t = TREE_CHAIN (t)) - if (comptypes (TREE_PURPOSE (t), type)) - { - error_at (loc, "redeclaration of %qs " - "%<#pragma omp declare reduction%> for " - "type %qT", - IDENTIFIER_POINTER (reduc_id) - + sizeof ("omp declare reduction ") - 1, - type); - location_t ploc - = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t), - 0)); - error_at (ploc, "previous %<#pragma omp declare " - "reduction%>"); - break; - } - if (t == NULL_TREE) - types.safe_push (type); - } - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - else - break; - } - - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>") - || types.is_empty ()) - { - fail: - clauses.release (); - types.release (); - while (true) - { - c_token *token = c_parser_peek_token (parser); - if (token->type == CPP_EOF || token->type == CPP_PRAGMA_EOL) - break; - c_parser_consume_token (parser); - } - c_parser_skip_to_pragma_eol (parser); - return; - } - - if (types.length () > 1) - { - while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - { - c_token *token = c_parser_peek_token (parser); - if (token->type == CPP_EOF) - goto fail; - clauses.safe_push (*token); - c_parser_consume_token (parser); - } - clauses.safe_push (*c_parser_peek_token (parser)); - c_parser_skip_to_pragma_eol (parser); - - /* Make sure nothing tries to read past the end of the tokens. */ - c_token eof_token; - memset (&eof_token, 0, sizeof (eof_token)); - eof_token.type = CPP_EOF; - clauses.safe_push (eof_token); - clauses.safe_push (eof_token); - } - - int errs = errorcount; - FOR_EACH_VEC_ELT (types, i, type) - { - tokens_avail = parser->tokens_avail; - gcc_assert (parser->tokens == &parser->tokens_buf[0]); - if (!clauses.is_empty ()) - { - parser->tokens = clauses.address (); - parser->tokens_avail = clauses.length (); - parser->in_pragma = true; - } - - bool nested = current_function_decl != NULL_TREE; - if (nested) - c_push_function_context (); - tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, - reduc_id, default_function_type); - current_function_decl = fndecl; - allocate_struct_function (fndecl, true); - push_scope (); - tree stmt = push_stmt_list (); - /* Intentionally BUILTINS_LOCATION, so that -Wshadow doesn't - warn about these. */ - tree omp_out = build_decl (BUILTINS_LOCATION, VAR_DECL, - get_identifier ("omp_out"), type); - DECL_ARTIFICIAL (omp_out) = 1; - DECL_CONTEXT (omp_out) = fndecl; - pushdecl (omp_out); - tree omp_in = build_decl (BUILTINS_LOCATION, VAR_DECL, - get_identifier ("omp_in"), type); - DECL_ARTIFICIAL (omp_in) = 1; - DECL_CONTEXT (omp_in) = fndecl; - pushdecl (omp_in); - struct c_expr combiner = c_parser_expression (parser); - struct c_expr initializer; - tree omp_priv = NULL_TREE, omp_orig = NULL_TREE; - bool bad = false; - initializer.set_error (); - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - bad = true; - else if (c_parser_next_token_is (parser, CPP_NAME) - && strcmp (IDENTIFIER_POINTER - (c_parser_peek_token (parser)->value), - "initializer") == 0) - { - c_parser_consume_token (parser); - pop_scope (); - push_scope (); - omp_priv = build_decl (BUILTINS_LOCATION, VAR_DECL, - get_identifier ("omp_priv"), type); - DECL_ARTIFICIAL (omp_priv) = 1; - DECL_INITIAL (omp_priv) = error_mark_node; - DECL_CONTEXT (omp_priv) = fndecl; - pushdecl (omp_priv); - omp_orig = build_decl (BUILTINS_LOCATION, VAR_DECL, - get_identifier ("omp_orig"), type); - DECL_ARTIFICIAL (omp_orig) = 1; - DECL_CONTEXT (omp_orig) = fndecl; - pushdecl (omp_orig); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - bad = true; - else if (!c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected % or " - "function-name"); - bad = true; - } - else if (strcmp (IDENTIFIER_POINTER - (c_parser_peek_token (parser)->value), - "omp_priv") != 0) - { - if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN - || c_parser_peek_token (parser)->id_kind != C_ID_ID) - { - c_parser_error (parser, "expected function-name %<(%>"); - bad = true; - } - else - initializer = c_parser_postfix_expression (parser); - if (initializer.value - && TREE_CODE (initializer.value) == CALL_EXPR) - { - int j; - tree c = initializer.value; - for (j = 0; j < call_expr_nargs (c); j++) - { - tree a = CALL_EXPR_ARG (c, j); - STRIP_NOPS (a); - if (TREE_CODE (a) == ADDR_EXPR - && TREE_OPERAND (a, 0) == omp_priv) - break; - } - if (j == call_expr_nargs (c)) - error ("one of the initializer call arguments should be " - "%<&omp_priv%>"); - } - } - else - { - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) - bad = true; - else - { - tree st = push_stmt_list (); - location_t loc = c_parser_peek_token (parser)->location; - rich_location richloc (line_table, loc); - start_init (omp_priv, NULL_TREE, 0, &richloc); - struct c_expr init = c_parser_initializer (parser); - finish_init (); - finish_decl (omp_priv, loc, init.value, - init.original_type, NULL_TREE); - pop_stmt_list (st); - } - } - if (!bad - && !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - bad = true; - } - - if (!bad) - { - c_parser_skip_to_pragma_eol (parser); - - tree t = tree_cons (type, make_tree_vec (omp_priv ? 6 : 3), - DECL_INITIAL (reduc_decl)); - DECL_INITIAL (reduc_decl) = t; - DECL_SOURCE_LOCATION (omp_out) = rloc; - TREE_VEC_ELT (TREE_VALUE (t), 0) = omp_out; - TREE_VEC_ELT (TREE_VALUE (t), 1) = omp_in; - TREE_VEC_ELT (TREE_VALUE (t), 2) = combiner.value; - walk_tree (&combiner.value, c_check_omp_declare_reduction_r, - &TREE_VEC_ELT (TREE_VALUE (t), 0), NULL); - if (omp_priv) - { - DECL_SOURCE_LOCATION (omp_priv) = rloc; - TREE_VEC_ELT (TREE_VALUE (t), 3) = omp_priv; - TREE_VEC_ELT (TREE_VALUE (t), 4) = omp_orig; - TREE_VEC_ELT (TREE_VALUE (t), 5) = initializer.value; - walk_tree (&initializer.value, c_check_omp_declare_reduction_r, - &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); - walk_tree (&DECL_INITIAL (omp_priv), - c_check_omp_declare_reduction_r, - &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); - } - } - - pop_stmt_list (stmt); - pop_scope (); - if (cfun->language != NULL) - { - ggc_free (cfun->language); - cfun->language = NULL; - } - set_cfun (NULL); - current_function_decl = NULL_TREE; - if (nested) - c_pop_function_context (); - - if (!clauses.is_empty ()) - { - parser->tokens = &parser->tokens_buf[0]; - parser->tokens_avail = tokens_avail; - } - if (bad) - goto fail; - if (errs != errorcount) - break; - } - - clauses.release (); - types.release (); -} - - -/* OpenMP 4.0 - #pragma omp declare simd declare-simd-clauses[optseq] new-line - #pragma omp declare reduction (reduction-id : typename-list : expression) \ - initializer-clause[opt] new-line - #pragma omp declare target new-line - - OpenMP 5.0 - #pragma omp declare variant (identifier) match (context-selector) */ - -static bool -c_parser_omp_declare (c_parser *parser, enum pragma_context context) -{ - c_parser_consume_pragma (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "simd") == 0) - { - /* c_parser_consume_token (parser); done in - c_parser_omp_declare_simd. */ - c_parser_omp_declare_simd (parser, context); - return true; - } - if (strcmp (p, "reduction") == 0) - { - c_parser_consume_token (parser); - c_parser_omp_declare_reduction (parser, context); - return false; - } - if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return false; - } - if (strcmp (p, "target") == 0) - { - c_parser_consume_token (parser); - c_parser_omp_declare_target (parser); - return false; - } - if (strcmp (p, "variant") == 0) - { - /* c_parser_consume_token (parser); done in - c_parser_omp_declare_simd. */ - c_parser_omp_declare_simd (parser, context); - return true; - } - } - - c_parser_error (parser, "expected %, %, " - "% or %"); - c_parser_skip_to_pragma_eol (parser); - return false; -} - -/* OpenMP 5.0 - #pragma omp requires clauses[optseq] new-line */ - -static void -c_parser_omp_requires (c_parser *parser) -{ - bool first = true; - enum omp_requires new_req = (enum omp_requires) 0; - - c_parser_consume_pragma (parser); - - location_t loc = c_parser_peek_token (parser)->location; - while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - { - if (!first - && c_parser_next_token_is (parser, CPP_COMMA) - && c_parser_peek_2nd_token (parser)->type == CPP_NAME) - c_parser_consume_token (parser); - - first = false; - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - location_t cloc = c_parser_peek_token (parser)->location; - enum omp_requires this_req = (enum omp_requires) 0; - - if (!strcmp (p, "unified_address")) - this_req = OMP_REQUIRES_UNIFIED_ADDRESS; - else if (!strcmp (p, "unified_shared_memory")) - this_req = OMP_REQUIRES_UNIFIED_SHARED_MEMORY; - else if (!strcmp (p, "dynamic_allocators")) - this_req = OMP_REQUIRES_DYNAMIC_ALLOCATORS; - else if (!strcmp (p, "reverse_offload")) - this_req = OMP_REQUIRES_REVERSE_OFFLOAD; - else if (!strcmp (p, "atomic_default_mem_order")) - { - c_parser_consume_token (parser); - - matching_parens parens; - if (parens.require_open (parser)) - { - if (c_parser_next_token_is (parser, CPP_NAME)) - { - tree v = c_parser_peek_token (parser)->value; - p = IDENTIFIER_POINTER (v); - - if (!strcmp (p, "seq_cst")) - this_req - = (enum omp_requires) OMP_MEMORY_ORDER_SEQ_CST; - else if (!strcmp (p, "relaxed")) - this_req - = (enum omp_requires) OMP_MEMORY_ORDER_RELAXED; - else if (!strcmp (p, "acq_rel")) - this_req - = (enum omp_requires) OMP_MEMORY_ORDER_ACQ_REL; - } - if (this_req == 0) - { - error_at (c_parser_peek_token (parser)->location, - "expected %, % or " - "%"); - switch (c_parser_peek_token (parser)->type) - { - case CPP_EOF: - case CPP_PRAGMA_EOL: - case CPP_CLOSE_PAREN: - break; - default: - if (c_parser_peek_2nd_token (parser)->type - == CPP_CLOSE_PAREN) - c_parser_consume_token (parser); - break; - } - } - else - c_parser_consume_token (parser); - - parens.skip_until_found_close (parser); - if (this_req == 0) - { - c_parser_skip_to_pragma_eol (parser, false); - return; - } - } - p = NULL; - } - else - { - error_at (cloc, "expected %, " - "%, " - "%, " - "% " - "or % clause"); - c_parser_skip_to_pragma_eol (parser, false); - return; - } - if (p && this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS) - sorry_at (cloc, "%qs clause on % directive not " - "supported yet", p); - if (p) - c_parser_consume_token (parser); - if (this_req) - { - if ((this_req & ~OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) - { - if ((this_req & new_req) != 0) - error_at (cloc, "too many %qs clauses", p); - if (this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS - && (omp_requires_mask & OMP_REQUIRES_TARGET_USED) != 0) - error_at (cloc, "%qs clause used lexically after first " - "target construct or offloading API", p); - } - else if ((new_req & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) - { - error_at (cloc, "too many %qs clauses", - "atomic_default_mem_order"); - this_req = (enum omp_requires) 0; - } - else if ((omp_requires_mask - & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) - { - error_at (cloc, "more than one %" - " clause in a single compilation unit"); - this_req - = (enum omp_requires) - (omp_requires_mask - & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER); - } - else if ((omp_requires_mask - & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED) != 0) - error_at (cloc, "% clause used " - "lexically after first % construct " - "without memory order clause"); - new_req = (enum omp_requires) (new_req | this_req); - omp_requires_mask - = (enum omp_requires) (omp_requires_mask | this_req); - continue; - } - } - break; - } - c_parser_skip_to_pragma_eol (parser); - - if (new_req == 0) - error_at (loc, "% requires at least one clause"); -} - -/* Helper function for c_parser_omp_taskloop. - Disallow zero sized or potentially zero sized task reductions. */ - -static tree -c_finish_taskloop_clauses (tree clauses) -{ - tree *pc = &clauses; - for (tree c = clauses; c; c = *pc) - { - bool remove = false; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) - { - tree type = strip_array_types (TREE_TYPE (OMP_CLAUSE_DECL (c))); - if (integer_zerop (TYPE_SIZE_UNIT (type))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "zero sized type %qT in % clause", type); - remove = true; - } - else if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) - { - error_at (OMP_CLAUSE_LOCATION (c), - "variable sized type %qT in % clause", - type); - remove = true; - } - } - if (remove) - *pc = OMP_CLAUSE_CHAIN (c); - else - pc = &OMP_CLAUSE_CHAIN (c); - } - return clauses; -} - -/* OpenMP 4.5: - #pragma omp taskloop taskloop-clause[optseq] new-line - for-loop - - #pragma omp taskloop simd taskloop-simd-clause[optseq] new-line - for-loop */ - -#define OMP_TASKLOOP_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_GRAINSIZE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TASKS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)) - -static tree -c_parser_omp_taskloop (location_t loc, c_parser *parser, - char *p_name, omp_clause_mask mask, tree *cclauses, - bool *if_p) -{ - tree clauses, block, ret; - - strcat (p_name, " taskloop"); - mask |= OMP_TASKLOOP_CLAUSE_MASK; - /* #pragma omp parallel master taskloop{, simd} disallow in_reduction - clause. */ - if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0) - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION); - - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - if (strcmp (p, "simd") == 0) - { - tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; - c_parser_consume_token (parser); - if (!flag_openmp) /* flag_openmp_simd */ - return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, - if_p); - block = c_begin_compound_stmt (true); - ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, if_p); - block = c_end_compound_stmt (loc, block, true); - if (ret == NULL) - return ret; - ret = make_node (OMP_TASKLOOP); - TREE_TYPE (ret) = void_type_node; - OMP_FOR_BODY (ret) = block; - OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; - OMP_FOR_CLAUSES (ret) - = c_finish_taskloop_clauses (OMP_FOR_CLAUSES (ret)); - SET_EXPR_LOCATION (ret, loc); - add_stmt (ret); - return ret; - } - } - if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; - } - - clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - if (cclauses) - { - omp_split_clauses (loc, OMP_TASKLOOP, mask, clauses, cclauses); - clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; - } - - clauses = c_finish_taskloop_clauses (clauses); - block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (loc, parser, OMP_TASKLOOP, clauses, NULL, if_p); - block = c_end_compound_stmt (loc, block, true); - add_stmt (block); - - return ret; -} - -/* OpenMP 5.1 - #pragma omp nothing new-line */ - -static void -c_parser_omp_nothing (c_parser *parser) -{ - c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); -} - -/* OpenMP 5.1 - #pragma omp error clauses[optseq] new-line */ - -static bool -c_parser_omp_error (c_parser *parser, enum pragma_context context) -{ - int at_compilation = -1; - int severity_fatal = -1; - tree message = NULL_TREE; - bool first = true; - bool bad = false; - location_t loc = c_parser_peek_token (parser)->location; - - c_parser_consume_pragma (parser); - - while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) - { - if (!first - && c_parser_next_token_is (parser, CPP_COMMA) - && c_parser_peek_2nd_token (parser)->type == CPP_NAME) - c_parser_consume_token (parser); - - first = false; - - if (!c_parser_next_token_is (parser, CPP_NAME)) - break; - - const char *p - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - location_t cloc = c_parser_peek_token (parser)->location; - static const char *args[] = { - "execution", "compilation", "warning", "fatal" - }; - int *v = NULL; - int idx = 0, n = -1; - tree m = NULL_TREE; - - if (!strcmp (p, "at")) - v = &at_compilation; - else if (!strcmp (p, "severity")) - { - v = &severity_fatal; - idx += 2; - } - else if (strcmp (p, "message")) - { - error_at (cloc, - "expected %, % or % clause"); - c_parser_skip_to_pragma_eol (parser, false); - return false; - } - - c_parser_consume_token (parser); - - matching_parens parens; - if (parens.require_open (parser)) - { - if (v == NULL) - { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true); - m = convert (const_string_type_node, expr.value); - m = c_fully_fold (m, false, NULL); - } - else - { - if (c_parser_next_token_is (parser, CPP_NAME)) - { - tree val = c_parser_peek_token (parser)->value; - const char *q = IDENTIFIER_POINTER (val); - - if (!strcmp (q, args[idx])) - n = 0; - else if (!strcmp (q, args[idx + 1])) - n = 1; - } - if (n == -1) - { - error_at (c_parser_peek_token (parser)->location, - "expected %qs or %qs", args[idx], args[idx + 1]); - bad = true; - switch (c_parser_peek_token (parser)->type) - { - case CPP_EOF: - case CPP_PRAGMA_EOL: - case CPP_CLOSE_PAREN: - break; - default: - if (c_parser_peek_2nd_token (parser)->type - == CPP_CLOSE_PAREN) - c_parser_consume_token (parser); - break; - } - } - else - c_parser_consume_token (parser); - } - - parens.skip_until_found_close (parser); - - if (v == NULL) - { - if (message) - { - error_at (cloc, "too many %qs clauses", p); - bad = true; - } - else - message = m; - } - else if (n != -1) - { - if (*v != -1) - { - error_at (cloc, "too many %qs clauses", p); - bad = true; - } - else - *v = n; - } - } - else - bad = true; - } - c_parser_skip_to_pragma_eol (parser); - if (bad) - return true; - - if (at_compilation == -1) - at_compilation = 1; - if (severity_fatal == -1) - severity_fatal = 1; - if (!at_compilation) - { - if (context != pragma_compound) - { - error_at (loc, "%<#pragma omp error%> with % clause " - "may only be used in compound statements"); - return true; - } - tree fndecl - = builtin_decl_explicit (severity_fatal ? BUILT_IN_GOMP_ERROR - : BUILT_IN_GOMP_WARNING); - if (!message) - message = build_zero_cst (const_string_type_node); - tree stmt = build_call_expr_loc (loc, fndecl, 2, message, - build_all_ones_cst (size_type_node)); - add_stmt (stmt); - return true; - } - const char *msg = NULL; - if (message) - { - msg = c_getstr (message); - if (msg == NULL) - msg = _(""); - } - if (msg) - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, - "% encountered: %s", msg); - else - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, - "% encountered"); - return false; -} - -/* Main entry point to parsing most OpenMP pragmas. */ - -static void -c_parser_omp_construct (c_parser *parser, bool *if_p) -{ - enum pragma_kind p_kind; - location_t loc; - tree stmt; - char p_name[sizeof "#pragma omp teams distribute parallel for simd"]; - omp_clause_mask mask (0); - - loc = c_parser_peek_token (parser)->location; - p_kind = c_parser_peek_token (parser)->pragma_kind; - c_parser_consume_pragma (parser); - - switch (p_kind) - { - case PRAGMA_OACC_ATOMIC: - c_parser_omp_atomic (loc, parser, true); - return; - case PRAGMA_OACC_CACHE: - strcpy (p_name, "#pragma acc"); - stmt = c_parser_oacc_cache (loc, parser); - break; - case PRAGMA_OACC_DATA: - stmt = c_parser_oacc_data (loc, parser, if_p); - break; - case PRAGMA_OACC_HOST_DATA: - stmt = c_parser_oacc_host_data (loc, parser, if_p); - break; - case PRAGMA_OACC_KERNELS: - case PRAGMA_OACC_PARALLEL: - case PRAGMA_OACC_SERIAL: - strcpy (p_name, "#pragma acc"); - stmt = c_parser_oacc_compute (loc, parser, p_kind, p_name, if_p); - break; - case PRAGMA_OACC_LOOP: - strcpy (p_name, "#pragma acc"); - stmt = c_parser_oacc_loop (loc, parser, p_name, mask, NULL, if_p); - break; - case PRAGMA_OACC_WAIT: - strcpy (p_name, "#pragma wait"); - stmt = c_parser_oacc_wait (loc, parser, p_name); - break; - case PRAGMA_OMP_ALLOCATE: - c_parser_omp_allocate (loc, parser); - return; - case PRAGMA_OMP_ATOMIC: - c_parser_omp_atomic (loc, parser, false); - return; - case PRAGMA_OMP_CRITICAL: - stmt = c_parser_omp_critical (loc, parser, if_p); - break; - case PRAGMA_OMP_DISTRIBUTE: - strcpy (p_name, "#pragma omp"); - stmt = c_parser_omp_distribute (loc, parser, p_name, mask, NULL, if_p); - break; - case PRAGMA_OMP_FOR: - strcpy (p_name, "#pragma omp"); - stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL, if_p); - break; - case PRAGMA_OMP_LOOP: - strcpy (p_name, "#pragma omp"); - stmt = c_parser_omp_loop (loc, parser, p_name, mask, NULL, if_p); - break; - case PRAGMA_OMP_MASKED: - strcpy (p_name, "#pragma omp"); - stmt = c_parser_omp_masked (loc, parser, p_name, mask, NULL, if_p); - break; - case PRAGMA_OMP_MASTER: - strcpy (p_name, "#pragma omp"); - stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p); - break; - case PRAGMA_OMP_PARALLEL: - strcpy (p_name, "#pragma omp"); - stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL, if_p); - break; - case PRAGMA_OMP_SCOPE: - stmt = c_parser_omp_scope (loc, parser, if_p); - break; - case PRAGMA_OMP_SECTIONS: - strcpy (p_name, "#pragma omp"); - stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL); - break; - case PRAGMA_OMP_SIMD: - strcpy (p_name, "#pragma omp"); - stmt = c_parser_omp_simd (loc, parser, p_name, mask, NULL, if_p); - break; - case PRAGMA_OMP_SINGLE: - stmt = c_parser_omp_single (loc, parser, if_p); - break; - case PRAGMA_OMP_TASK: - stmt = c_parser_omp_task (loc, parser, if_p); - break; - case PRAGMA_OMP_TASKGROUP: - stmt = c_parser_omp_taskgroup (loc, parser, if_p); - break; - case PRAGMA_OMP_TASKLOOP: - strcpy (p_name, "#pragma omp"); - stmt = c_parser_omp_taskloop (loc, parser, p_name, mask, NULL, if_p); - break; - case PRAGMA_OMP_TEAMS: - strcpy (p_name, "#pragma omp"); - stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL, if_p); - break; - default: - gcc_unreachable (); - } - - if (stmt && stmt != error_mark_node) - gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION); -} - - -/* OpenMP 2.5: - # pragma omp threadprivate (variable-list) */ - -static void -c_parser_omp_threadprivate (c_parser *parser) -{ - tree vars, t; - location_t loc; - - c_parser_consume_pragma (parser); - loc = c_parser_peek_token (parser)->location; - vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); - - /* Mark every variable in VARS to be assigned thread local storage. */ - for (t = vars; t; t = TREE_CHAIN (t)) - { - tree v = TREE_PURPOSE (t); - - /* FIXME diagnostics: Ideally we should keep individual - locations for all the variables in the var list to make the - following errors more precise. Perhaps - c_parser_omp_var_list_parens() should construct a list of - locations to go along with the var list. */ - - /* If V had already been marked threadprivate, it doesn't matter - whether it had been used prior to this point. */ - if (!VAR_P (v)) - error_at (loc, "%qD is not a variable", v); - else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v)) - error_at (loc, "%qE declared % after first use", v); - else if (! is_global_var (v)) - error_at (loc, "automatic variable %qE cannot be %", v); - else if (TREE_TYPE (v) == error_mark_node) - ; - else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) - error_at (loc, "% %qE has incomplete type", v); - else - { - if (! DECL_THREAD_LOCAL_P (v)) - { - set_decl_tls_model (v, decl_default_tls_model (v)); - /* If rtl has been already set for this var, call - make_decl_rtl once again, so that encode_section_info - has a chance to look at the new decl flags. */ - if (DECL_RTL_SET_P (v)) - make_decl_rtl (v); - } - C_DECL_THREADPRIVATE_P (v) = 1; - } - } - - c_parser_skip_to_pragma_eol (parser); -} - -/* Parse a transaction attribute (GCC Extension). - - transaction-attribute: - gnu-attributes - attribute-specifier -*/ - -static tree -c_parser_transaction_attributes (c_parser *parser) -{ - if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - return c_parser_gnu_attributes (parser); - - if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) - return NULL_TREE; - return c_parser_std_attribute_specifier (parser, true); -} - -/* Parse a __transaction_atomic or __transaction_relaxed statement - (GCC Extension). - - transaction-statement: - __transaction_atomic transaction-attribute[opt] compound-statement - __transaction_relaxed compound-statement - - Note that the only valid attribute is: "outer". -*/ - -static tree -c_parser_transaction (c_parser *parser, enum rid keyword) -{ - unsigned int old_in = parser->in_transaction; - unsigned int this_in = 1, new_in; - location_t loc = c_parser_peek_token (parser)->location; - tree stmt, attrs; - - gcc_assert ((keyword == RID_TRANSACTION_ATOMIC - || keyword == RID_TRANSACTION_RELAXED) - && c_parser_next_token_is_keyword (parser, keyword)); - c_parser_consume_token (parser); - - if (keyword == RID_TRANSACTION_RELAXED) - this_in |= TM_STMT_ATTR_RELAXED; - else - { - attrs = c_parser_transaction_attributes (parser); - if (attrs) - this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); - } - - /* Keep track if we're in the lexical scope of an outer transaction. */ - new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); - - parser->in_transaction = new_in; - stmt = c_parser_compound_statement (parser); - parser->in_transaction = old_in; - - if (flag_tm) - stmt = c_finish_transaction (loc, stmt, this_in); - else - error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? - "%<__transaction_atomic%> without transactional memory support enabled" - : "%<__transaction_relaxed %> " - "without transactional memory support enabled")); - - return stmt; -} - -/* Parse a __transaction_atomic or __transaction_relaxed expression - (GCC Extension). - - transaction-expression: - __transaction_atomic ( expression ) - __transaction_relaxed ( expression ) -*/ - -static struct c_expr -c_parser_transaction_expression (c_parser *parser, enum rid keyword) -{ - struct c_expr ret; - unsigned int old_in = parser->in_transaction; - unsigned int this_in = 1; - location_t loc = c_parser_peek_token (parser)->location; - tree attrs; - - gcc_assert ((keyword == RID_TRANSACTION_ATOMIC - || keyword == RID_TRANSACTION_RELAXED) - && c_parser_next_token_is_keyword (parser, keyword)); - c_parser_consume_token (parser); - - if (keyword == RID_TRANSACTION_RELAXED) - this_in |= TM_STMT_ATTR_RELAXED; - else - { - attrs = c_parser_transaction_attributes (parser); - if (attrs) - this_in |= parse_tm_stmt_attr (attrs, 0); - } - - parser->in_transaction = this_in; - matching_parens parens; - if (parens.require_open (parser)) - { - tree expr = c_parser_expression (parser).value; - ret.original_type = TREE_TYPE (expr); - ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr); - if (this_in & TM_STMT_ATTR_RELAXED) - TRANSACTION_EXPR_RELAXED (ret.value) = 1; - SET_EXPR_LOCATION (ret.value, loc); - ret.original_code = TRANSACTION_EXPR; - if (!parens.require_close (parser)) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - goto error; - } - } - else - { - error: - ret.set_error (); - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - } - parser->in_transaction = old_in; - - if (!flag_tm) - error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? - "%<__transaction_atomic%> without transactional memory support enabled" - : "%<__transaction_relaxed %> " - "without transactional memory support enabled")); - - set_c_expr_source_range (&ret, loc, loc); - - return ret; -} - -/* Parse a __transaction_cancel statement (GCC Extension). - - transaction-cancel-statement: - __transaction_cancel transaction-attribute[opt] ; - - Note that the only valid attribute is "outer". -*/ - -static tree -c_parser_transaction_cancel (c_parser *parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - tree attrs; - bool is_outer = false; - - gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRANSACTION_CANCEL)); - c_parser_consume_token (parser); - - attrs = c_parser_transaction_attributes (parser); - if (attrs) - is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0); - - if (!flag_tm) - { - error_at (loc, "%<__transaction_cancel%> without " - "transactional memory support enabled"); - goto ret_error; - } - else if (parser->in_transaction & TM_STMT_ATTR_RELAXED) - { - error_at (loc, "%<__transaction_cancel%> within a " - "%<__transaction_relaxed%>"); - goto ret_error; - } - else if (is_outer) - { - if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0 - && !is_tm_may_cancel_outer (current_function_decl)) - { - error_at (loc, "outer %<__transaction_cancel%> not " - "within outer %<__transaction_atomic%> or " - "a % function"); - goto ret_error; - } - } - else if (parser->in_transaction == 0) - { - error_at (loc, "%<__transaction_cancel%> not within " - "%<__transaction_atomic%>"); - goto ret_error; - } - - return add_stmt (build_tm_abort_call (loc, is_outer)); - - ret_error: - return build1 (NOP_EXPR, void_type_node, error_mark_node); -} - -/* Parse a single source file. */ - -void -c_parse_file (void) -{ - /* Use local storage to begin. If the first token is a pragma, parse it. - If it is #pragma GCC pch_preprocess, then this will load a PCH file - which will cause garbage collection. */ - c_parser tparser; - - memset (&tparser, 0, sizeof tparser); - tparser.translate_strings_p = true; - tparser.tokens = &tparser.tokens_buf[0]; - the_parser = &tparser; - - if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) - c_parser_pragma_pch_preprocess (&tparser); - else - c_common_no_more_pch (); - - the_parser = ggc_alloc (); - *the_parser = tparser; - if (tparser.tokens == &tparser.tokens_buf[0]) - the_parser->tokens = &the_parser->tokens_buf[0]; - - /* Initialize EH, if we've been told to do so. */ - if (flag_exceptions) - using_eh_for_cleanups (); - - c_parser_translation_unit (the_parser); - the_parser = NULL; -} - -/* Parse the body of a function declaration marked with "__RTL". - - The RTL parser works on the level of characters read from a - FILE *, whereas c_parser works at the level of tokens. - Square this circle by consuming all of the tokens up to and - including the closing brace, recording the start/end of the RTL - fragment, and reopening the file and re-reading the relevant - lines within the RTL parser. - - This requires the opening and closing braces of the C function - to be on separate lines from the RTL they wrap. - - Take ownership of START_WITH_PASS, if non-NULL. */ - -location_t -c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass) -{ - if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) - { - free (start_with_pass); - return c_parser_peek_token (parser)->location; - } - - location_t start_loc = c_parser_peek_token (parser)->location; - - /* Consume all tokens, up to the closing brace, handling - matching pairs of braces in the rtl dump. */ - int num_open_braces = 1; - while (1) - { - switch (c_parser_peek_token (parser)->type) - { - case CPP_OPEN_BRACE: - num_open_braces++; - break; - case CPP_CLOSE_BRACE: - if (--num_open_braces == 0) - goto found_closing_brace; - break; - case CPP_EOF: - error_at (start_loc, "no closing brace"); - free (start_with_pass); - return c_parser_peek_token (parser)->location; - default: - break; - } - c_parser_consume_token (parser); - } - - found_closing_brace: - /* At the closing brace; record its location. */ - location_t end_loc = c_parser_peek_token (parser)->location; - - /* Consume the closing brace. */ - c_parser_consume_token (parser); - - /* Invoke the RTL parser. */ - if (!read_rtl_function_body_from_file_range (start_loc, end_loc)) - { - free (start_with_pass); - return end_loc; - } - - /* Run the backend on the cfun created above, transferring ownership of - START_WITH_PASS. */ - run_rtl_passes (start_with_pass); - return end_loc; -} - -#include "gt-c-c-parser.h" diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc new file mode 100644 index 0000000..20774f7 --- /dev/null +++ b/gcc/c/c-parser.cc @@ -0,0 +1,23404 @@ +/* Parser for C and Objective-C. + Copyright (C) 1987-2022 Free Software Foundation, Inc. + + Parser actions based on the old Bison parser; structure somewhat + influenced by and fragments based on the C++ parser. + +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 +. */ + +/* TODO: + + Make sure all relevant comments, and all relevant code from all + actions, brought over from old parser. Verify exact correspondence + of syntax accepted. + + Add testcases covering every input symbol in every state in old and + new parsers. + + Include full syntax for GNU C, including erroneous cases accepted + with error messages, in syntax productions in comments. + + Make more diagnostics in the front end generally take an explicit + location rather than implicitly using input_location. */ + +#include "config.h" +#define INCLUDE_MEMORY +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "function.h" +#include "c-tree.h" +#include "timevar.h" +#include "stringpool.h" +#include "cgraph.h" +#include "attribs.h" +#include "stor-layout.h" +#include "varasm.h" +#include "trans-mem.h" +#include "c-family/c-pragma.h" +#include "c-lang.h" +#include "c-family/c-objc.h" +#include "plugin.h" +#include "omp-general.h" +#include "omp-offload.h" +#include "builtins.h" +#include "gomp-constants.h" +#include "c-family/c-indentation.h" +#include "gimple-expr.h" +#include "context.h" +#include "gcc-rich-location.h" +#include "c-parser.h" +#include "gimple-parser.h" +#include "read-rtl-function.h" +#include "run-rtl-passes.h" +#include "intl.h" +#include "c-family/name-hint.h" +#include "tree-iterator.h" +#include "tree-pretty-print.h" +#include "memmodel.h" +#include "c-family/known-headers.h" + +/* We need to walk over decls with incomplete struct/union/enum types + after parsing the whole translation unit. + In finish_decl(), if the decl is static, has incomplete + struct/union/enum type, it is appended to incomplete_record_decls. + In c_parser_translation_unit(), we iterate over incomplete_record_decls + and report error if any of the decls are still incomplete. */ + +vec incomplete_record_decls; + +void +set_c_expr_source_range (c_expr *expr, + location_t start, location_t finish) +{ + expr->src_range.m_start = start; + expr->src_range.m_finish = finish; + if (expr->value) + set_source_range (expr->value, start, finish); +} + +void +set_c_expr_source_range (c_expr *expr, + source_range src_range) +{ + expr->src_range = src_range; + if (expr->value) + set_source_range (expr->value, src_range); +} + + +/* Initialization routine for this file. */ + +void +c_parse_init (void) +{ + /* The only initialization required is of the reserved word + identifiers. */ + unsigned int i; + tree id; + int mask = 0; + + /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in + the c_token structure. */ + gcc_assert (RID_MAX <= 255); + + mask |= D_CXXONLY; + if (!flag_isoc99) + mask |= D_C99; + if (flag_no_asm) + { + mask |= D_ASM | D_EXT; + if (!flag_isoc99) + mask |= D_EXT89; + } + if (!c_dialect_objc ()) + mask |= D_OBJC | D_CXX_OBJC; + + ridpointers = ggc_cleared_vec_alloc ((int) RID_MAX); + for (i = 0; i < num_c_common_reswords; i++) + { + /* If a keyword is disabled, do not enter it into the table + and so create a canonical spelling that isn't a keyword. */ + if (c_common_reswords[i].disable & mask) + { + if (warn_cxx_compat + && (c_common_reswords[i].disable & D_CXXWARN)) + { + id = get_identifier (c_common_reswords[i].word); + C_SET_RID_CODE (id, RID_CXX_COMPAT_WARN); + C_IS_RESERVED_WORD (id) = 1; + } + continue; + } + + id = get_identifier (c_common_reswords[i].word); + C_SET_RID_CODE (id, c_common_reswords[i].rid); + C_IS_RESERVED_WORD (id) = 1; + ridpointers [(int) c_common_reswords[i].rid] = id; + } + + for (i = 0; i < NUM_INT_N_ENTS; i++) + { + /* We always create the symbols but they aren't always supported. */ + char name[50]; + sprintf (name, "__int%d", int_n_data[i].bitsize); + id = get_identifier (name); + C_SET_RID_CODE (id, RID_FIRST_INT_N + i); + C_IS_RESERVED_WORD (id) = 1; + + sprintf (name, "__int%d__", int_n_data[i].bitsize); + id = get_identifier (name); + C_SET_RID_CODE (id, RID_FIRST_INT_N + i); + C_IS_RESERVED_WORD (id) = 1; + } +} + +/* A parser structure recording information about the state and + context of parsing. Includes lexer information with up to two + tokens of look-ahead; more are not needed for C. */ +struct GTY(()) c_parser { + /* The look-ahead tokens. */ + c_token * GTY((skip)) tokens; + /* Buffer for look-ahead tokens. */ + c_token tokens_buf[4]; + /* How many look-ahead tokens are available (0 - 4, or + more if parsing from pre-lexed tokens). */ + unsigned int tokens_avail; + /* Raw look-ahead tokens, used only for checking in Objective-C + whether '[[' starts attributes. */ + vec *raw_tokens; + /* The number of raw look-ahead tokens that have since been fully + lexed. */ + unsigned int raw_tokens_used; + /* True if a syntax error is being recovered from; false otherwise. + c_parser_error sets this flag. It should clear this flag when + enough tokens have been consumed to recover from the error. */ + BOOL_BITFIELD error : 1; + /* True if we're processing a pragma, and shouldn't automatically + consume CPP_PRAGMA_EOL. */ + BOOL_BITFIELD in_pragma : 1; + /* True if we're parsing the outermost block of an if statement. */ + BOOL_BITFIELD in_if_block : 1; + /* True if we want to lex a translated, joined string (for an + initial #pragma pch_preprocess). Otherwise the parser is + responsible for concatenating strings and translating to the + execution character set as needed. */ + BOOL_BITFIELD lex_joined_string : 1; + /* True if, when the parser is concatenating string literals, it + should translate them to the execution character set (false + inside attributes). */ + BOOL_BITFIELD translate_strings_p : 1; + + /* Objective-C specific parser/lexer information. */ + + /* True if we are in a context where the Objective-C "PQ" keywords + are considered keywords. */ + BOOL_BITFIELD objc_pq_context : 1; + /* True if we are parsing a (potential) Objective-C foreach + statement. This is set to true after we parsed 'for (' and while + we wait for 'in' or ';' to decide if it's a standard C for loop or an + Objective-C foreach loop. */ + BOOL_BITFIELD objc_could_be_foreach_context : 1; + /* The following flag is needed to contextualize Objective-C lexical + analysis. In some cases (e.g., 'int NSObject;'), it is + undesirable to bind an identifier to an Objective-C class, even + if a class with that name exists. */ + BOOL_BITFIELD objc_need_raw_identifier : 1; + /* Nonzero if we're processing a __transaction statement. The value + is 1 | TM_STMT_ATTR_*. */ + unsigned int in_transaction : 4; + /* True if we are in a context where the Objective-C "Property attribute" + keywords are valid. */ + BOOL_BITFIELD objc_property_attr_context : 1; + + /* Whether we have just seen/constructed a string-literal. Set when + returning a string-literal from c_parser_string_literal. Reset + in consume_token. Useful when we get a parse error and see an + unknown token, which could have been a string-literal constant + macro. */ + BOOL_BITFIELD seen_string_literal : 1; + + /* Location of the last consumed token. */ + location_t last_token_location; +}; + +/* Return a pointer to the Nth token in PARSERs tokens_buf. */ + +c_token * +c_parser_tokens_buf (c_parser *parser, unsigned n) +{ + return &parser->tokens_buf[n]; +} + +/* Return the error state of PARSER. */ + +bool +c_parser_error (c_parser *parser) +{ + return parser->error; +} + +/* Set the error state of PARSER to ERR. */ + +void +c_parser_set_error (c_parser *parser, bool err) +{ + parser->error = err; +} + + +/* The actual parser and external interface. ??? Does this need to be + garbage-collected? */ + +static GTY (()) c_parser *the_parser; + +/* Read in and lex a single token, storing it in *TOKEN. If RAW, + context-sensitive postprocessing of the token is not done. */ + +static void +c_lex_one_token (c_parser *parser, c_token *token, bool raw = false) +{ + timevar_push (TV_LEX); + + if (raw || vec_safe_length (parser->raw_tokens) == 0) + { + token->type = c_lex_with_flags (&token->value, &token->location, + &token->flags, + (parser->lex_joined_string + ? 0 : C_LEX_STRING_NO_JOIN)); + token->id_kind = C_ID_NONE; + token->keyword = RID_MAX; + token->pragma_kind = PRAGMA_NONE; + } + else + { + /* Use a token previously lexed as a raw look-ahead token, and + complete the processing on it. */ + *token = (*parser->raw_tokens)[parser->raw_tokens_used]; + ++parser->raw_tokens_used; + if (parser->raw_tokens_used == vec_safe_length (parser->raw_tokens)) + { + vec_free (parser->raw_tokens); + parser->raw_tokens_used = 0; + } + } + + if (raw) + goto out; + + switch (token->type) + { + case CPP_NAME: + { + tree decl; + + bool objc_force_identifier = parser->objc_need_raw_identifier; + if (c_dialect_objc ()) + parser->objc_need_raw_identifier = false; + + if (C_IS_RESERVED_WORD (token->value)) + { + enum rid rid_code = C_RID_CODE (token->value); + + if (rid_code == RID_CXX_COMPAT_WARN) + { + warning_at (token->location, + OPT_Wc___compat, + "identifier %qE conflicts with C++ keyword", + token->value); + } + else if (rid_code >= RID_FIRST_ADDR_SPACE + && rid_code <= RID_LAST_ADDR_SPACE) + { + addr_space_t as; + as = (addr_space_t) (rid_code - RID_FIRST_ADDR_SPACE); + targetm.addr_space.diagnose_usage (as, token->location); + token->id_kind = C_ID_ADDRSPACE; + token->keyword = rid_code; + break; + } + else if (c_dialect_objc () && OBJC_IS_PQ_KEYWORD (rid_code)) + { + /* We found an Objective-C "pq" keyword (in, out, + inout, bycopy, byref, oneway). They need special + care because the interpretation depends on the + context. */ + if (parser->objc_pq_context) + { + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + else if (parser->objc_could_be_foreach_context + && rid_code == RID_IN) + { + /* We are in Objective-C, inside a (potential) + foreach context (which means after having + parsed 'for (', but before having parsed ';'), + and we found 'in'. We consider it the keyword + which terminates the declaration at the + beginning of a foreach-statement. Note that + this means you can't use 'in' for anything else + in that context; in particular, in Objective-C + you can't use 'in' as the name of the running + variable in a C for loop. We could potentially + try to add code here to disambiguate, but it + seems a reasonable limitation. */ + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + /* Else, "pq" keywords outside of the "pq" context are + not keywords, and we fall through to the code for + normal tokens. */ + } + else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code)) + { + /* We found an Objective-C "property attribute" + keyword (getter, setter, readonly, etc). These are + only valid in the property context. */ + if (parser->objc_property_attr_context) + { + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + /* Else they are not special keywords. + */ + } + else if (c_dialect_objc () + && (OBJC_IS_AT_KEYWORD (rid_code) + || OBJC_IS_CXX_KEYWORD (rid_code))) + { + /* We found one of the Objective-C "@" keywords (defs, + selector, synchronized, etc) or one of the + Objective-C "cxx" keywords (class, private, + protected, public, try, catch, throw) without a + preceding '@' sign. Do nothing and fall through to + the code for normal tokens (in C++ we would still + consider the CXX ones keywords, but not in C). */ + ; + } + else + { + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + } + + decl = lookup_name (token->value); + if (decl) + { + if (TREE_CODE (decl) == TYPE_DECL) + { + token->id_kind = C_ID_TYPENAME; + break; + } + } + else if (c_dialect_objc ()) + { + tree objc_interface_decl = objc_is_class_name (token->value); + /* Objective-C class names are in the same namespace as + variables and typedefs, and hence are shadowed by local + declarations. */ + if (objc_interface_decl + && (!objc_force_identifier || global_bindings_p ())) + { + token->value = objc_interface_decl; + token->id_kind = C_ID_CLASSNAME; + break; + } + } + token->id_kind = C_ID_ID; + } + break; + case CPP_AT_NAME: + /* This only happens in Objective-C; it must be a keyword. */ + token->type = CPP_KEYWORD; + switch (C_RID_CODE (token->value)) + { + /* Replace 'class' with '@class', 'private' with '@private', + etc. This prevents confusion with the C++ keyword + 'class', and makes the tokens consistent with other + Objective-C 'AT' keywords. For example '@class' is + reported as RID_AT_CLASS which is consistent with + '@synchronized', which is reported as + RID_AT_SYNCHRONIZED. + */ + case RID_CLASS: token->keyword = RID_AT_CLASS; break; + case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break; + case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break; + case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break; + case RID_THROW: token->keyword = RID_AT_THROW; break; + case RID_TRY: token->keyword = RID_AT_TRY; break; + case RID_CATCH: token->keyword = RID_AT_CATCH; break; + case RID_SYNCHRONIZED: token->keyword = RID_AT_SYNCHRONIZED; break; + default: token->keyword = C_RID_CODE (token->value); + } + break; + case CPP_COLON: + case CPP_COMMA: + case CPP_CLOSE_PAREN: + case CPP_SEMICOLON: + /* These tokens may affect the interpretation of any identifiers + following, if doing Objective-C. */ + if (c_dialect_objc ()) + parser->objc_need_raw_identifier = false; + break; + case CPP_PRAGMA: + /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */ + token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value); + token->value = NULL; + break; + default: + break; + } + out: + timevar_pop (TV_LEX); +} + +/* Return a pointer to the next token from PARSER, reading it in if + necessary. */ + +c_token * +c_parser_peek_token (c_parser *parser) +{ + if (parser->tokens_avail == 0) + { + c_lex_one_token (parser, &parser->tokens[0]); + parser->tokens_avail = 1; + } + return &parser->tokens[0]; +} + +/* Return a pointer to the next-but-one token from PARSER, reading it + in if necessary. The next token is already read in. */ + +c_token * +c_parser_peek_2nd_token (c_parser *parser) +{ + if (parser->tokens_avail >= 2) + return &parser->tokens[1]; + gcc_assert (parser->tokens_avail == 1); + gcc_assert (parser->tokens[0].type != CPP_EOF); + gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL); + c_lex_one_token (parser, &parser->tokens[1]); + parser->tokens_avail = 2; + return &parser->tokens[1]; +} + +/* Return a pointer to the Nth token from PARSER, reading it + in if necessary. The N-1th token is already read in. */ + +c_token * +c_parser_peek_nth_token (c_parser *parser, unsigned int n) +{ + /* N is 1-based, not zero-based. */ + gcc_assert (n > 0); + + if (parser->tokens_avail >= n) + return &parser->tokens[n - 1]; + gcc_assert (parser->tokens_avail == n - 1); + c_lex_one_token (parser, &parser->tokens[n - 1]); + parser->tokens_avail = n; + return &parser->tokens[n - 1]; +} + +/* Return a pointer to the Nth token from PARSER, reading it in as a + raw look-ahead token if necessary. The N-1th token is already read + in. Raw look-ahead tokens remain available for when the non-raw + functions above are called. */ + +c_token * +c_parser_peek_nth_token_raw (c_parser *parser, unsigned int n) +{ + /* N is 1-based, not zero-based. */ + gcc_assert (n > 0); + + if (parser->tokens_avail >= n) + return &parser->tokens[n - 1]; + unsigned int raw_len = vec_safe_length (parser->raw_tokens); + unsigned int raw_avail + = parser->tokens_avail + raw_len - parser->raw_tokens_used; + gcc_assert (raw_avail >= n - 1); + if (raw_avail >= n) + return &(*parser->raw_tokens)[parser->raw_tokens_used + + n - 1 - parser->tokens_avail]; + vec_safe_reserve (parser->raw_tokens, 1); + parser->raw_tokens->quick_grow (raw_len + 1); + c_lex_one_token (parser, &(*parser->raw_tokens)[raw_len], true); + return &(*parser->raw_tokens)[raw_len]; +} + +bool +c_keyword_starts_typename (enum rid keyword) +{ + switch (keyword) + { + case RID_UNSIGNED: + case RID_LONG: + case RID_SHORT: + case RID_SIGNED: + case RID_COMPLEX: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + CASE_RID_FLOATN_NX: + case RID_BOOL: + case RID_ENUM: + case RID_STRUCT: + case RID_UNION: + case RID_TYPEOF: + case RID_CONST: + case RID_ATOMIC: + case RID_VOLATILE: + case RID_RESTRICT: + case RID_ATTRIBUTE: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: + case RID_AUTO_TYPE: + case RID_ALIGNAS: + return true; + default: + if (keyword >= RID_FIRST_INT_N + && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS + && int_n_enabled_p[keyword - RID_FIRST_INT_N]) + return true; + return false; + } +} + +/* Return true if TOKEN can start a type name, + false otherwise. */ +bool +c_token_starts_typename (c_token *token) +{ + switch (token->type) + { + case CPP_NAME: + switch (token->id_kind) + { + case C_ID_ID: + return false; + case C_ID_ADDRSPACE: + return true; + case C_ID_TYPENAME: + return true; + case C_ID_CLASSNAME: + gcc_assert (c_dialect_objc ()); + return true; + default: + gcc_unreachable (); + } + case CPP_KEYWORD: + return c_keyword_starts_typename (token->keyword); + case CPP_LESS: + if (c_dialect_objc ()) + return true; + return false; + default: + return false; + } +} + +/* Return true if the next token from PARSER can start a type name, + false otherwise. LA specifies how to do lookahead in order to + detect unknown type names. If unsure, pick CLA_PREFER_ID. */ + +static inline bool +c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la) +{ + c_token *token = c_parser_peek_token (parser); + if (c_token_starts_typename (token)) + return true; + + /* Try a bit harder to detect an unknown typename. */ + if (la != cla_prefer_id + && token->type == CPP_NAME + && token->id_kind == C_ID_ID + + /* Do not try too hard when we could have "object in array". */ + && !parser->objc_could_be_foreach_context + + && (la == cla_prefer_type + || c_parser_peek_2nd_token (parser)->type == CPP_NAME + || c_parser_peek_2nd_token (parser)->type == CPP_MULT) + + /* Only unknown identifiers. */ + && !lookup_name (token->value)) + return true; + + return false; +} + +/* Return true if TOKEN is a type qualifier, false otherwise. */ +static bool +c_token_is_qualifier (c_token *token) +{ + switch (token->type) + { + case CPP_NAME: + switch (token->id_kind) + { + case C_ID_ADDRSPACE: + return true; + default: + return false; + } + case CPP_KEYWORD: + switch (token->keyword) + { + case RID_CONST: + case RID_VOLATILE: + case RID_RESTRICT: + case RID_ATTRIBUTE: + case RID_ATOMIC: + return true; + default: + return false; + } + case CPP_LESS: + return false; + default: + gcc_unreachable (); + } +} + +/* Return true if the next token from PARSER is a type qualifier, + false otherwise. */ +static inline bool +c_parser_next_token_is_qualifier (c_parser *parser) +{ + c_token *token = c_parser_peek_token (parser); + return c_token_is_qualifier (token); +} + +/* Return true if TOKEN can start declaration specifiers (not + including standard attributes), false otherwise. */ +static bool +c_token_starts_declspecs (c_token *token) +{ + switch (token->type) + { + case CPP_NAME: + switch (token->id_kind) + { + case C_ID_ID: + return false; + case C_ID_ADDRSPACE: + return true; + case C_ID_TYPENAME: + return true; + case C_ID_CLASSNAME: + gcc_assert (c_dialect_objc ()); + return true; + default: + gcc_unreachable (); + } + case CPP_KEYWORD: + switch (token->keyword) + { + case RID_STATIC: + case RID_EXTERN: + case RID_REGISTER: + case RID_TYPEDEF: + case RID_INLINE: + case RID_NORETURN: + case RID_AUTO: + case RID_THREAD: + case RID_UNSIGNED: + case RID_LONG: + case RID_SHORT: + case RID_SIGNED: + case RID_COMPLEX: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + CASE_RID_FLOATN_NX: + case RID_BOOL: + case RID_ENUM: + case RID_STRUCT: + case RID_UNION: + case RID_TYPEOF: + case RID_CONST: + case RID_VOLATILE: + case RID_RESTRICT: + case RID_ATTRIBUTE: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: + case RID_ALIGNAS: + case RID_ATOMIC: + case RID_AUTO_TYPE: + return true; + default: + if (token->keyword >= RID_FIRST_INT_N + && token->keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS + && int_n_enabled_p[token->keyword - RID_FIRST_INT_N]) + return true; + return false; + } + case CPP_LESS: + if (c_dialect_objc ()) + return true; + return false; + default: + return false; + } +} + + +/* Return true if TOKEN can start declaration specifiers (not + including standard attributes) or a static assertion, false + otherwise. */ +static bool +c_token_starts_declaration (c_token *token) +{ + if (c_token_starts_declspecs (token) + || token->keyword == RID_STATIC_ASSERT) + return true; + else + return false; +} + +/* Return true if the next token from PARSER can start declaration + specifiers (not including standard attributes), false + otherwise. */ +bool +c_parser_next_token_starts_declspecs (c_parser *parser) +{ + c_token *token = c_parser_peek_token (parser); + + /* In Objective-C, a classname normally starts a declspecs unless it + is immediately followed by a dot. In that case, it is the + Objective-C 2.0 "dot-syntax" for class objects, ie, calls the + setter/getter on the class. c_token_starts_declspecs() can't + differentiate between the two cases because it only checks the + current token, so we have a special check here. */ + if (c_dialect_objc () + && token->type == CPP_NAME + && token->id_kind == C_ID_CLASSNAME + && c_parser_peek_2nd_token (parser)->type == CPP_DOT) + return false; + + return c_token_starts_declspecs (token); +} + +/* Return true if the next tokens from PARSER can start declaration + specifiers (not including standard attributes) or a static + assertion, false otherwise. */ +bool +c_parser_next_tokens_start_declaration (c_parser *parser) +{ + c_token *token = c_parser_peek_token (parser); + + /* Same as above. */ + if (c_dialect_objc () + && token->type == CPP_NAME + && token->id_kind == C_ID_CLASSNAME + && c_parser_peek_2nd_token (parser)->type == CPP_DOT) + return false; + + /* Labels do not start declarations. */ + if (token->type == CPP_NAME + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + return false; + + if (c_token_starts_declaration (token)) + return true; + + if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl)) + return true; + + return false; +} + +/* Consume the next token from PARSER. */ + +void +c_parser_consume_token (c_parser *parser) +{ + gcc_assert (parser->tokens_avail >= 1); + gcc_assert (parser->tokens[0].type != CPP_EOF); + gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL); + gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA); + parser->last_token_location = parser->tokens[0].location; + if (parser->tokens != &parser->tokens_buf[0]) + parser->tokens++; + else if (parser->tokens_avail >= 2) + { + parser->tokens[0] = parser->tokens[1]; + if (parser->tokens_avail >= 3) + { + parser->tokens[1] = parser->tokens[2]; + if (parser->tokens_avail >= 4) + parser->tokens[2] = parser->tokens[3]; + } + } + parser->tokens_avail--; + parser->seen_string_literal = false; +} + +/* Expect the current token to be a #pragma. Consume it and remember + that we've begun parsing a pragma. */ + +static void +c_parser_consume_pragma (c_parser *parser) +{ + gcc_assert (!parser->in_pragma); + gcc_assert (parser->tokens_avail >= 1); + gcc_assert (parser->tokens[0].type == CPP_PRAGMA); + if (parser->tokens != &parser->tokens_buf[0]) + parser->tokens++; + else if (parser->tokens_avail >= 2) + { + parser->tokens[0] = parser->tokens[1]; + if (parser->tokens_avail >= 3) + parser->tokens[1] = parser->tokens[2]; + } + parser->tokens_avail--; + parser->in_pragma = true; +} + +/* Update the global input_location from TOKEN. */ +static inline void +c_parser_set_source_position_from_token (c_token *token) +{ + if (token->type != CPP_EOF) + { + input_location = token->location; + } +} + +/* Helper function for c_parser_error. + Having peeked a token of kind TOK1_KIND that might signify + a conflict marker, peek successor tokens to determine + if we actually do have a conflict marker. + Specifically, we consider a run of 7 '<', '=' or '>' characters + at the start of a line as a conflict marker. + These come through the lexer as three pairs and a single, + e.g. three CPP_LSHIFT ("<<") and a CPP_LESS ('<'). + If it returns true, *OUT_LOC is written to with the location/range + of the marker. */ + +static bool +c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind, + location_t *out_loc) +{ + c_token *token2 = c_parser_peek_2nd_token (parser); + if (token2->type != tok1_kind) + return false; + c_token *token3 = c_parser_peek_nth_token (parser, 3); + if (token3->type != tok1_kind) + return false; + c_token *token4 = c_parser_peek_nth_token (parser, 4); + if (token4->type != conflict_marker_get_final_tok_kind (tok1_kind)) + return false; + + /* It must be at the start of the line. */ + location_t start_loc = c_parser_peek_token (parser)->location; + if (LOCATION_COLUMN (start_loc) != 1) + return false; + + /* We have a conflict marker. Construct a location of the form: + <<<<<<< + ^~~~~~~ + with start == caret, finishing at the end of the marker. */ + location_t finish_loc = get_finish (token4->location); + *out_loc = make_location (start_loc, start_loc, finish_loc); + + return true; +} + +/* Issue a diagnostic of the form + FILE:LINE: MESSAGE before TOKEN + where TOKEN is the next token in the input stream of PARSER. + MESSAGE (specified by the caller) is usually of the form "expected + OTHER-TOKEN". + + Use RICHLOC as the location of the diagnostic. + + Do not issue a diagnostic if still recovering from an error. + + Return true iff an error was actually emitted. + + ??? This is taken from the C++ parser, but building up messages in + this way is not i18n-friendly and some other approach should be + used. */ + +static bool +c_parser_error_richloc (c_parser *parser, const char *gmsgid, + rich_location *richloc) +{ + c_token *token = c_parser_peek_token (parser); + if (parser->error) + return false; + parser->error = true; + if (!gmsgid) + return false; + + /* If this is actually a conflict marker, report it as such. */ + if (token->type == CPP_LSHIFT + || token->type == CPP_RSHIFT + || token->type == CPP_EQ_EQ) + { + location_t loc; + if (c_parser_peek_conflict_marker (parser, token->type, &loc)) + { + error_at (loc, "version control conflict marker in file"); + return true; + } + } + + /* If we were parsing a string-literal and there is an unknown name + token right after, then check to see if that could also have been + a literal string by checking the name against a list of known + standard string literal constants defined in header files. If + there is one, then add that as an hint to the error message. */ + auto_diagnostic_group d; + name_hint h; + if (parser->seen_string_literal && token->type == CPP_NAME) + { + tree name = token->value; + const char *token_name = IDENTIFIER_POINTER (name); + const char *header_hint + = get_c_stdlib_header_for_string_macro_name (token_name); + if (header_hint != NULL) + h = name_hint (NULL, new suggest_missing_header (token->location, + token_name, + header_hint)); + } + + c_parse_error (gmsgid, + /* Because c_parse_error does not understand + CPP_KEYWORD, keywords are treated like + identifiers. */ + (token->type == CPP_KEYWORD ? CPP_NAME : token->type), + /* ??? The C parser does not save the cpp flags of a + token, we need to pass 0 here and we will not get + the source spelling of some tokens but rather the + canonical spelling. */ + token->value, /*flags=*/0, richloc); + return true; +} + +/* As c_parser_error_richloc, but issue the message at the + location of PARSER's next token, or at input_location + if the next token is EOF. */ + +bool +c_parser_error (c_parser *parser, const char *gmsgid) +{ + c_token *token = c_parser_peek_token (parser); + c_parser_set_source_position_from_token (token); + rich_location richloc (line_table, input_location); + return c_parser_error_richloc (parser, gmsgid, &richloc); +} + +/* Some tokens naturally come in pairs e.g.'(' and ')'. + This class is for tracking such a matching pair of symbols. + In particular, it tracks the location of the first token, + so that if the second token is missing, we can highlight the + location of the first token when notifying the user about the + problem. */ + +template +class token_pair +{ + public: + /* token_pair's ctor. */ + token_pair () : m_open_loc (UNKNOWN_LOCATION) {} + + /* If the next token is the opening symbol for this pair, consume it and + return true. + Otherwise, issue an error and return false. + In either case, record the location of the opening token. */ + + bool require_open (c_parser *parser) + { + c_token *token = c_parser_peek_token (parser); + if (token) + m_open_loc = token->location; + + return c_parser_require (parser, traits_t::open_token_type, + traits_t::open_gmsgid); + } + + /* Consume the next token from PARSER, recording its location as + that of the opening token within the pair. */ + + void consume_open (c_parser *parser) + { + c_token *token = c_parser_peek_token (parser); + gcc_assert (token->type == traits_t::open_token_type); + m_open_loc = token->location; + c_parser_consume_token (parser); + } + + /* If the next token is the closing symbol for this pair, consume it + and return true. + Otherwise, issue an error, highlighting the location of the + corresponding opening token, and return false. */ + + bool require_close (c_parser *parser) const + { + return c_parser_require (parser, traits_t::close_token_type, + traits_t::close_gmsgid, m_open_loc); + } + + /* Like token_pair::require_close, except that tokens will be skipped + until the desired token is found. An error message is still produced + if the next token is not as expected. */ + + void skip_until_found_close (c_parser *parser) const + { + c_parser_skip_until_found (parser, traits_t::close_token_type, + traits_t::close_gmsgid, m_open_loc); + } + + private: + location_t m_open_loc; +}; + +/* Traits for token_pair for tracking matching pairs of parentheses. */ + +struct matching_paren_traits +{ + static const enum cpp_ttype open_token_type = CPP_OPEN_PAREN; + static const char * const open_gmsgid; + static const enum cpp_ttype close_token_type = CPP_CLOSE_PAREN; + static const char * const close_gmsgid; +}; + +const char * const matching_paren_traits::open_gmsgid = "expected %<(%>"; +const char * const matching_paren_traits::close_gmsgid = "expected %<)%>"; + +/* "matching_parens" is a token_pair class for tracking matching + pairs of parentheses. */ + +typedef token_pair matching_parens; + +/* Traits for token_pair for tracking matching pairs of braces. */ + +struct matching_brace_traits +{ + static const enum cpp_ttype open_token_type = CPP_OPEN_BRACE; + static const char * const open_gmsgid; + static const enum cpp_ttype close_token_type = CPP_CLOSE_BRACE; + static const char * const close_gmsgid; +}; + +const char * const matching_brace_traits::open_gmsgid = "expected %<{%>"; +const char * const matching_brace_traits::close_gmsgid = "expected %<}%>"; + +/* "matching_braces" is a token_pair class for tracking matching + pairs of braces. */ + +typedef token_pair matching_braces; + +/* Get a description of the matching symbol to TYPE e.g. "(" for + CPP_CLOSE_PAREN. */ + +static const char * +get_matching_symbol (enum cpp_ttype type) +{ + switch (type) + { + default: + gcc_unreachable (); + case CPP_CLOSE_PAREN: + return "("; + case CPP_CLOSE_BRACE: + return "{"; + } +} + +/* If the next token is of the indicated TYPE, consume it. Otherwise, + issue the error MSGID. If MSGID is NULL then a message has already + been produced and no message will be produced this time. Returns + true if found, false otherwise. + + If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it + within any error as the location of an "opening" token matching + the close token TYPE (e.g. the location of the '(' when TYPE is + CPP_CLOSE_PAREN). + + If TYPE_IS_UNIQUE is true (the default) then msgid describes exactly + one type (e.g. "expected %<)%>") and thus it may be reasonable to + attempt to generate a fix-it hint for the problem. + Otherwise msgid describes multiple token types (e.g. + "expected %<;%>, %<,%> or %<)%>"), and thus we shouldn't attempt to + generate a fix-it hint. */ + +bool +c_parser_require (c_parser *parser, + enum cpp_ttype type, + const char *msgid, + location_t matching_location, + bool type_is_unique) +{ + if (c_parser_next_token_is (parser, type)) + { + c_parser_consume_token (parser); + return true; + } + else + { + location_t next_token_loc = c_parser_peek_token (parser)->location; + gcc_rich_location richloc (next_token_loc); + + /* Potentially supply a fix-it hint, suggesting to add the + missing token immediately after the *previous* token. + This may move the primary location within richloc. */ + if (!parser->error && type_is_unique) + maybe_suggest_missing_token_insertion (&richloc, type, + parser->last_token_location); + + /* If matching_location != UNKNOWN_LOCATION, highlight it. + Attempt to consolidate diagnostics by printing it as a + secondary range within the main diagnostic. */ + bool added_matching_location = false; + if (matching_location != UNKNOWN_LOCATION) + added_matching_location + = richloc.add_location_if_nearby (matching_location); + + if (c_parser_error_richloc (parser, msgid, &richloc)) + /* If we weren't able to consolidate matching_location, then + print it as a secondary diagnostic. */ + if (matching_location != UNKNOWN_LOCATION && !added_matching_location) + inform (matching_location, "to match this %qs", + get_matching_symbol (type)); + + return false; + } +} + +/* If the next token is the indicated keyword, consume it. Otherwise, + issue the error MSGID. Returns true if found, false otherwise. */ + +static bool +c_parser_require_keyword (c_parser *parser, + enum rid keyword, + const char *msgid) +{ + if (c_parser_next_token_is_keyword (parser, keyword)) + { + c_parser_consume_token (parser); + return true; + } + else + { + c_parser_error (parser, msgid); + return false; + } +} + +/* Like c_parser_require, except that tokens will be skipped until the + desired token is found. An error message is still produced if the + next token is not as expected. If MSGID is NULL then a message has + already been produced and no message will be produced this + time. + + If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it + within any error as the location of an "opening" token matching + the close token TYPE (e.g. the location of the '(' when TYPE is + CPP_CLOSE_PAREN). */ + +void +c_parser_skip_until_found (c_parser *parser, + enum cpp_ttype type, + const char *msgid, + location_t matching_location) +{ + unsigned nesting_depth = 0; + + if (c_parser_require (parser, type, msgid, matching_location)) + return; + + /* Skip tokens until the desired token is found. */ + while (true) + { + /* Peek at the next token. */ + c_token *token = c_parser_peek_token (parser); + /* If we've reached the token we want, consume it and stop. */ + if (token->type == type && !nesting_depth) + { + c_parser_consume_token (parser); + break; + } + + /* If we've run out of tokens, stop. */ + if (token->type == CPP_EOF) + return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; + if (token->type == CPP_OPEN_BRACE + || token->type == CPP_OPEN_PAREN + || token->type == CPP_OPEN_SQUARE) + ++nesting_depth; + else if (token->type == CPP_CLOSE_BRACE + || token->type == CPP_CLOSE_PAREN + || token->type == CPP_CLOSE_SQUARE) + { + if (nesting_depth-- == 0) + break; + } + /* Consume this token. */ + c_parser_consume_token (parser); + } + parser->error = false; +} + +/* Skip tokens until the end of a parameter is found, but do not + consume the comma, semicolon or closing delimiter. */ + +static void +c_parser_skip_to_end_of_parameter (c_parser *parser) +{ + unsigned nesting_depth = 0; + + while (true) + { + c_token *token = c_parser_peek_token (parser); + if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON) + && !nesting_depth) + break; + /* If we've run out of tokens, stop. */ + if (token->type == CPP_EOF) + return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; + if (token->type == CPP_OPEN_BRACE + || token->type == CPP_OPEN_PAREN + || token->type == CPP_OPEN_SQUARE) + ++nesting_depth; + else if (token->type == CPP_CLOSE_BRACE + || token->type == CPP_CLOSE_PAREN + || token->type == CPP_CLOSE_SQUARE) + { + if (nesting_depth-- == 0) + break; + } + /* Consume this token. */ + c_parser_consume_token (parser); + } + parser->error = false; +} + +/* Expect to be at the end of the pragma directive and consume an + end of line marker. */ + +static void +c_parser_skip_to_pragma_eol (c_parser *parser, bool error_if_not_eol = true) +{ + gcc_assert (parser->in_pragma); + parser->in_pragma = false; + + if (error_if_not_eol && c_parser_peek_token (parser)->type != CPP_PRAGMA_EOL) + c_parser_error (parser, "expected end of line"); + + cpp_ttype token_type; + do + { + c_token *token = c_parser_peek_token (parser); + token_type = token->type; + if (token_type == CPP_EOF) + break; + c_parser_consume_token (parser); + } + while (token_type != CPP_PRAGMA_EOL); + + parser->error = false; +} + +/* Skip tokens until we have consumed an entire block, or until we + have consumed a non-nested ';'. */ + +static void +c_parser_skip_to_end_of_block_or_statement (c_parser *parser) +{ + unsigned nesting_depth = 0; + bool save_error = parser->error; + + while (true) + { + c_token *token; + + /* Peek at the next token. */ + token = c_parser_peek_token (parser); + + switch (token->type) + { + case CPP_EOF: + return; + + case CPP_PRAGMA_EOL: + if (parser->in_pragma) + return; + break; + + case CPP_SEMICOLON: + /* If the next token is a ';', we have reached the + end of the statement. */ + if (!nesting_depth) + { + /* Consume the ';'. */ + c_parser_consume_token (parser); + goto finished; + } + break; + + case CPP_CLOSE_BRACE: + /* If the next token is a non-nested '}', then we have + reached the end of the current block. */ + if (nesting_depth == 0 || --nesting_depth == 0) + { + c_parser_consume_token (parser); + goto finished; + } + break; + + case CPP_OPEN_BRACE: + /* If it the next token is a '{', then we are entering a new + block. Consume the entire block. */ + ++nesting_depth; + break; + + case CPP_PRAGMA: + /* If we see a pragma, consume the whole thing at once. We + have some safeguards against consuming pragmas willy-nilly. + Normally, we'd expect to be here with parser->error set, + which disables these safeguards. But it's possible to get + here for secondary error recovery, after parser->error has + been cleared. */ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + parser->error = save_error; + continue; + + default: + break; + } + + c_parser_consume_token (parser); + } + + finished: + parser->error = false; +} + +/* CPP's options (initialized by c-opts.c). */ +extern cpp_options *cpp_opts; + +/* Save the warning flags which are controlled by __extension__. */ + +static inline int +disable_extension_diagnostics (void) +{ + int ret = (pedantic + | (warn_pointer_arith << 1) + | (warn_traditional << 2) + | (flag_iso << 3) + | (warn_long_long << 4) + | (warn_cxx_compat << 5) + | (warn_overlength_strings << 6) + /* warn_c90_c99_compat has three states: -1/0/1, so we must + play tricks to properly restore it. */ + | ((warn_c90_c99_compat == 1) << 7) + | ((warn_c90_c99_compat == -1) << 8) + /* Similarly for warn_c99_c11_compat. */ + | ((warn_c99_c11_compat == 1) << 9) + | ((warn_c99_c11_compat == -1) << 10) + /* Similarly for warn_c11_c2x_compat. */ + | ((warn_c11_c2x_compat == 1) << 11) + | ((warn_c11_c2x_compat == -1) << 12) + ); + cpp_opts->cpp_pedantic = pedantic = 0; + warn_pointer_arith = 0; + cpp_opts->cpp_warn_traditional = warn_traditional = 0; + flag_iso = 0; + cpp_opts->cpp_warn_long_long = warn_long_long = 0; + warn_cxx_compat = 0; + warn_overlength_strings = 0; + warn_c90_c99_compat = 0; + warn_c99_c11_compat = 0; + warn_c11_c2x_compat = 0; + return ret; +} + +/* Restore the warning flags which are controlled by __extension__. + FLAGS is the return value from disable_extension_diagnostics. */ + +static inline void +restore_extension_diagnostics (int flags) +{ + cpp_opts->cpp_pedantic = pedantic = flags & 1; + warn_pointer_arith = (flags >> 1) & 1; + cpp_opts->cpp_warn_traditional = warn_traditional = (flags >> 2) & 1; + flag_iso = (flags >> 3) & 1; + cpp_opts->cpp_warn_long_long = warn_long_long = (flags >> 4) & 1; + warn_cxx_compat = (flags >> 5) & 1; + warn_overlength_strings = (flags >> 6) & 1; + /* See above for why is this needed. */ + warn_c90_c99_compat = (flags >> 7) & 1 ? 1 : ((flags >> 8) & 1 ? -1 : 0); + warn_c99_c11_compat = (flags >> 9) & 1 ? 1 : ((flags >> 10) & 1 ? -1 : 0); + warn_c11_c2x_compat = (flags >> 11) & 1 ? 1 : ((flags >> 12) & 1 ? -1 : 0); +} + +/* Helper data structure for parsing #pragma acc routine. */ +struct oacc_routine_data { + bool error_seen; /* Set if error has been reported. */ + bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ + tree clauses; + location_t loc; +}; + +/* Used for parsing objc foreach statements. */ +static tree objc_foreach_break_label, objc_foreach_continue_label; + +static bool c_parser_nth_token_starts_std_attributes (c_parser *, + unsigned int); +static tree c_parser_std_attribute_specifier_sequence (c_parser *); +static void c_parser_external_declaration (c_parser *); +static void c_parser_asm_definition (c_parser *); +static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, + bool, bool, tree * = NULL, + vec * = NULL, + bool have_attrs = false, + tree attrs = NULL, + struct oacc_routine_data * = NULL, + bool * = NULL); +static void c_parser_static_assert_declaration_no_semi (c_parser *); +static void c_parser_static_assert_declaration (c_parser *); +static struct c_typespec c_parser_enum_specifier (c_parser *); +static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); +static tree c_parser_struct_declaration (c_parser *); +static struct c_typespec c_parser_typeof_specifier (c_parser *); +static tree c_parser_alignas_specifier (c_parser *); +static struct c_declarator *c_parser_direct_declarator (c_parser *, bool, + c_dtr_syn, bool *); +static struct c_declarator *c_parser_direct_declarator_inner (c_parser *, + bool, + struct c_declarator *); +static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree, + bool); +static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree, + tree, bool); +static struct c_parm *c_parser_parameter_declaration (c_parser *, tree, bool); +static tree c_parser_simple_asm_expr (c_parser *); +static tree c_parser_gnu_attributes (c_parser *); +static struct c_expr c_parser_initializer (c_parser *); +static struct c_expr c_parser_braced_init (c_parser *, tree, bool, + struct obstack *); +static void c_parser_initelt (c_parser *, struct obstack *); +static void c_parser_initval (c_parser *, struct c_expr *, + struct obstack *); +static tree c_parser_compound_statement (c_parser *, location_t * = NULL); +static location_t c_parser_compound_statement_nostart (c_parser *); +static void c_parser_label (c_parser *, tree); +static void c_parser_statement (c_parser *, bool *, location_t * = NULL); +static void c_parser_statement_after_labels (c_parser *, bool *, + vec * = NULL); +static tree c_parser_c99_block_statement (c_parser *, bool *, + location_t * = NULL); +static void c_parser_if_statement (c_parser *, bool *, vec *); +static void c_parser_switch_statement (c_parser *, bool *); +static void c_parser_while_statement (c_parser *, bool, unsigned short, bool *); +static void c_parser_do_statement (c_parser *, bool, unsigned short); +static void c_parser_for_statement (c_parser *, bool, unsigned short, bool *); +static tree c_parser_asm_statement (c_parser *); +static tree c_parser_asm_operands (c_parser *); +static tree c_parser_asm_goto_operands (c_parser *); +static tree c_parser_asm_clobbers (c_parser *); +static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *, + tree = NULL_TREE); +static struct c_expr c_parser_conditional_expression (c_parser *, + struct c_expr *, tree); +static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, + tree); +static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); +static struct c_expr c_parser_unary_expression (c_parser *); +static struct c_expr c_parser_sizeof_expression (c_parser *); +static struct c_expr c_parser_alignof_expression (c_parser *); +static struct c_expr c_parser_postfix_expression (c_parser *); +static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *, + struct c_type_name *, + location_t); +static struct c_expr c_parser_postfix_expression_after_primary (c_parser *, + location_t loc, + struct c_expr); +static tree c_parser_transaction (c_parser *, enum rid); +static struct c_expr c_parser_transaction_expression (c_parser *, enum rid); +static tree c_parser_transaction_cancel (c_parser *); +static struct c_expr c_parser_expression (c_parser *); +static struct c_expr c_parser_expression_conv (c_parser *); +static vec *c_parser_expr_list (c_parser *, bool, bool, + vec **, location_t *, + tree *, vec *, + unsigned int * = NULL); +static struct c_expr c_parser_has_attribute_expression (c_parser *); + +static void c_parser_oacc_declare (c_parser *); +static void c_parser_oacc_enter_exit_data (c_parser *, bool); +static void c_parser_oacc_update (c_parser *); +static void c_parser_omp_construct (c_parser *, bool *); +static void c_parser_omp_threadprivate (c_parser *); +static void c_parser_omp_barrier (c_parser *); +static void c_parser_omp_depobj (c_parser *); +static void c_parser_omp_flush (c_parser *); +static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, + tree, tree *, bool *); +static void c_parser_omp_taskwait (c_parser *); +static void c_parser_omp_taskyield (c_parser *); +static void c_parser_omp_cancel (c_parser *); +static void c_parser_omp_nothing (c_parser *); + +enum pragma_context { pragma_external, pragma_struct, pragma_param, + pragma_stmt, pragma_compound }; +static bool c_parser_pragma (c_parser *, enum pragma_context, bool *); +static bool c_parser_omp_cancellation_point (c_parser *, enum pragma_context); +static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *); +static void c_parser_omp_end_declare_target (c_parser *); +static bool c_parser_omp_declare (c_parser *, enum pragma_context); +static void c_parser_omp_requires (c_parser *); +static bool c_parser_omp_error (c_parser *, enum pragma_context); +static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *); +static void c_parser_oacc_routine (c_parser *, enum pragma_context); + +/* These Objective-C parser functions are only ever called when + compiling Objective-C. */ +static void c_parser_objc_class_definition (c_parser *, tree); +static void c_parser_objc_class_instance_variables (c_parser *); +static void c_parser_objc_class_declaration (c_parser *); +static void c_parser_objc_alias_declaration (c_parser *); +static void c_parser_objc_protocol_definition (c_parser *, tree); +static bool c_parser_objc_method_type (c_parser *); +static void c_parser_objc_method_definition (c_parser *); +static void c_parser_objc_methodprotolist (c_parser *); +static void c_parser_objc_methodproto (c_parser *); +static tree c_parser_objc_method_decl (c_parser *, bool, tree *, tree *); +static tree c_parser_objc_type_name (c_parser *); +static tree c_parser_objc_protocol_refs (c_parser *); +static void c_parser_objc_try_catch_finally_statement (c_parser *); +static void c_parser_objc_synchronized_statement (c_parser *); +static tree c_parser_objc_selector (c_parser *); +static tree c_parser_objc_selector_arg (c_parser *); +static tree c_parser_objc_receiver (c_parser *); +static tree c_parser_objc_message_args (c_parser *); +static tree c_parser_objc_keywordexpr (c_parser *); +static void c_parser_objc_at_property_declaration (c_parser *); +static void c_parser_objc_at_synthesize_declaration (c_parser *); +static void c_parser_objc_at_dynamic_declaration (c_parser *); +static bool c_parser_objc_diagnose_bad_element_prefix + (c_parser *, struct c_declspecs *); +static location_t c_parser_parse_rtl_body (c_parser *, char *); + +/* Parse a translation unit (C90 6.7, C99 6.9, C11 6.9). + + translation-unit: + external-declarations + + external-declarations: + external-declaration + external-declarations external-declaration + + GNU extensions: + + translation-unit: + empty +*/ + +static void +c_parser_translation_unit (c_parser *parser) +{ + if (c_parser_next_token_is (parser, CPP_EOF)) + { + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "ISO C forbids an empty translation unit"); + } + else + { + void *obstack_position = obstack_alloc (&parser_obstack, 0); + mark_valid_location_for_stdc_pragma (false); + do + { + ggc_collect (); + c_parser_external_declaration (parser); + obstack_free (&parser_obstack, obstack_position); + } + while (c_parser_next_token_is_not (parser, CPP_EOF)); + } + + unsigned int i; + tree decl; + FOR_EACH_VEC_ELT (incomplete_record_decls, i, decl) + if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node) + error ("storage size of %q+D isn%'t known", decl); + + if (current_omp_declare_target_attribute) + { + if (!errorcount) + error ("%<#pragma omp declare target%> without corresponding " + "%<#pragma omp end declare target%>"); + current_omp_declare_target_attribute = 0; + } +} + +/* Parse an external declaration (C90 6.7, C99 6.9, C11 6.9). + + external-declaration: + function-definition + declaration + + GNU extensions: + + external-declaration: + asm-definition + ; + __extension__ external-declaration + + Objective-C: + + external-declaration: + objc-class-definition + objc-class-declaration + objc-alias-declaration + objc-protocol-definition + objc-method-definition + @end +*/ + +static void +c_parser_external_declaration (c_parser *parser) +{ + int ext; + switch (c_parser_peek_token (parser)->type) + { + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_EXTENSION: + ext = disable_extension_diagnostics (); + c_parser_consume_token (parser); + c_parser_external_declaration (parser); + restore_extension_diagnostics (ext); + break; + case RID_ASM: + c_parser_asm_definition (parser); + break; + case RID_AT_INTERFACE: + case RID_AT_IMPLEMENTATION: + gcc_assert (c_dialect_objc ()); + c_parser_objc_class_definition (parser, NULL_TREE); + break; + case RID_AT_CLASS: + gcc_assert (c_dialect_objc ()); + c_parser_objc_class_declaration (parser); + break; + case RID_AT_ALIAS: + gcc_assert (c_dialect_objc ()); + c_parser_objc_alias_declaration (parser); + break; + case RID_AT_PROTOCOL: + gcc_assert (c_dialect_objc ()); + c_parser_objc_protocol_definition (parser, NULL_TREE); + break; + case RID_AT_PROPERTY: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_property_declaration (parser); + break; + case RID_AT_SYNTHESIZE: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_synthesize_declaration (parser); + break; + case RID_AT_DYNAMIC: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_dynamic_declaration (parser); + break; + case RID_AT_END: + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + objc_finish_implementation (); + break; + default: + goto decl_or_fndef; + } + break; + case CPP_SEMICOLON: + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "ISO C does not allow extra %<;%> outside of a function"); + c_parser_consume_token (parser); + break; + case CPP_PRAGMA: + mark_valid_location_for_stdc_pragma (true); + c_parser_pragma (parser, pragma_external, NULL); + mark_valid_location_for_stdc_pragma (false); + break; + case CPP_PLUS: + case CPP_MINUS: + if (c_dialect_objc ()) + { + c_parser_objc_method_definition (parser); + break; + } + /* Else fall through, and yield a syntax error trying to parse + as a declaration or function definition. */ + /* FALLTHRU */ + default: + decl_or_fndef: + /* A declaration or a function definition (or, in Objective-C, + an @interface or @protocol with prefix attributes). We can + only tell which after parsing the declaration specifiers, if + any, and the first declarator. */ + c_parser_declaration_or_fndef (parser, true, true, true, false, true); + break; + } +} + +static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec *); +static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool); + +/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */ + +static void +add_debug_begin_stmt (location_t loc) +{ + /* Don't add DEBUG_BEGIN_STMTs outside of functions, see PR84721. */ + if (!MAY_HAVE_DEBUG_MARKER_STMTS || !building_stmt_list_p ()) + return; + + tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node); + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); +} + +/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 + 6.7, 6.9.1, C11 6.7, 6.9.1). If FNDEF_OK is true, a function definition + is accepted; otherwise (old-style parameter declarations) only other + declarations are accepted. If STATIC_ASSERT_OK is true, a static + assertion is accepted; otherwise (old-style parameter declarations) + it is not. If NESTED is true, we are inside a function or parsing + old-style parameter declarations; any functions encountered are + nested functions and declaration specifiers are required; otherwise + we are at top level and functions are normal functions and + declaration specifiers may be optional. If EMPTY_OK is true, empty + declarations are OK (subject to all other constraints); otherwise + (old-style parameter declarations) they are diagnosed. If + START_ATTR_OK is true, the declaration specifiers may start with + attributes (GNU or standard); otherwise they may not. + OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed + declaration when parsing an Objective-C foreach statement. + FALLTHRU_ATTR_P is used to signal whether this function parsed + "__attribute__((fallthrough));". ATTRS are any standard attributes + parsed in the caller (in contexts where such attributes had to be + parsed to determine whether what follows is a declaration or a + statement); HAVE_ATTRS says whether there were any such attributes + (even empty). + + declaration: + declaration-specifiers init-declarator-list[opt] ; + static_assert-declaration + + function-definition: + declaration-specifiers[opt] declarator declaration-list[opt] + compound-statement + + declaration-list: + declaration + declaration-list declaration + + init-declarator-list: + init-declarator + init-declarator-list , init-declarator + + init-declarator: + declarator simple-asm-expr[opt] gnu-attributes[opt] + declarator simple-asm-expr[opt] gnu-attributes[opt] = initializer + + GNU extensions: + + nested-function-definition: + declaration-specifiers declarator declaration-list[opt] + compound-statement + + attribute ; + + Objective-C: + gnu-attributes objc-class-definition + gnu-attributes objc-category-definition + gnu-attributes objc-protocol-definition + + The simple-asm-expr and gnu-attributes are GNU extensions. + + This function does not handle __extension__; that is handled in its + callers. ??? Following the old parser, __extension__ may start + external declarations, declarations in functions and declarations + at the start of "for" loops, but not old-style parameter + declarations. + + C99 requires declaration specifiers in a function definition; the + absence is diagnosed through the diagnosis of implicit int. In GNU + C we also allow but diagnose declarations without declaration + specifiers, but only at top level (elsewhere they conflict with + other syntax). + + In Objective-C, declarations of the looping variable in a foreach + statement are exceptionally terminated by 'in' (for example, 'for + (NSObject *object in array) { ... }'). + + OpenMP: + + declaration: + threadprivate-directive + + GIMPLE: + + gimple-function-definition: + declaration-specifiers[opt] __GIMPLE (gimple-or-rtl-pass-list) declarator + declaration-list[opt] compound-statement + + rtl-function-definition: + declaration-specifiers[opt] __RTL (gimple-or-rtl-pass-list) declarator + declaration-list[opt] compound-statement */ + +static void +c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, + bool static_assert_ok, bool empty_ok, + bool nested, bool start_attr_ok, + tree *objc_foreach_object_declaration + /* = NULL */, + vec *omp_declare_simd_clauses + /* = NULL */, + bool have_attrs /* = false */, + tree attrs /* = NULL_TREE */, + struct oacc_routine_data *oacc_routine_data + /* = NULL */, + bool *fallthru_attr_p /* = NULL */) +{ + struct c_declspecs *specs; + tree prefix_attrs; + tree all_prefix_attrs; + bool diagnosed_no_specs = false; + location_t here = c_parser_peek_token (parser)->location; + + add_debug_begin_stmt (c_parser_peek_token (parser)->location); + + if (static_assert_ok + && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) + { + c_parser_static_assert_declaration (parser); + return; + } + specs = build_null_declspecs (); + + /* Handle any standard attributes parsed in the caller. */ + if (have_attrs) + { + declspecs_add_attrs (here, specs, attrs); + specs->non_std_attrs_seen_p = false; + } + + /* Try to detect an unknown type name when we have "A B" or "A *B". */ + if (c_parser_peek_token (parser)->type == CPP_NAME + && c_parser_peek_token (parser)->id_kind == C_ID_ID + && (c_parser_peek_2nd_token (parser)->type == CPP_NAME + || c_parser_peek_2nd_token (parser)->type == CPP_MULT) + && (!nested || !lookup_name (c_parser_peek_token (parser)->value))) + { + tree name = c_parser_peek_token (parser)->value; + + /* Issue a warning about NAME being an unknown type name, perhaps + with some kind of hint. + If the user forgot a "struct" etc, suggest inserting + it. Otherwise, attempt to look for misspellings. */ + gcc_rich_location richloc (here); + if (tag_exists_p (RECORD_TYPE, name)) + { + /* This is not C++ with its implicit typedef. */ + richloc.add_fixit_insert_before ("struct "); + error_at (&richloc, + "unknown type name %qE;" + " use % keyword to refer to the type", + name); + } + else if (tag_exists_p (UNION_TYPE, name)) + { + richloc.add_fixit_insert_before ("union "); + error_at (&richloc, + "unknown type name %qE;" + " use % keyword to refer to the type", + name); + } + else if (tag_exists_p (ENUMERAL_TYPE, name)) + { + richloc.add_fixit_insert_before ("enum "); + error_at (&richloc, + "unknown type name %qE;" + " use % keyword to refer to the type", + name); + } + else + { + auto_diagnostic_group d; + name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME, + here); + if (const char *suggestion = hint.suggestion ()) + { + richloc.add_fixit_replace (suggestion); + error_at (&richloc, + "unknown type name %qE; did you mean %qs?", + name, suggestion); + } + else + error_at (here, "unknown type name %qE", name); + } + + /* Parse declspecs normally to get a correct pointer type, but avoid + a further "fails to be a type name" error. Refuse nested functions + since it is not how the user likely wants us to recover. */ + c_parser_peek_token (parser)->type = CPP_KEYWORD; + c_parser_peek_token (parser)->keyword = RID_VOID; + c_parser_peek_token (parser)->value = error_mark_node; + fndef_ok = !nested; + } + + /* When there are standard attributes at the start of the + declaration (to apply to the entity being declared), an + init-declarator-list or function definition must be present. */ + if (c_parser_nth_token_starts_std_attributes (parser, 1)) + have_attrs = true; + + c_parser_declspecs (parser, specs, true, true, start_attr_ok, + true, true, start_attr_ok, true, cla_nonabstract_decl); + if (parser->error) + { + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + if (nested && !specs->declspecs_seen_p) + { + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + + finish_declspecs (specs); + bool auto_type_p = specs->typespec_word == cts_auto_type; + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + if (auto_type_p) + error_at (here, "%<__auto_type%> in empty declaration"); + else if (specs->typespec_kind == ctsk_none + && attribute_fallthrough_p (specs->attrs)) + { + if (fallthru_attr_p != NULL) + *fallthru_attr_p = true; + if (nested) + { + tree fn = build_call_expr_internal_loc (here, IFN_FALLTHROUGH, + void_type_node, 0); + add_stmt (fn); + } + else + pedwarn (here, OPT_Wattributes, + "% attribute at top level"); + } + else if (empty_ok && !(have_attrs + && specs->non_std_attrs_seen_p)) + shadow_tag (specs); + else + { + shadow_tag_warned (specs, 1); + pedwarn (here, 0, "empty declaration"); + } + c_parser_consume_token (parser); + if (oacc_routine_data) + c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); + return; + } + + /* Provide better error recovery. Note that a type name here is usually + better diagnosed as a redeclaration. */ + if (empty_ok + && specs->typespec_kind == ctsk_tagdef + && c_parser_next_token_starts_declspecs (parser) + && !c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %<;%>, identifier or %<(%>"); + parser->error = false; + shadow_tag_warned (specs, 1); + return; + } + else if (c_dialect_objc () && !auto_type_p) + { + /* Prefix attributes are an error on method decls. */ + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + case CPP_MINUS: + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + if (specs->attrs) + { + warning_at (c_parser_peek_token (parser)->location, + OPT_Wattributes, + "prefix attributes are ignored for methods"); + specs->attrs = NULL_TREE; + } + if (fndef_ok) + c_parser_objc_method_definition (parser); + else + c_parser_objc_methodproto (parser); + return; + break; + default: + break; + } + /* This is where we parse 'attributes @interface ...', + 'attributes @implementation ...', 'attributes @protocol ...' + (where attributes could be, for example, __attribute__ + ((deprecated)). + */ + switch (c_parser_peek_token (parser)->keyword) + { + case RID_AT_INTERFACE: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + c_parser_objc_class_definition (parser, specs->attrs); + return; + } + break; + case RID_AT_IMPLEMENTATION: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + if (specs->attrs) + { + warning_at (c_parser_peek_token (parser)->location, + OPT_Wattributes, + "prefix attributes are ignored for implementations"); + specs->attrs = NULL_TREE; + } + c_parser_objc_class_definition (parser, NULL_TREE); + return; + } + break; + case RID_AT_PROTOCOL: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + c_parser_objc_protocol_definition (parser, specs->attrs); + return; + } + break; + case RID_AT_ALIAS: + case RID_AT_CLASS: + case RID_AT_END: + case RID_AT_PROPERTY: + if (specs->attrs) + { + c_parser_error (parser, "unexpected attribute"); + specs->attrs = NULL; + } + break; + default: + break; + } + } + else if (attribute_fallthrough_p (specs->attrs)) + warning_at (here, OPT_Wattributes, + "% attribute not followed by %<;%>"); + + pending_xref_error (); + prefix_attrs = specs->attrs; + all_prefix_attrs = prefix_attrs; + specs->attrs = NULL_TREE; + while (true) + { + struct c_declarator *declarator; + bool dummy = false; + timevar_id_t tv; + tree fnbody = NULL_TREE; + /* Declaring either one or more declarators (in which case we + should diagnose if there were no declaration specifiers) or a + function definition (in which case the diagnostic for + implicit int suffices). */ + declarator = c_parser_declarator (parser, + specs->typespec_kind != ctsk_none, + C_DTR_NORMAL, &dummy); + if (declarator == NULL) + { + if (omp_declare_simd_clauses) + c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE, + omp_declare_simd_clauses); + if (oacc_routine_data) + c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + if (auto_type_p && declarator->kind != cdk_id) + { + error_at (here, + "%<__auto_type%> requires a plain identifier" + " as declarator"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + if (c_parser_next_token_is (parser, CPP_EQ) + || c_parser_next_token_is (parser, CPP_COMMA) + || c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is_keyword (parser, RID_ASM) + || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE) + || c_parser_next_token_is_keyword (parser, RID_IN)) + { + tree asm_name = NULL_TREE; + tree postfix_attrs = NULL_TREE; + if (!diagnosed_no_specs && !specs->declspecs_seen_p) + { + diagnosed_no_specs = true; + pedwarn (here, 0, "data definition has no type or storage class"); + } + /* Having seen a data definition, there cannot now be a + function definition. */ + fndef_ok = false; + if (c_parser_next_token_is_keyword (parser, RID_ASM)) + asm_name = c_parser_simple_asm_expr (parser); + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + { + postfix_attrs = c_parser_gnu_attributes (parser); + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + /* This means there is an attribute specifier after + the declarator in a function definition. Provide + some more information for the user. */ + error_at (here, "attributes should be specified before the " + "declarator in a function definition"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + } + if (c_parser_next_token_is (parser, CPP_EQ)) + { + tree d; + struct c_expr init; + location_t init_loc; + c_parser_consume_token (parser); + if (auto_type_p) + { + init_loc = c_parser_peek_token (parser)->location; + rich_location richloc (line_table, init_loc); + start_init (NULL_TREE, asm_name, global_bindings_p (), &richloc); + /* A parameter is initialized, which is invalid. Don't + attempt to instrument the initializer. */ + int flag_sanitize_save = flag_sanitize; + if (nested && !empty_ok) + flag_sanitize = 0; + init = c_parser_expr_no_commas (parser, NULL); + flag_sanitize = flag_sanitize_save; + if (TREE_CODE (init.value) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1))) + error_at (here, + "%<__auto_type%> used with a bit-field" + " initializer"); + init = convert_lvalue_to_rvalue (init_loc, init, true, true); + tree init_type = TREE_TYPE (init.value); + bool vm_type = variably_modified_type_p (init_type, + NULL_TREE); + if (vm_type) + init.value = save_expr (init.value); + finish_init (); + specs->typespec_kind = ctsk_typeof; + specs->locations[cdw_typedef] = init_loc; + specs->typedef_p = true; + specs->type = init_type; + if (vm_type) + { + bool maybe_const = true; + tree type_expr = c_fully_fold (init.value, false, + &maybe_const); + specs->expr_const_operands &= maybe_const; + if (specs->expr) + specs->expr = build2 (COMPOUND_EXPR, + TREE_TYPE (type_expr), + specs->expr, type_expr); + else + specs->expr = type_expr; + } + d = start_decl (declarator, specs, true, + chainon (postfix_attrs, all_prefix_attrs)); + if (!d) + d = error_mark_node; + if (omp_declare_simd_clauses) + c_finish_omp_declare_simd (parser, d, NULL_TREE, + omp_declare_simd_clauses); + } + else + { + /* The declaration of the variable is in effect while + its initializer is parsed. */ + d = start_decl (declarator, specs, true, + chainon (postfix_attrs, all_prefix_attrs)); + if (!d) + d = error_mark_node; + if (omp_declare_simd_clauses) + c_finish_omp_declare_simd (parser, d, NULL_TREE, + omp_declare_simd_clauses); + init_loc = c_parser_peek_token (parser)->location; + rich_location richloc (line_table, init_loc); + start_init (d, asm_name, global_bindings_p (), &richloc); + /* A parameter is initialized, which is invalid. Don't + attempt to instrument the initializer. */ + int flag_sanitize_save = flag_sanitize; + if (TREE_CODE (d) == PARM_DECL) + flag_sanitize = 0; + init = c_parser_initializer (parser); + flag_sanitize = flag_sanitize_save; + finish_init (); + } + if (oacc_routine_data) + c_finish_oacc_routine (oacc_routine_data, d, false); + if (d != error_mark_node) + { + maybe_warn_string_init (init_loc, TREE_TYPE (d), init); + finish_decl (d, init_loc, init.value, + init.original_type, asm_name); + } + } + else + { + if (auto_type_p) + { + error_at (here, + "%<__auto_type%> requires an initialized " + "data declaration"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + + location_t lastloc = UNKNOWN_LOCATION; + tree attrs = chainon (postfix_attrs, all_prefix_attrs); + tree d = start_decl (declarator, specs, false, attrs, &lastloc); + if (d && TREE_CODE (d) == FUNCTION_DECL) + { + /* Find the innermost declarator that is neither cdk_id + nor cdk_attrs. */ + const struct c_declarator *decl = declarator; + const struct c_declarator *last_non_id_attrs = NULL; + + while (decl) + switch (decl->kind) + { + case cdk_array: + case cdk_function: + case cdk_pointer: + last_non_id_attrs = decl; + decl = decl->declarator; + break; + + case cdk_attrs: + decl = decl->declarator; + break; + + case cdk_id: + decl = 0; + break; + + default: + gcc_unreachable (); + } + + /* If it exists and is cdk_function declaration whose + arguments have not been set yet, use its arguments. */ + if (last_non_id_attrs + && last_non_id_attrs->kind == cdk_function) + { + tree parms = last_non_id_attrs->u.arg_info->parms; + if (DECL_ARGUMENTS (d) == NULL_TREE + && DECL_INITIAL (d) == NULL_TREE) + DECL_ARGUMENTS (d) = parms; + + warn_parm_array_mismatch (lastloc, d, parms); + } + } + if (omp_declare_simd_clauses) + { + tree parms = NULL_TREE; + if (d && TREE_CODE (d) == FUNCTION_DECL) + { + struct c_declarator *ce = declarator; + while (ce != NULL) + if (ce->kind == cdk_function) + { + parms = ce->u.arg_info->parms; + break; + } + else + ce = ce->declarator; + } + if (parms) + temp_store_parm_decls (d, parms); + c_finish_omp_declare_simd (parser, d, parms, + omp_declare_simd_clauses); + if (parms) + temp_pop_parm_decls (); + } + if (oacc_routine_data) + c_finish_oacc_routine (oacc_routine_data, d, false); + if (d) + finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, + NULL_TREE, asm_name); + + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + if (d) + *objc_foreach_object_declaration = d; + else + *objc_foreach_object_declaration = error_mark_node; + } + } + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + if (auto_type_p) + { + error_at (here, + "%<__auto_type%> may only be used with" + " a single declarator"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + c_parser_consume_token (parser); + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + all_prefix_attrs = chainon (c_parser_gnu_attributes (parser), + prefix_attrs); + else + all_prefix_attrs = prefix_attrs; + continue; + } + else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_parser_consume_token (parser); + return; + } + else if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + /* This can only happen in Objective-C: we found the + 'in' that terminates the declaration inside an + Objective-C foreach statement. Do not consume the + token, so that the caller can use it to determine + that this indeed is a foreach context. */ + return; + } + else + { + c_parser_error (parser, "expected %<,%> or %<;%>"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + } + else if (auto_type_p) + { + error_at (here, + "%<__auto_type%> requires an initialized data declaration"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + else if (!fndef_ok) + { + c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, " + "% or %<__attribute__%>"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + /* Function definition (nested or otherwise). */ + if (nested) + { + pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions"); + c_push_function_context (); + } + if (!start_function (specs, declarator, all_prefix_attrs)) + { + /* At this point we've consumed: + declaration-specifiers declarator + and the next token isn't CPP_EQ, CPP_COMMA, CPP_SEMICOLON, + RID_ASM, RID_ATTRIBUTE, or RID_IN, + but the + declaration-specifiers declarator + aren't grokkable as a function definition, so we have + an error. */ + gcc_assert (!c_parser_next_token_is (parser, CPP_SEMICOLON)); + if (c_parser_next_token_starts_declspecs (parser)) + { + /* If we have + declaration-specifiers declarator decl-specs + then assume we have a missing semicolon, which would + give us: + declaration-specifiers declarator decl-specs + ^ + ; + <~~~~~~~~~ declaration ~~~~~~~~~~> + Use c_parser_require to get an error with a fix-it hint. */ + c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"); + parser->error = false; + } + else + { + /* This can appear in many cases looking nothing like a + function definition, so we don't give a more specific + error suggesting there was one. */ + c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, % " + "or %<__attribute__%>"); + } + if (nested) + c_pop_function_context (); + break; + } + + if (DECL_DECLARED_INLINE_P (current_function_decl)) + tv = TV_PARSE_INLINE; + else + tv = TV_PARSE_FUNC; + auto_timevar at (g_timer, tv); + + /* Parse old-style parameter declarations. ??? Attributes are + not allowed to start declaration specifiers here because of a + syntax conflict between a function declaration with attribute + suffix and a function definition with an attribute prefix on + first old-style parameter declaration. Following the old + parser, they are not accepted on subsequent old-style + parameter declarations either. However, there is no + ambiguity after the first declaration, nor indeed on the + first as long as we don't allow postfix attributes after a + declarator with a nonempty identifier list in a definition; + and postfix attributes have never been accepted here in + function definitions either. */ + while (c_parser_next_token_is_not (parser, CPP_EOF) + && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE)) + c_parser_declaration_or_fndef (parser, false, false, false, + true, false); + store_parm_decls (); + if (omp_declare_simd_clauses) + c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE, + omp_declare_simd_clauses); + if (oacc_routine_data) + c_finish_oacc_routine (oacc_routine_data, current_function_decl, true); + location_t startloc = c_parser_peek_token (parser)->location; + DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus + = startloc; + location_t endloc = startloc; + + /* If the definition was marked with __RTL, use the RTL parser now, + consuming the function body. */ + if (specs->declspec_il == cdil_rtl) + { + endloc = c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass); + + /* Normally, store_parm_decls sets next_is_function_body, + anticipating a function body. We need a push_scope/pop_scope + pair to flush out this state, or subsequent function parsing + will go wrong. */ + push_scope (); + pop_scope (); + + finish_function (endloc); + return; + } + /* If the definition was marked with __GIMPLE then parse the + function body as GIMPLE. */ + else if (specs->declspec_il != cdil_none) + { + bool saved = in_late_binary_op; + in_late_binary_op = true; + c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass, + specs->declspec_il, + specs->entry_bb_count); + in_late_binary_op = saved; + } + else + fnbody = c_parser_compound_statement (parser, &endloc); + tree fndecl = current_function_decl; + if (nested) + { + tree decl = current_function_decl; + /* Mark nested functions as needing static-chain initially. + lower_nested_functions will recompute it but the + DECL_STATIC_CHAIN flag is also used before that happens, + by initializer_constant_valid_p. See gcc.dg/nested-fn-2.c. */ + DECL_STATIC_CHAIN (decl) = 1; + add_stmt (fnbody); + finish_function (endloc); + c_pop_function_context (); + add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); + } + else + { + if (fnbody) + add_stmt (fnbody); + finish_function (endloc); + } + /* Get rid of the empty stmt list for GIMPLE/RTL. */ + if (specs->declspec_il != cdil_none) + DECL_SAVED_TREE (fndecl) = NULL_TREE; + + break; + } +} + +/* Parse an asm-definition (asm() outside a function body). This is a + GNU extension. + + asm-definition: + simple-asm-expr ; +*/ + +static void +c_parser_asm_definition (c_parser *parser) +{ + tree asm_str = c_parser_simple_asm_expr (parser); + if (asm_str) + symtab->finalize_toplevel_asm (asm_str); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); +} + +/* Parse a static assertion (C11 6.7.10). + + static_assert-declaration: + static_assert-declaration-no-semi ; +*/ + +static void +c_parser_static_assert_declaration (c_parser *parser) +{ + c_parser_static_assert_declaration_no_semi (parser); + if (parser->error + || !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + c_parser_skip_to_end_of_block_or_statement (parser); +} + +/* Parse a static assertion (C11 6.7.10), without the trailing + semicolon. + + static_assert-declaration-no-semi: + _Static_assert ( constant-expression , string-literal ) + + C2X: + static_assert-declaration-no-semi: + _Static_assert ( constant-expression ) +*/ + +static void +c_parser_static_assert_declaration_no_semi (c_parser *parser) +{ + location_t assert_loc, value_loc; + tree value; + tree string = NULL_TREE; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)); + assert_loc = c_parser_peek_token (parser)->location; + if (flag_isoc99) + pedwarn_c99 (assert_loc, OPT_Wpedantic, + "ISO C99 does not support %<_Static_assert%>"); + else + pedwarn_c99 (assert_loc, OPT_Wpedantic, + "ISO C90 does not support %<_Static_assert%>"); + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + return; + location_t value_tok_loc = c_parser_peek_token (parser)->location; + value = c_parser_expr_no_commas (parser, NULL).value; + value_loc = EXPR_LOC_OR_LOC (value, value_tok_loc); + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + switch (c_parser_peek_token (parser)->type) + { + case CPP_STRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_WSTRING: + case CPP_UTF8STRING: + string = c_parser_string_literal (parser, false, true).value; + break; + default: + c_parser_error (parser, "expected string literal"); + return; + } + } + else if (flag_isoc11) + /* If pedantic for pre-C11, the use of _Static_assert itself will + have been diagnosed, so do not also diagnose the use of this + new C2X feature of _Static_assert. */ + pedwarn_c11 (assert_loc, OPT_Wpedantic, + "ISO C11 does not support omitting the string in " + "%<_Static_assert%>"); + parens.require_close (parser); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (value))) + { + error_at (value_loc, "expression in static assertion is not an integer"); + return; + } + if (TREE_CODE (value) != INTEGER_CST) + { + value = c_fully_fold (value, false, NULL); + /* Strip no-op conversions. */ + STRIP_TYPE_NOPS (value); + if (TREE_CODE (value) == INTEGER_CST) + pedwarn (value_loc, OPT_Wpedantic, "expression in static assertion " + "is not an integer constant expression"); + } + if (TREE_CODE (value) != INTEGER_CST) + { + error_at (value_loc, "expression in static assertion is not constant"); + return; + } + constant_expression_warning (value); + if (integer_zerop (value)) + { + if (string) + error_at (assert_loc, "static assertion failed: %E", string); + else + error_at (assert_loc, "static assertion failed"); + } +} + +/* Parse some declaration specifiers (possibly none) (C90 6.5, C99 + 6.7, C11 6.7), adding them to SPECS (which may already include some). + Storage class specifiers are accepted iff SCSPEC_OK; type + specifiers are accepted iff TYPESPEC_OK; alignment specifiers are + accepted iff ALIGNSPEC_OK; gnu-attributes are accepted at the start + iff START_ATTR_OK; __auto_type is accepted iff AUTO_TYPE_OK. In + addition to the syntax shown, standard attributes are accepted at + the start iff START_STD_ATTR_OK and at the end iff END_STD_ATTR_OK; + unlike gnu-attributes, they are not accepted in the middle of the + list. (This combines various different syntax productions in the C + standard, and in some cases gnu-attributes and standard attributes + at the start may already have been parsed before this function is + called.) + + declaration-specifiers: + storage-class-specifier declaration-specifiers[opt] + type-specifier declaration-specifiers[opt] + type-qualifier declaration-specifiers[opt] + function-specifier declaration-specifiers[opt] + alignment-specifier declaration-specifiers[opt] + + Function specifiers (inline) are from C99, and are currently + handled as storage class specifiers, as is __thread. Alignment + specifiers are from C11. + + C90 6.5.1, C99 6.7.1, C11 6.7.1: + storage-class-specifier: + typedef + extern + static + auto + register + _Thread_local + + (_Thread_local is new in C11.) + + C99 6.7.4, C11 6.7.4: + function-specifier: + inline + _Noreturn + + (_Noreturn is new in C11.) + + C90 6.5.2, C99 6.7.2, C11 6.7.2: + type-specifier: + void + char + short + int + long + float + double + signed + unsigned + _Bool + _Complex + [_Imaginary removed in C99 TC2] + struct-or-union-specifier + enum-specifier + typedef-name + atomic-type-specifier + + (_Bool and _Complex are new in C99.) + (atomic-type-specifier is new in C11.) + + C90 6.5.3, C99 6.7.3, C11 6.7.3: + + type-qualifier: + const + restrict + volatile + address-space-qualifier + _Atomic + + (restrict is new in C99.) + (_Atomic is new in C11.) + + GNU extensions: + + declaration-specifiers: + gnu-attributes declaration-specifiers[opt] + + type-qualifier: + address-space + + address-space: + identifier recognized by the target + + storage-class-specifier: + __thread + + type-specifier: + typeof-specifier + __auto_type + __intN + _Decimal32 + _Decimal64 + _Decimal128 + _Fract + _Accum + _Sat + + (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037: + http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf) + + atomic-type-specifier + _Atomic ( type-name ) + + Objective-C: + + type-specifier: + class-name objc-protocol-refs[opt] + typedef-name objc-protocol-refs + objc-protocol-refs +*/ + +void +c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, + bool scspec_ok, bool typespec_ok, bool start_attr_ok, + bool alignspec_ok, bool auto_type_ok, + bool start_std_attr_ok, bool end_std_attr_ok, + enum c_lookahead_kind la) +{ + bool attrs_ok = start_attr_ok; + bool seen_type = specs->typespec_kind != ctsk_none; + + if (!typespec_ok) + gcc_assert (la == cla_prefer_id); + + if (start_std_attr_ok + && c_parser_nth_token_starts_std_attributes (parser, 1)) + { + gcc_assert (!specs->non_std_attrs_seen_p); + location_t loc = c_parser_peek_token (parser)->location; + tree attrs = c_parser_std_attribute_specifier_sequence (parser); + declspecs_add_attrs (loc, specs, attrs); + specs->non_std_attrs_seen_p = false; + } + + while (c_parser_next_token_is (parser, CPP_NAME) + || c_parser_next_token_is (parser, CPP_KEYWORD) + || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS))) + { + struct c_typespec t; + tree attrs; + tree align; + location_t loc = c_parser_peek_token (parser)->location; + + /* If we cannot accept a type, exit if the next token must start + one. Also, if we already have seen a tagged definition, + a typename would be an error anyway and likely the user + has simply forgotten a semicolon, so we exit. */ + if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef) + && c_parser_next_tokens_start_typename (parser, la) + && !c_parser_next_token_is_qualifier (parser) + && !c_parser_next_token_is_keyword (parser, RID_ALIGNAS)) + break; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *name_token = c_parser_peek_token (parser); + tree value = name_token->value; + c_id_kind kind = name_token->id_kind; + + if (kind == C_ID_ADDRSPACE) + { + addr_space_t as + = name_token->keyword - RID_FIRST_ADDR_SPACE; + declspecs_add_addrspace (name_token->location, specs, as); + c_parser_consume_token (parser); + attrs_ok = true; + continue; + } + + gcc_assert (!c_parser_next_token_is_qualifier (parser)); + + /* If we cannot accept a type, and the next token must start one, + exit. Do the same if we already have seen a tagged definition, + since it would be an error anyway and likely the user has simply + forgotten a semicolon. */ + if (seen_type || !c_parser_next_tokens_start_typename (parser, la)) + break; + + /* Now at an unknown typename (C_ID_ID), a C_ID_TYPENAME or + a C_ID_CLASSNAME. */ + c_parser_consume_token (parser); + seen_type = true; + attrs_ok = true; + if (kind == C_ID_ID) + { + error_at (loc, "unknown type name %qE", value); + t.kind = ctsk_typedef; + t.spec = error_mark_node; + } + else if (kind == C_ID_TYPENAME + && (!c_dialect_objc () + || c_parser_next_token_is_not (parser, CPP_LESS))) + { + t.kind = ctsk_typedef; + /* For a typedef name, record the meaning, not the name. + In case of 'foo foo, bar;'. */ + t.spec = lookup_name (value); + } + else + { + tree proto = NULL_TREE; + gcc_assert (c_dialect_objc ()); + t.kind = ctsk_objc; + if (c_parser_next_token_is (parser, CPP_LESS)) + proto = c_parser_objc_protocol_refs (parser); + t.spec = objc_get_protocol_qualified_type (value, proto); + } + t.expr = NULL_TREE; + t.expr_const_operands = true; + declspecs_add_type (name_token->location, specs, t); + continue; + } + if (c_parser_next_token_is (parser, CPP_LESS)) + { + /* Make "" equivalent to "id " - + nisse@lysator.liu.se. */ + tree proto; + gcc_assert (c_dialect_objc ()); + if (!typespec_ok || seen_type) + break; + proto = c_parser_objc_protocol_refs (parser); + t.kind = ctsk_objc; + t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto); + t.expr = NULL_TREE; + t.expr_const_operands = true; + declspecs_add_type (loc, specs, t); + continue; + } + gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD)); + switch (c_parser_peek_token (parser)->keyword) + { + case RID_STATIC: + case RID_EXTERN: + case RID_REGISTER: + case RID_TYPEDEF: + case RID_INLINE: + case RID_NORETURN: + case RID_AUTO: + case RID_THREAD: + if (!scspec_ok) + goto out; + attrs_ok = true; + /* TODO: Distinguish between function specifiers (inline, noreturn) + and storage class specifiers, either here or in + declspecs_add_scspec. */ + declspecs_add_scspec (loc, specs, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + break; + case RID_AUTO_TYPE: + if (!auto_type_ok) + goto out; + /* Fall through. */ + case RID_UNSIGNED: + case RID_LONG: + case RID_SHORT: + case RID_SIGNED: + case RID_COMPLEX: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + CASE_RID_FLOATN_NX: + case RID_BOOL: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: + case RID_INT_N_0: + case RID_INT_N_1: + case RID_INT_N_2: + case RID_INT_N_3: + if (!typespec_ok) + goto out; + attrs_ok = true; + seen_type = true; + if (c_dialect_objc ()) + parser->objc_need_raw_identifier = true; + t.kind = ctsk_resword; + t.spec = c_parser_peek_token (parser)->value; + t.expr = NULL_TREE; + t.expr_const_operands = true; + declspecs_add_type (loc, specs, t); + c_parser_consume_token (parser); + break; + case RID_ENUM: + if (!typespec_ok) + goto out; + attrs_ok = true; + seen_type = true; + t = c_parser_enum_specifier (parser); + invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec); + declspecs_add_type (loc, specs, t); + break; + case RID_STRUCT: + case RID_UNION: + if (!typespec_ok) + goto out; + attrs_ok = true; + seen_type = true; + t = c_parser_struct_or_union_specifier (parser); + invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec); + declspecs_add_type (loc, specs, t); + break; + case RID_TYPEOF: + /* ??? The old parser rejected typeof after other type + specifiers, but is a syntax error the best way of + handling this? */ + if (!typespec_ok || seen_type) + goto out; + attrs_ok = true; + seen_type = true; + t = c_parser_typeof_specifier (parser); + declspecs_add_type (loc, specs, t); + break; + case RID_ATOMIC: + /* C parser handling of Objective-C constructs needs + checking for correct lvalue-to-rvalue conversions, and + the code in build_modify_expr handling various + Objective-C cases, and that in build_unary_op handling + Objective-C cases for increment / decrement, also needs + updating; uses of TYPE_MAIN_VARIANT in objc_compare_types + and objc_types_are_equivalent may also need updates. */ + if (c_dialect_objc ()) + sorry ("%<_Atomic%> in Objective-C"); + if (flag_isoc99) + pedwarn_c99 (loc, OPT_Wpedantic, + "ISO C99 does not support the %<_Atomic%> qualifier"); + else + pedwarn_c99 (loc, OPT_Wpedantic, + "ISO C90 does not support the %<_Atomic%> qualifier"); + attrs_ok = true; + tree value; + value = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (typespec_ok && c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + /* _Atomic ( type-name ). */ + seen_type = true; + c_parser_consume_token (parser); + struct c_type_name *type = c_parser_type_name (parser); + t.kind = ctsk_typeof; + t.spec = error_mark_node; + t.expr = NULL_TREE; + t.expr_const_operands = true; + if (type != NULL) + t.spec = groktypename (type, &t.expr, + &t.expr_const_operands); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + if (t.spec != error_mark_node) + { + if (TREE_CODE (t.spec) == ARRAY_TYPE) + error_at (loc, "%<_Atomic%>-qualified array type"); + else if (TREE_CODE (t.spec) == FUNCTION_TYPE) + error_at (loc, "%<_Atomic%>-qualified function type"); + else if (TYPE_QUALS (t.spec) != TYPE_UNQUALIFIED) + error_at (loc, "%<_Atomic%> applied to a qualified type"); + else + t.spec = c_build_qualified_type (t.spec, TYPE_QUAL_ATOMIC); + } + declspecs_add_type (loc, specs, t); + } + else + declspecs_add_qual (loc, specs, value); + break; + case RID_CONST: + case RID_VOLATILE: + case RID_RESTRICT: + attrs_ok = true; + declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + break; + case RID_ATTRIBUTE: + if (!attrs_ok) + goto out; + attrs = c_parser_gnu_attributes (parser); + declspecs_add_attrs (loc, specs, attrs); + break; + case RID_ALIGNAS: + if (!alignspec_ok) + goto out; + align = c_parser_alignas_specifier (parser); + declspecs_add_alignas (loc, specs, align); + break; + case RID_GIMPLE: + if (! flag_gimple) + error_at (loc, "%<__GIMPLE%> only valid with %<-fgimple%>"); + c_parser_consume_token (parser); + specs->declspec_il = cdil_gimple; + specs->locations[cdw_gimple] = loc; + c_parser_gimple_or_rtl_pass_list (parser, specs); + break; + case RID_RTL: + c_parser_consume_token (parser); + specs->declspec_il = cdil_rtl; + specs->locations[cdw_rtl] = loc; + c_parser_gimple_or_rtl_pass_list (parser, specs); + break; + default: + goto out; + } + } + out: + if (end_std_attr_ok + && c_parser_nth_token_starts_std_attributes (parser, 1)) + specs->postfix_attrs = c_parser_std_attribute_specifier_sequence (parser); +} + +/* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2, C11 6.7.2.2). + + enum-specifier: + enum gnu-attributes[opt] identifier[opt] { enumerator-list } + gnu-attributes[opt] + enum gnu-attributes[opt] identifier[opt] { enumerator-list , } + gnu-attributes[opt] + enum gnu-attributes[opt] identifier + + The form with trailing comma is new in C99. The forms with + gnu-attributes are GNU extensions. In GNU C, we accept any expression + without commas in the syntax (assignment expressions, not just + conditional expressions); assignment expressions will be diagnosed + as non-constant. + + enumerator-list: + enumerator + enumerator-list , enumerator + + enumerator: + enumeration-constant attribute-specifier-sequence[opt] + enumeration-constant attribute-specifier-sequence[opt] + = constant-expression + + GNU Extensions: + + enumerator: + enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt] + enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt] + = constant-expression + +*/ + +static struct c_typespec +c_parser_enum_specifier (c_parser *parser) +{ + struct c_typespec ret; + bool have_std_attrs; + tree std_attrs = NULL_TREE; + tree attrs; + tree ident = NULL_TREE; + location_t enum_loc; + location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); + c_parser_consume_token (parser); + have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); + if (have_std_attrs) + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + attrs = c_parser_gnu_attributes (parser); + enum_loc = c_parser_peek_token (parser)->location; + /* Set the location in case we create a decl now. */ + c_parser_set_source_position_from_token (c_parser_peek_token (parser)); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + ident = c_parser_peek_token (parser)->value; + ident_loc = c_parser_peek_token (parser)->location; + enum_loc = ident_loc; + c_parser_consume_token (parser); + } + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + /* Parse an enum definition. */ + struct c_enum_contents the_enum; + tree type; + tree postfix_attrs; + /* We chain the enumerators in reverse order, then put them in + forward order at the end. */ + tree values; + timevar_push (TV_PARSE_ENUM); + type = start_enum (enum_loc, &the_enum, ident); + values = NULL_TREE; + c_parser_consume_token (parser); + while (true) + { + tree enum_id; + tree enum_value; + tree enum_decl; + bool seen_comma; + c_token *token; + location_t comma_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + location_t decl_loc, value_loc; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + /* Give a nicer error for "enum {}". */ + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE) + && !parser->error) + { + error_at (c_parser_peek_token (parser)->location, + "empty enum is invalid"); + parser->error = true; + } + else + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); + values = error_mark_node; + break; + } + token = c_parser_peek_token (parser); + enum_id = token->value; + /* Set the location in case we create a decl now. */ + c_parser_set_source_position_from_token (token); + decl_loc = value_loc = token->location; + c_parser_consume_token (parser); + /* Parse any specified attributes. */ + tree std_attrs = NULL_TREE; + if (c_parser_nth_token_starts_std_attributes (parser, 1)) + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + tree enum_attrs = chainon (std_attrs, + c_parser_gnu_attributes (parser)); + if (c_parser_next_token_is (parser, CPP_EQ)) + { + c_parser_consume_token (parser); + value_loc = c_parser_peek_token (parser)->location; + enum_value = c_parser_expr_no_commas (parser, NULL).value; + } + else + enum_value = NULL_TREE; + enum_decl = build_enumerator (decl_loc, value_loc, + &the_enum, enum_id, enum_value); + if (enum_attrs) + decl_attributes (&TREE_PURPOSE (enum_decl), enum_attrs, 0); + TREE_CHAIN (enum_decl) = values; + values = enum_decl; + seen_comma = false; + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + comma_loc = c_parser_peek_token (parser)->location; + seen_comma = true; + c_parser_consume_token (parser); + } + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + if (seen_comma) + pedwarn_c90 (comma_loc, OPT_Wpedantic, + "comma at end of enumerator list"); + c_parser_consume_token (parser); + break; + } + if (!seen_comma) + { + c_parser_error (parser, "expected %<,%> or %<}%>"); + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); + values = error_mark_node; + break; + } + } + postfix_attrs = c_parser_gnu_attributes (parser); + ret.spec = finish_enum (type, nreverse (values), + chainon (std_attrs, + chainon (attrs, postfix_attrs))); + ret.kind = ctsk_tagdef; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + timevar_pop (TV_PARSE_ENUM); + return ret; + } + else if (!ident) + { + c_parser_error (parser, "expected %<{%>"); + ret.spec = error_mark_node; + ret.kind = ctsk_tagref; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + return ret; + } + /* Attributes may only appear when the members are defined or in + certain forward declarations (treat enum forward declarations in + GNU C analogously to struct and union forward declarations in + standard C). */ + if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + c_parser_error (parser, "expected %<;%>"); + ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs, + std_attrs); + /* In ISO C, enumerated types can be referred to only if already + defined. */ + if (pedantic && !COMPLETE_TYPE_P (ret.spec)) + { + gcc_assert (ident); + pedwarn (enum_loc, OPT_Wpedantic, + "ISO C forbids forward references to % types"); + } + return ret; +} + +/* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1, C11 6.7.2.1). + + struct-or-union-specifier: + struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt] + identifier[opt] { struct-contents } gnu-attributes[opt] + struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt] + identifier + + struct-contents: + struct-declaration-list + + struct-declaration-list: + struct-declaration ; + struct-declaration-list struct-declaration ; + + GNU extensions: + + struct-contents: + empty + struct-declaration + struct-declaration-list struct-declaration + + struct-declaration-list: + struct-declaration-list ; + ; + + (Note that in the syntax here, unlike that in ISO C, the semicolons + are included here rather than in struct-declaration, in order to + describe the syntax with extra semicolons and missing semicolon at + end.) + + Objective-C: + + struct-declaration-list: + @defs ( class-name ) + + (Note this does not include a trailing semicolon, but can be + followed by further declarations, and gets a pedwarn-if-pedantic + when followed by a semicolon.) */ + +static struct c_typespec +c_parser_struct_or_union_specifier (c_parser *parser) +{ + struct c_typespec ret; + bool have_std_attrs; + tree std_attrs = NULL_TREE; + tree attrs; + tree ident = NULL_TREE; + location_t struct_loc; + location_t ident_loc = UNKNOWN_LOCATION; + enum tree_code code; + switch (c_parser_peek_token (parser)->keyword) + { + case RID_STRUCT: + code = RECORD_TYPE; + break; + case RID_UNION: + code = UNION_TYPE; + break; + default: + gcc_unreachable (); + } + struct_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); + if (have_std_attrs) + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + attrs = c_parser_gnu_attributes (parser); + + /* Set the location in case we create a decl now. */ + c_parser_set_source_position_from_token (c_parser_peek_token (parser)); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + ident = c_parser_peek_token (parser)->value; + ident_loc = c_parser_peek_token (parser)->location; + struct_loc = ident_loc; + c_parser_consume_token (parser); + } + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + /* Parse a struct or union definition. Start the scope of the + tag before parsing components. */ + class c_struct_parse_info *struct_info; + tree type = start_struct (struct_loc, code, ident, &struct_info); + tree postfix_attrs; + /* We chain the components in reverse order, then put them in + forward order at the end. Each struct-declaration may + declare multiple components (comma-separated), so we must use + chainon to join them, although when parsing each + struct-declaration we can use TREE_CHAIN directly. + + The theory behind all this is that there will be more + semicolon separated fields than comma separated fields, and + so we'll be minimizing the number of node traversals required + by chainon. */ + tree contents; + timevar_push (TV_PARSE_STRUCT); + contents = NULL_TREE; + c_parser_consume_token (parser); + /* Handle the Objective-C @defs construct, + e.g. foo(sizeof(struct{ @defs(ClassName) }));. */ + if (c_parser_next_token_is_keyword (parser, RID_AT_DEFS)) + { + tree name; + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + goto end_at_defs; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + { + c_parser_error (parser, "expected class name"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + goto end_at_defs; + } + parens.skip_until_found_close (parser); + contents = nreverse (objc_get_class_ivars (name)); + } + end_at_defs: + /* Parse the struct-declarations and semicolons. Problems with + semicolons are diagnosed here; empty structures are diagnosed + elsewhere. */ + while (true) + { + tree decls; + /* Parse any stray semicolon. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + location_t semicolon_loc + = c_parser_peek_token (parser)->location; + gcc_rich_location richloc (semicolon_loc); + richloc.add_fixit_remove (); + pedwarn (&richloc, OPT_Wpedantic, + "extra semicolon in struct or union specified"); + c_parser_consume_token (parser); + continue; + } + /* Stop if at the end of the struct or union contents. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + c_parser_consume_token (parser); + break; + } + /* Accept #pragmas at struct scope. */ + if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + c_parser_pragma (parser, pragma_struct, NULL); + continue; + } + /* Parse some comma-separated declarations, but not the + trailing semicolon if any. */ + decls = c_parser_struct_declaration (parser); + contents = chainon (decls, contents); + /* If no semicolon follows, either we have a parse error or + are at the end of the struct or union and should + pedwarn. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_consume_token (parser); + else + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + pedwarn (c_parser_peek_token (parser)->location, 0, + "no semicolon at end of struct or union"); + else if (parser->error + || !c_parser_next_token_starts_declspecs (parser)) + { + c_parser_error (parser, "expected %<;%>"); + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); + break; + } + + /* If we come here, we have already emitted an error + for an expected `;', identifier or `(', and we also + recovered already. Go on with the next field. */ + } + } + postfix_attrs = c_parser_gnu_attributes (parser); + ret.spec = finish_struct (struct_loc, type, nreverse (contents), + chainon (std_attrs, + chainon (attrs, postfix_attrs)), + struct_info); + ret.kind = ctsk_tagdef; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + timevar_pop (TV_PARSE_STRUCT); + return ret; + } + else if (!ident) + { + c_parser_error (parser, "expected %<{%>"); + ret.spec = error_mark_node; + ret.kind = ctsk_tagref; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + return ret; + } + /* Attributes may only appear when the members are defined or in + certain forward declarations. */ + if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + c_parser_error (parser, "expected %<;%>"); + /* ??? Existing practice is that GNU attributes are ignored after + the struct or union keyword when not defining the members. */ + ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs); + return ret; +} + +/* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1, C11 6.7.2.1), + *without* the trailing semicolon. + + struct-declaration: + attribute-specifier-sequence[opt] specifier-qualifier-list + attribute-specifier-sequence[opt] struct-declarator-list + static_assert-declaration-no-semi + + specifier-qualifier-list: + type-specifier specifier-qualifier-list[opt] + type-qualifier specifier-qualifier-list[opt] + alignment-specifier specifier-qualifier-list[opt] + gnu-attributes specifier-qualifier-list[opt] + + struct-declarator-list: + struct-declarator + struct-declarator-list , gnu-attributes[opt] struct-declarator + + struct-declarator: + declarator gnu-attributes[opt] + declarator[opt] : constant-expression gnu-attributes[opt] + + GNU extensions: + + struct-declaration: + __extension__ struct-declaration + specifier-qualifier-list + + Unlike the ISO C syntax, semicolons are handled elsewhere. The use + of gnu-attributes where shown is a GNU extension. In GNU C, we accept + any expression without commas in the syntax (assignment + expressions, not just conditional expressions); assignment + expressions will be diagnosed as non-constant. */ + +static tree +c_parser_struct_declaration (c_parser *parser) +{ + struct c_declspecs *specs; + tree prefix_attrs; + tree all_prefix_attrs; + tree decls; + location_t decl_loc; + if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) + { + int ext; + tree decl; + ext = disable_extension_diagnostics (); + c_parser_consume_token (parser); + decl = c_parser_struct_declaration (parser); + restore_extension_diagnostics (ext); + return decl; + } + if (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) + { + c_parser_static_assert_declaration_no_semi (parser); + return NULL_TREE; + } + specs = build_null_declspecs (); + decl_loc = c_parser_peek_token (parser)->location; + /* Strictly by the standard, we shouldn't allow _Alignas here, + but it appears to have been intended to allow it there, so + we're keeping it as it is until WG14 reaches a conclusion + of N1731. + */ + c_parser_declspecs (parser, specs, false, true, true, + true, false, true, true, cla_nonabstract_decl); + if (parser->error) + return NULL_TREE; + if (!specs->declspecs_seen_p) + { + c_parser_error (parser, "expected specifier-qualifier-list"); + return NULL_TREE; + } + finish_declspecs (specs); + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + tree ret; + if (specs->typespec_kind == ctsk_none) + { + pedwarn (decl_loc, OPT_Wpedantic, + "ISO C forbids member declarations with no members"); + shadow_tag_warned (specs, pedantic); + ret = NULL_TREE; + } + else + { + /* Support for unnamed structs or unions as members of + structs or unions (which is [a] useful and [b] supports + MS P-SDK). */ + tree attrs = NULL; + + ret = grokfield (c_parser_peek_token (parser)->location, + build_id_declarator (NULL_TREE), specs, + NULL_TREE, &attrs); + if (ret) + decl_attributes (&ret, attrs, 0); + } + return ret; + } + + /* Provide better error recovery. Note that a type name here is valid, + and will be treated as a field name. */ + if (specs->typespec_kind == ctsk_tagdef + && TREE_CODE (specs->type) != ENUMERAL_TYPE + && c_parser_next_token_starts_declspecs (parser) + && !c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %<;%>, identifier or %<(%>"); + parser->error = false; + return NULL_TREE; + } + + pending_xref_error (); + prefix_attrs = specs->attrs; + all_prefix_attrs = prefix_attrs; + specs->attrs = NULL_TREE; + decls = NULL_TREE; + while (true) + { + /* Declaring one or more declarators or un-named bit-fields. */ + struct c_declarator *declarator; + bool dummy = false; + if (c_parser_next_token_is (parser, CPP_COLON)) + declarator = build_id_declarator (NULL_TREE); + else + declarator = c_parser_declarator (parser, + specs->typespec_kind != ctsk_none, + C_DTR_NORMAL, &dummy); + if (declarator == NULL) + { + c_parser_skip_to_end_of_block_or_statement (parser); + break; + } + if (c_parser_next_token_is (parser, CPP_COLON) + || c_parser_next_token_is (parser, CPP_COMMA) + || c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_CLOSE_BRACE) + || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + { + tree postfix_attrs = NULL_TREE; + tree width = NULL_TREE; + tree d; + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + width = c_parser_expr_no_commas (parser, NULL).value; + } + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + postfix_attrs = c_parser_gnu_attributes (parser); + d = grokfield (c_parser_peek_token (parser)->location, + declarator, specs, width, &all_prefix_attrs); + decl_attributes (&d, chainon (postfix_attrs, + all_prefix_attrs), 0); + DECL_CHAIN (d) = decls; + decls = d; + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + all_prefix_attrs = chainon (c_parser_gnu_attributes (parser), + prefix_attrs); + else + all_prefix_attrs = prefix_attrs; + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else if (c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + /* Semicolon consumed in caller. */ + break; + } + else + { + c_parser_error (parser, "expected %<,%>, %<;%> or %<}%>"); + break; + } + } + else + { + c_parser_error (parser, + "expected %<:%>, %<,%>, %<;%>, %<}%> or " + "%<__attribute__%>"); + break; + } + } + return decls; +} + +/* Parse a typeof specifier (a GNU extension). + + typeof-specifier: + typeof ( expression ) + typeof ( type-name ) +*/ + +static struct c_typespec +c_parser_typeof_specifier (c_parser *parser) +{ + struct c_typespec ret; + ret.kind = ctsk_typeof; + ret.spec = error_mark_node; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF)); + c_parser_consume_token (parser); + c_inhibit_evaluation_warnings++; + in_typeof++; + matching_parens parens; + if (!parens.require_open (parser)) + { + c_inhibit_evaluation_warnings--; + in_typeof--; + return ret; + } + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + struct c_type_name *type = c_parser_type_name (parser); + c_inhibit_evaluation_warnings--; + in_typeof--; + if (type != NULL) + { + ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands); + pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE)); + } + } + else + { + bool was_vm; + location_t here = c_parser_peek_token (parser)->location; + struct c_expr expr = c_parser_expression (parser); + c_inhibit_evaluation_warnings--; + in_typeof--; + if (TREE_CODE (expr.value) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) + error_at (here, "% applied to a bit-field"); + mark_exp_read (expr.value); + ret.spec = TREE_TYPE (expr.value); + was_vm = variably_modified_type_p (ret.spec, NULL_TREE); + /* This is returned with the type so that when the type is + evaluated, this can be evaluated. */ + if (was_vm) + ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands); + pop_maybe_used (was_vm); + } + parens.skip_until_found_close (parser); + return ret; +} + +/* Parse an alignment-specifier. + + C11 6.7.5: + + alignment-specifier: + _Alignas ( type-name ) + _Alignas ( constant-expression ) +*/ + +static tree +c_parser_alignas_specifier (c_parser * parser) +{ + tree ret = error_mark_node; + location_t loc = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNAS)); + c_parser_consume_token (parser); + if (flag_isoc99) + pedwarn_c99 (loc, OPT_Wpedantic, + "ISO C99 does not support %<_Alignas%>"); + else + pedwarn_c99 (loc, OPT_Wpedantic, + "ISO C90 does not support %<_Alignas%>"); + matching_parens parens; + if (!parens.require_open (parser)) + return ret; + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + struct c_type_name *type = c_parser_type_name (parser); + if (type != NULL) + ret = c_sizeof_or_alignof_type (loc, groktypename (type, NULL, NULL), + false, true, 1); + } + else + ret = c_parser_expr_no_commas (parser, NULL).value; + parens.skip_until_found_close (parser); + return ret; +} + +/* Parse a declarator, possibly an abstract declarator (C90 6.5.4, + 6.5.5, C99 6.7.5, 6.7.6, C11 6.7.6, 6.7.7). If TYPE_SEEN_P then + a typedef name may be redeclared; otherwise it may not. KIND + indicates which kind of declarator is wanted. Returns a valid + declarator except in the case of a syntax error in which case NULL is + returned. *SEEN_ID is set to true if an identifier being declared is + seen; this is used to diagnose bad forms of abstract array declarators + and to determine whether an identifier list is syntactically permitted. + + declarator: + pointer[opt] direct-declarator + + direct-declarator: + identifier + ( gnu-attributes[opt] declarator ) + direct-declarator array-declarator + direct-declarator ( parameter-type-list ) + direct-declarator ( identifier-list[opt] ) + + pointer: + * type-qualifier-list[opt] + * type-qualifier-list[opt] pointer + + type-qualifier-list: + type-qualifier + gnu-attributes + type-qualifier-list type-qualifier + type-qualifier-list gnu-attributes + + array-declarator: + [ type-qualifier-list[opt] assignment-expression[opt] ] + [ static type-qualifier-list[opt] assignment-expression ] + [ type-qualifier-list static assignment-expression ] + [ type-qualifier-list[opt] * ] + + parameter-type-list: + parameter-list + parameter-list , ... + + parameter-list: + parameter-declaration + parameter-list , parameter-declaration + + parameter-declaration: + declaration-specifiers declarator gnu-attributes[opt] + declaration-specifiers abstract-declarator[opt] gnu-attributes[opt] + + identifier-list: + identifier + identifier-list , identifier + + abstract-declarator: + pointer + pointer[opt] direct-abstract-declarator + + direct-abstract-declarator: + ( gnu-attributes[opt] abstract-declarator ) + direct-abstract-declarator[opt] array-declarator + direct-abstract-declarator[opt] ( parameter-type-list[opt] ) + + GNU extensions: + + direct-declarator: + direct-declarator ( parameter-forward-declarations + parameter-type-list[opt] ) + + direct-abstract-declarator: + direct-abstract-declarator[opt] ( parameter-forward-declarations + parameter-type-list[opt] ) + + parameter-forward-declarations: + parameter-list ; + parameter-forward-declarations parameter-list ; + + The uses of gnu-attributes shown above are GNU extensions. + + Some forms of array declarator are not included in C99 in the + syntax for abstract declarators; these are disallowed elsewhere. + This may be a defect (DR#289). + + This function also accepts an omitted abstract declarator as being + an abstract declarator, although not part of the formal syntax. */ + +struct c_declarator * +c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, + bool *seen_id) +{ + /* Parse any initial pointer part. */ + if (c_parser_next_token_is (parser, CPP_MULT)) + { + struct c_declspecs *quals_attrs = build_null_declspecs (); + struct c_declarator *inner; + c_parser_consume_token (parser); + c_parser_declspecs (parser, quals_attrs, false, false, true, + false, false, true, false, cla_prefer_id); + inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); + if (inner == NULL) + return NULL; + else + return make_pointer_declarator (quals_attrs, inner); + } + /* Now we have a direct declarator, direct abstract declarator or + nothing (which counts as a direct abstract declarator here). */ + return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id); +} + +/* Parse a direct declarator or direct abstract declarator; arguments + as c_parser_declarator. */ + +static struct c_declarator * +c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, + bool *seen_id) +{ + /* The direct declarator must start with an identifier (possibly + omitted) or a parenthesized declarator (possibly abstract). In + an ordinary declarator, initial parentheses must start a + parenthesized declarator. In an abstract declarator or parameter + declarator, they could start a parenthesized declarator or a + parameter list. To tell which, the open parenthesis and any + following gnu-attributes must be read. If a declaration + specifier or standard attributes follow, then it is a parameter + list; if the specifier is a typedef name, there might be an + ambiguity about redeclaring it, which is resolved in the + direction of treating it as a typedef name. If a close + parenthesis follows, it is also an empty parameter list, as the + syntax does not permit empty abstract declarators. Otherwise, it + is a parenthesized declarator (in which case the analysis may be + repeated inside it, recursively). + + ??? There is an ambiguity in a parameter declaration "int + (__attribute__((foo)) x)", where x is not a typedef name: it + could be an abstract declarator for a function, or declare x with + parentheses. The proper resolution of this ambiguity needs + documenting. At present we follow an accident of the old + parser's implementation, whereby the first parameter must have + some declaration specifiers other than just gnu-attributes. Thus as + a parameter declaration it is treated as a parenthesized + parameter named x, and as an abstract declarator it is + rejected. + + ??? Also following the old parser, gnu-attributes inside an empty + parameter list are ignored, making it a list not yielding a + prototype, rather than giving an error or making it have one + parameter with implicit type int. + + ??? Also following the old parser, typedef names may be + redeclared in declarators, but not Objective-C class names. */ + + if (kind != C_DTR_ABSTRACT + && c_parser_next_token_is (parser, CPP_NAME) + && ((type_seen_p + && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME + || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) + || c_parser_peek_token (parser)->id_kind == C_ID_ID)) + { + struct c_declarator *inner + = build_id_declarator (c_parser_peek_token (parser)->value); + *seen_id = true; + inner->id_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (c_parser_nth_token_starts_std_attributes (parser, 1)) + inner->u.id.attrs = c_parser_std_attribute_specifier_sequence (parser); + return c_parser_direct_declarator_inner (parser, *seen_id, inner); + } + + if (kind != C_DTR_NORMAL + && c_parser_next_token_is (parser, CPP_OPEN_SQUARE) + && !c_parser_nth_token_starts_std_attributes (parser, 1)) + { + struct c_declarator *inner = build_id_declarator (NULL_TREE); + inner->id_loc = c_parser_peek_token (parser)->location; + return c_parser_direct_declarator_inner (parser, *seen_id, inner); + } + + /* Either we are at the end of an abstract declarator, or we have + parentheses. */ + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + tree attrs; + struct c_declarator *inner; + c_parser_consume_token (parser); + bool have_gnu_attrs = c_parser_next_token_is_keyword (parser, + RID_ATTRIBUTE); + attrs = c_parser_gnu_attributes (parser); + if (kind != C_DTR_NORMAL + && (c_parser_next_token_starts_declspecs (parser) + || (!have_gnu_attrs + && c_parser_nth_token_starts_std_attributes (parser, 1)) + || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) + { + struct c_arg_info *args + = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL, + attrs, have_gnu_attrs); + if (args == NULL) + return NULL; + else + { + inner = build_id_declarator (NULL_TREE); + if (!(args->types + && args->types != error_mark_node + && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE) + && c_parser_nth_token_starts_std_attributes (parser, 1)) + { + tree std_attrs + = c_parser_std_attribute_specifier_sequence (parser); + if (std_attrs) + inner = build_attrs_declarator (std_attrs, inner); + } + inner = build_function_declarator (args, inner); + return c_parser_direct_declarator_inner (parser, *seen_id, + inner); + } + } + /* A parenthesized declarator. */ + inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); + if (inner != NULL && attrs != NULL) + inner = build_attrs_declarator (attrs, inner); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + if (inner == NULL) + return NULL; + else + return c_parser_direct_declarator_inner (parser, *seen_id, inner); + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return NULL; + } + } + else + { + if (kind == C_DTR_NORMAL) + { + c_parser_error (parser, "expected identifier or %<(%>"); + return NULL; + } + else + return build_id_declarator (NULL_TREE); + } +} + +/* Parse part of a direct declarator or direct abstract declarator, + given that some (in INNER) has already been parsed; ID_PRESENT is + true if an identifier is present, false for an abstract + declarator. */ + +static struct c_declarator * +c_parser_direct_declarator_inner (c_parser *parser, bool id_present, + struct c_declarator *inner) +{ + /* Parse a sequence of array declarators and parameter lists. */ + if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE) + && !c_parser_nth_token_starts_std_attributes (parser, 1)) + { + location_t brace_loc = c_parser_peek_token (parser)->location; + struct c_declarator *declarator; + struct c_declspecs *quals_attrs = build_null_declspecs (); + bool static_seen; + bool star_seen; + struct c_expr dimen; + dimen.value = NULL_TREE; + dimen.original_code = ERROR_MARK; + dimen.original_type = NULL_TREE; + c_parser_consume_token (parser); + c_parser_declspecs (parser, quals_attrs, false, false, true, + false, false, false, false, cla_prefer_id); + static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC); + if (static_seen) + c_parser_consume_token (parser); + if (static_seen && !quals_attrs->declspecs_seen_p) + c_parser_declspecs (parser, quals_attrs, false, false, true, + false, false, false, false, cla_prefer_id); + if (!quals_attrs->declspecs_seen_p) + quals_attrs = NULL; + /* If "static" is present, there must be an array dimension. + Otherwise, there may be a dimension, "*", or no + dimension. */ + if (static_seen) + { + star_seen = false; + dimen = c_parser_expr_no_commas (parser, NULL); + } + else + { + if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + { + dimen.value = NULL_TREE; + star_seen = false; + } + else if (c_parser_next_token_is (parser, CPP_MULT)) + { + if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE) + { + dimen.value = NULL_TREE; + star_seen = true; + c_parser_consume_token (parser); + } + else + { + star_seen = false; + dimen = c_parser_expr_no_commas (parser, NULL); + } + } + else + { + star_seen = false; + dimen = c_parser_expr_no_commas (parser, NULL); + } + } + if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + c_parser_consume_token (parser); + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + return NULL; + } + if (dimen.value) + dimen = convert_lvalue_to_rvalue (brace_loc, dimen, true, true); + declarator = build_array_declarator (brace_loc, dimen.value, quals_attrs, + static_seen, star_seen); + if (declarator == NULL) + return NULL; + if (c_parser_nth_token_starts_std_attributes (parser, 1)) + { + tree std_attrs + = c_parser_std_attribute_specifier_sequence (parser); + if (std_attrs) + inner = build_attrs_declarator (std_attrs, inner); + } + inner = set_array_declarator_inner (declarator, inner); + return c_parser_direct_declarator_inner (parser, id_present, inner); + } + else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + tree attrs; + struct c_arg_info *args; + c_parser_consume_token (parser); + bool have_gnu_attrs = c_parser_next_token_is_keyword (parser, + RID_ATTRIBUTE); + attrs = c_parser_gnu_attributes (parser); + args = c_parser_parms_declarator (parser, id_present, attrs, + have_gnu_attrs); + if (args == NULL) + return NULL; + else + { + if (!(args->types + && args->types != error_mark_node + && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE) + && c_parser_nth_token_starts_std_attributes (parser, 1)) + { + tree std_attrs + = c_parser_std_attribute_specifier_sequence (parser); + if (std_attrs) + inner = build_attrs_declarator (std_attrs, inner); + } + inner = build_function_declarator (args, inner); + return c_parser_direct_declarator_inner (parser, id_present, inner); + } + } + return inner; +} + +/* Parse a parameter list or identifier list, including the closing + parenthesis but not the opening one. ATTRS are the gnu-attributes + at the start of the list. ID_LIST_OK is true if an identifier list + is acceptable; such a list must not have attributes at the start. + HAVE_GNU_ATTRS says whether any gnu-attributes (including empty + attributes) were present (in which case standard attributes cannot + occur). */ + +static struct c_arg_info * +c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs, + bool have_gnu_attrs) +{ + push_scope (); + declare_parm_level (); + /* If the list starts with an identifier, it is an identifier list. + Otherwise, it is either a prototype list or an empty list. */ + if (id_list_ok + && !attrs + && c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID + + /* Look ahead to detect typos in type names. */ + && c_parser_peek_2nd_token (parser)->type != CPP_NAME + && c_parser_peek_2nd_token (parser)->type != CPP_MULT + && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN + && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE + && c_parser_peek_2nd_token (parser)->type != CPP_KEYWORD) + { + tree list = NULL_TREE, *nextp = &list; + while (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + *nextp = build_tree_list (NULL_TREE, + c_parser_peek_token (parser)->value); + nextp = & TREE_CHAIN (*nextp); + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_error (parser, "expected identifier"); + break; + } + } + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + struct c_arg_info *ret = build_arg_info (); + ret->types = list; + c_parser_consume_token (parser); + pop_scope (); + return ret; + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + pop_scope (); + return NULL; + } + } + else + { + struct c_arg_info *ret + = c_parser_parms_list_declarator (parser, attrs, NULL, have_gnu_attrs); + pop_scope (); + return ret; + } +} + +/* Parse a parameter list (possibly empty), including the closing + parenthesis but not the opening one. ATTRS are the gnu-attributes + at the start of the list; if HAVE_GNU_ATTRS, there were some such + attributes (possibly empty, in which case ATTRS is NULL_TREE), + which means standard attributes cannot start the list. EXPR is + NULL or an expression that needs to be evaluated for the side + effects of array size expressions in the parameters. */ + +static struct c_arg_info * +c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr, + bool have_gnu_attrs) +{ + bool bad_parm = false; + + /* ??? Following the old parser, forward parameter declarations may + use abstract declarators, and if no real parameter declarations + follow the forward declarations then this is not diagnosed. Also + note as above that gnu-attributes are ignored as the only contents of + the parentheses, or as the only contents after forward + declarations. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + struct c_arg_info *ret = build_arg_info (); + c_parser_consume_token (parser); + return ret; + } + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + struct c_arg_info *ret = build_arg_info (); + + if (flag_allow_parameterless_variadic_functions) + { + /* F (...) is allowed. */ + ret->types = NULL_TREE; + } + else + { + /* Suppress -Wold-style-definition for this case. */ + ret->types = error_mark_node; + error_at (c_parser_peek_token (parser)->location, + "ISO C requires a named argument before %<...%>"); + } + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + return ret; + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return NULL; + } + } + /* Nonempty list of parameters, either terminated with semicolon + (forward declarations; recurse) or with close parenthesis (normal + function) or with ", ... )" (variadic function). */ + while (true) + { + /* Parse a parameter. */ + struct c_parm *parm = c_parser_parameter_declaration (parser, attrs, + have_gnu_attrs); + attrs = NULL_TREE; + have_gnu_attrs = false; + if (parm == NULL) + bad_parm = true; + else + push_parm_decl (parm, &expr); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + tree new_attrs; + c_parser_consume_token (parser); + mark_forward_parm_decls (); + bool new_have_gnu_attrs + = c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE); + new_attrs = c_parser_gnu_attributes (parser); + return c_parser_parms_list_declarator (parser, new_attrs, expr, + new_have_gnu_attrs); + } + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + if (bad_parm) + return NULL; + else + return get_parm_info (false, expr); + } + if (!c_parser_require (parser, CPP_COMMA, + "expected %<;%>, %<,%> or %<)%>", + UNKNOWN_LOCATION, false)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return NULL; + } + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + if (bad_parm) + return NULL; + else + return get_parm_info (true, expr); + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return NULL; + } + } + } +} + +/* Parse a parameter declaration. ATTRS are the gnu-attributes at the + start of the declaration if it is the first parameter; + HAVE_GNU_ATTRS is true if there were any gnu-attributes there (even + empty) there. */ + +static struct c_parm * +c_parser_parameter_declaration (c_parser *parser, tree attrs, + bool have_gnu_attrs) +{ + struct c_declspecs *specs; + struct c_declarator *declarator; + tree prefix_attrs; + tree postfix_attrs = NULL_TREE; + bool dummy = false; + + /* Accept #pragmas between parameter declarations. */ + while (c_parser_next_token_is (parser, CPP_PRAGMA)) + c_parser_pragma (parser, pragma_param, NULL); + + if (!c_parser_next_token_starts_declspecs (parser) + && !c_parser_nth_token_starts_std_attributes (parser, 1)) + { + c_token *token = c_parser_peek_token (parser); + if (parser->error) + return NULL; + c_parser_set_source_position_from_token (token); + if (c_parser_next_tokens_start_typename (parser, cla_prefer_type)) + { + auto_diagnostic_group d; + name_hint hint = lookup_name_fuzzy (token->value, + FUZZY_LOOKUP_TYPENAME, + token->location); + if (const char *suggestion = hint.suggestion ()) + { + gcc_rich_location richloc (token->location); + richloc.add_fixit_replace (suggestion); + error_at (&richloc, + "unknown type name %qE; did you mean %qs?", + token->value, suggestion); + } + else + error_at (token->location, "unknown type name %qE", token->value); + parser->error = true; + } + /* ??? In some Objective-C cases '...' isn't applicable so there + should be a different message. */ + else + c_parser_error (parser, + "expected declaration specifiers or %<...%>"); + c_parser_skip_to_end_of_parameter (parser); + return NULL; + } + + location_t start_loc = c_parser_peek_token (parser)->location; + + specs = build_null_declspecs (); + if (attrs) + { + declspecs_add_attrs (input_location, specs, attrs); + attrs = NULL_TREE; + } + c_parser_declspecs (parser, specs, true, true, true, true, false, + !have_gnu_attrs, true, cla_nonabstract_decl); + finish_declspecs (specs); + pending_xref_error (); + prefix_attrs = specs->attrs; + specs->attrs = NULL_TREE; + declarator = c_parser_declarator (parser, + specs->typespec_kind != ctsk_none, + C_DTR_PARM, &dummy); + if (declarator == NULL) + { + c_parser_skip_until_found (parser, CPP_COMMA, NULL); + return NULL; + } + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + postfix_attrs = c_parser_gnu_attributes (parser); + + /* Generate a location for the parameter, ranging from the start of the + initial token to the end of the final token. + + If we have a identifier, then use it for the caret location, e.g. + + extern int callee (int one, int (*two)(int, int), float three); + ~~~~~~^~~~~~~~~~~~~~ + + otherwise, reuse the start location for the caret location e.g.: + + extern int callee (int one, int (*)(int, int), float three); + ^~~~~~~~~~~~~~~~~ + */ + location_t end_loc = parser->last_token_location; + + /* Find any cdk_id declarator; determine if we have an identifier. */ + c_declarator *id_declarator = declarator; + while (id_declarator && id_declarator->kind != cdk_id) + id_declarator = id_declarator->declarator; + location_t caret_loc = (id_declarator->u.id.id + ? id_declarator->id_loc + : start_loc); + location_t param_loc = make_location (caret_loc, start_loc, end_loc); + + return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs), + declarator, param_loc); +} + +/* Parse a string literal in an asm expression. It should not be + translated, and wide string literals are an error although + permitted by the syntax. This is a GNU extension. + + asm-string-literal: + string-literal +*/ + +static tree +c_parser_asm_string_literal (c_parser *parser) +{ + tree str; + int save_flag = warn_overlength_strings; + warn_overlength_strings = 0; + str = c_parser_string_literal (parser, false, false).value; + warn_overlength_strings = save_flag; + return str; +} + +/* Parse a simple asm expression. This is used in restricted + contexts, where a full expression with inputs and outputs does not + make sense. This is a GNU extension. + + simple-asm-expr: + asm ( asm-string-literal ) +*/ + +static tree +c_parser_simple_asm_expr (c_parser *parser) +{ + tree str; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + return NULL_TREE; + str = c_parser_asm_string_literal (parser); + if (!parens.require_close (parser)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return NULL_TREE; + } + return str; +} + +static tree +c_parser_gnu_attribute_any_word (c_parser *parser) +{ + tree attr_name = NULL_TREE; + + if (c_parser_next_token_is (parser, CPP_KEYWORD)) + { + /* ??? See comment above about what keywords are accepted here. */ + bool ok; + switch (c_parser_peek_token (parser)->keyword) + { + case RID_STATIC: + case RID_UNSIGNED: + case RID_LONG: + case RID_CONST: + case RID_EXTERN: + case RID_REGISTER: + case RID_TYPEDEF: + case RID_SHORT: + case RID_INLINE: + case RID_NORETURN: + case RID_VOLATILE: + case RID_SIGNED: + case RID_AUTO: + case RID_RESTRICT: + case RID_COMPLEX: + case RID_THREAD: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + CASE_RID_FLOATN_NX: + case RID_BOOL: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_CANCEL: + case RID_ATOMIC: + case RID_AUTO_TYPE: + case RID_INT_N_0: + case RID_INT_N_1: + case RID_INT_N_2: + case RID_INT_N_3: + ok = true; + break; + default: + ok = false; + break; + } + if (!ok) + return NULL_TREE; + + /* Accept __attribute__((__const)) as __attribute__((const)) etc. */ + attr_name = ridpointers[(int) c_parser_peek_token (parser)->keyword]; + } + else if (c_parser_next_token_is (parser, CPP_NAME)) + attr_name = c_parser_peek_token (parser)->value; + + return attr_name; +} + +/* Parse attribute arguments. This is a common form of syntax + covering all currently valid GNU and standard attributes. + + gnu-attribute-arguments: + identifier + identifier , nonempty-expr-list + expr-list + + where the "identifier" must not be declared as a type. ??? Why not + allow identifiers declared as types to start the arguments? */ + +static tree +c_parser_attribute_arguments (c_parser *parser, bool takes_identifier, + bool require_string, bool allow_empty_args) +{ + vec *expr_list; + tree attr_args; + /* Parse the attribute contents. If they start with an + identifier which is followed by a comma or close + parenthesis, then the arguments start with that + identifier; otherwise they are an expression list. + In objective-c the identifier may be a classname. */ + if (c_parser_next_token_is (parser, CPP_NAME) + && (c_parser_peek_token (parser)->id_kind == C_ID_ID + || (c_dialect_objc () + && c_parser_peek_token (parser)->id_kind + == C_ID_CLASSNAME)) + && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA) + || (c_parser_peek_2nd_token (parser)->type + == CPP_CLOSE_PAREN)) + && (takes_identifier + || (c_dialect_objc () + && c_parser_peek_token (parser)->id_kind + == C_ID_CLASSNAME))) + { + tree arg1 = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + attr_args = build_tree_list (NULL_TREE, arg1); + else + { + tree tree_list; + c_parser_consume_token (parser); + expr_list = c_parser_expr_list (parser, false, true, + NULL, NULL, NULL, NULL); + tree_list = build_tree_list_vec (expr_list); + attr_args = tree_cons (NULL_TREE, arg1, tree_list); + release_tree_vector (expr_list); + } + } + else + { + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + if (!allow_empty_args) + error_at (c_parser_peek_token (parser)->location, + "parentheses must be omitted if " + "attribute argument list is empty"); + attr_args = NULL_TREE; + } + else if (require_string) + { + /* The only valid argument for this attribute is a string + literal. Handle this specially here to avoid accepting + string literals with excess parentheses. */ + tree string = c_parser_string_literal (parser, false, true).value; + attr_args = build_tree_list (NULL_TREE, string); + } + else + { + expr_list = c_parser_expr_list (parser, false, true, + NULL, NULL, NULL, NULL); + attr_args = build_tree_list_vec (expr_list); + release_tree_vector (expr_list); + } + } + return attr_args; +} + +/* Parse (possibly empty) gnu-attributes. This is a GNU extension. + + gnu-attributes: + empty + gnu-attributes gnu-attribute + + gnu-attribute: + __attribute__ ( ( gnu-attribute-list ) ) + + gnu-attribute-list: + gnu-attrib + gnu-attribute_list , gnu-attrib + + gnu-attrib: + empty + any-word + any-word ( gnu-attribute-arguments ) + + where "any-word" may be any identifier (including one declared as a + type), a reserved word storage class specifier, type specifier or + type qualifier. ??? This still leaves out most reserved keywords + (following the old parser), shouldn't we include them? + When EXPECT_COMMA is true, expect the attribute to be preceded + by a comma and fail if it isn't. + When EMPTY_OK is true, allow and consume any number of consecutive + commas with no attributes in between. */ + +static tree +c_parser_gnu_attribute (c_parser *parser, tree attrs, + bool expect_comma = false, bool empty_ok = true) +{ + bool comma_first = c_parser_next_token_is (parser, CPP_COMMA); + if (!comma_first + && !c_parser_next_token_is (parser, CPP_NAME) + && !c_parser_next_token_is (parser, CPP_KEYWORD)) + return NULL_TREE; + + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + if (!empty_ok) + return attrs; + } + + tree attr_name = c_parser_gnu_attribute_any_word (parser); + if (attr_name == NULL_TREE) + return NULL_TREE; + + attr_name = canonicalize_attr_name (attr_name); + c_parser_consume_token (parser); + + tree attr; + if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) + { + if (expect_comma && !comma_first) + { + /* A comma is missing between the last attribute on the chain + and this one. */ + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return error_mark_node; + } + attr = build_tree_list (attr_name, NULL_TREE); + /* Add this attribute to the list. */ + attrs = chainon (attrs, attr); + return attrs; + } + c_parser_consume_token (parser); + + tree attr_args + = c_parser_attribute_arguments (parser, + attribute_takes_identifier_p (attr_name), + false, true); + + attr = build_tree_list (attr_name, attr_args); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_consume_token (parser); + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return error_mark_node; + } + + if (expect_comma && !comma_first) + { + /* A comma is missing between the last attribute on the chain + and this one. */ + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return error_mark_node; + } + + /* Add this attribute to the list. */ + attrs = chainon (attrs, attr); + return attrs; +} + +static tree +c_parser_gnu_attributes (c_parser *parser) +{ + tree attrs = NULL_TREE; + while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + { + bool save_translate_strings_p = parser->translate_strings_p; + parser->translate_strings_p = false; + /* Consume the `__attribute__' keyword. */ + c_parser_consume_token (parser); + /* Look for the two `(' tokens. */ + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + parser->translate_strings_p = save_translate_strings_p; + return attrs; + } + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + parser->translate_strings_p = save_translate_strings_p; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return attrs; + } + /* Parse the attribute list. Require a comma between successive + (possibly empty) attributes. */ + for (bool expect_comma = false; ; expect_comma = true) + { + /* Parse a single attribute. */ + tree attr = c_parser_gnu_attribute (parser, attrs, expect_comma); + if (attr == error_mark_node) + return attrs; + if (!attr) + break; + attrs = attr; + } + + /* Look for the two `)' tokens. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_consume_token (parser); + else + { + parser->translate_strings_p = save_translate_strings_p; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return attrs; + } + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_consume_token (parser); + else + { + parser->translate_strings_p = save_translate_strings_p; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return attrs; + } + parser->translate_strings_p = save_translate_strings_p; + } + + return attrs; +} + +/* Parse an optional balanced token sequence. + + balanced-token-sequence: + balanced-token + balanced-token-sequence balanced-token + + balanced-token: + ( balanced-token-sequence[opt] ) + [ balanced-token-sequence[opt] ] + { balanced-token-sequence[opt] } + any token other than ()[]{} +*/ + +static void +c_parser_balanced_token_sequence (c_parser *parser) +{ + while (true) + { + c_token *token = c_parser_peek_token (parser); + switch (token->type) + { + case CPP_OPEN_BRACE: + { + matching_braces braces; + braces.consume_open (parser); + c_parser_balanced_token_sequence (parser); + braces.require_close (parser); + break; + } + + case CPP_OPEN_PAREN: + { + matching_parens parens; + parens.consume_open (parser); + c_parser_balanced_token_sequence (parser); + parens.require_close (parser); + break; + } + + case CPP_OPEN_SQUARE: + c_parser_consume_token (parser); + c_parser_balanced_token_sequence (parser); + c_parser_require (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + break; + + case CPP_CLOSE_BRACE: + case CPP_CLOSE_PAREN: + case CPP_CLOSE_SQUARE: + case CPP_EOF: + return; + + case CPP_PRAGMA: + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser, false); + break; + + default: + c_parser_consume_token (parser); + break; + } + } +} + +/* Parse standard (C2X) attributes (including GNU attributes in the + gnu:: namespace). + + attribute-specifier-sequence: + attribute-specifier-sequence[opt] attribute-specifier + + attribute-specifier: + [ [ attribute-list ] ] + + attribute-list: + attribute[opt] + attribute-list, attribute[opt] + + attribute: + attribute-token attribute-argument-clause[opt] + + attribute-token: + standard-attribute + attribute-prefixed-token + + standard-attribute: + identifier + + attribute-prefixed-token: + attribute-prefix :: identifier + + attribute-prefix: + identifier + + attribute-argument-clause: + ( balanced-token-sequence[opt] ) + + Keywords are accepted as identifiers for this purpose. +*/ + +static tree +c_parser_std_attribute (c_parser *parser, bool for_tm) +{ + c_token *token = c_parser_peek_token (parser); + tree ns, name, attribute; + + /* Parse the attribute-token. */ + if (token->type != CPP_NAME && token->type != CPP_KEYWORD) + { + c_parser_error (parser, "expected identifier"); + return error_mark_node; + } + name = canonicalize_attr_name (token->value); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SCOPE)) + { + ns = name; + c_parser_consume_token (parser); + token = c_parser_peek_token (parser); + if (token->type != CPP_NAME && token->type != CPP_KEYWORD) + { + c_parser_error (parser, "expected identifier"); + return error_mark_node; + } + name = canonicalize_attr_name (token->value); + c_parser_consume_token (parser); + } + else + ns = NULL_TREE; + attribute = build_tree_list (build_tree_list (ns, name), NULL_TREE); + + /* Parse the arguments, if any. */ + const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (attribute)); + if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) + goto out; + { + location_t open_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + parens.consume_open (parser); + if ((as && as->max_length == 0) + /* Special-case the transactional-memory attribute "outer", + which is specially handled but not registered as an + attribute, to avoid allowing arbitrary balanced token + sequences as arguments. */ + || is_attribute_p ("outer", name)) + { + error_at (open_loc, "%qE attribute does not take any arguments", name); + parens.skip_until_found_close (parser); + return error_mark_node; + } + /* If this is a fake attribute created to handle -Wno-attributes, + we must skip parsing the arguments. */ + if (as && !attribute_ignored_p (as)) + { + bool takes_identifier + = (ns != NULL_TREE + && strcmp (IDENTIFIER_POINTER (ns), "gnu") == 0 + && attribute_takes_identifier_p (name)); + bool require_string + = (ns == NULL_TREE + && (strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0 + || strcmp (IDENTIFIER_POINTER (name), "nodiscard") == 0)); + TREE_VALUE (attribute) + = c_parser_attribute_arguments (parser, takes_identifier, + require_string, false); + } + else + c_parser_balanced_token_sequence (parser); + parens.require_close (parser); + } + out: + if (ns == NULL_TREE && !for_tm && !as) + { + /* An attribute with standard syntax and no namespace specified + is a constraint violation if it is not one of the known + standard attributes. Diagnose it here with a pedwarn and + then discard it to prevent a duplicate warning later. */ + pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", + name); + return error_mark_node; + } + return attribute; +} + +static tree +c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) +{ + location_t loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) + return NULL_TREE; + if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + return NULL_TREE; + } + if (!for_tm) + pedwarn_c11 (loc, OPT_Wpedantic, + "ISO C does not support %<[[]]%> attributes before C2X"); + tree attributes = NULL_TREE; + while (true) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_CLOSE_SQUARE) + break; + if (token->type == CPP_COMMA) + { + c_parser_consume_token (parser); + continue; + } + tree attribute = c_parser_std_attribute (parser, for_tm); + if (attribute != error_mark_node) + { + TREE_CHAIN (attribute) = attributes; + attributes = attribute; + } + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + } + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + return nreverse (attributes); +} + +/* Look past an optional balanced token sequence of raw look-ahead + tokens starting with the *Nth token. *N is updated to point to the + following token. Return true if such a sequence was found, false + if the tokens parsed were not balanced. */ + +static bool +c_parser_check_balanced_raw_token_sequence (c_parser *parser, unsigned int *n) +{ + while (true) + { + c_token *token = c_parser_peek_nth_token_raw (parser, *n); + switch (token->type) + { + case CPP_OPEN_BRACE: + { + ++*n; + if (c_parser_check_balanced_raw_token_sequence (parser, n)) + { + token = c_parser_peek_nth_token_raw (parser, *n); + if (token->type == CPP_CLOSE_BRACE) + ++*n; + else + return false; + } + else + return false; + break; + } + + case CPP_OPEN_PAREN: + { + ++*n; + if (c_parser_check_balanced_raw_token_sequence (parser, n)) + { + token = c_parser_peek_nth_token_raw (parser, *n); + if (token->type == CPP_CLOSE_PAREN) + ++*n; + else + return false; + } + else + return false; + break; + } + + case CPP_OPEN_SQUARE: + { + ++*n; + if (c_parser_check_balanced_raw_token_sequence (parser, n)) + { + token = c_parser_peek_nth_token_raw (parser, *n); + if (token->type == CPP_CLOSE_SQUARE) + ++*n; + else + return false; + } + else + return false; + break; + } + + case CPP_CLOSE_BRACE: + case CPP_CLOSE_PAREN: + case CPP_CLOSE_SQUARE: + case CPP_EOF: + return true; + + default: + ++*n; + break; + } + } +} + +/* Return whether standard attributes start with the Nth token. */ + +static bool +c_parser_nth_token_starts_std_attributes (c_parser *parser, unsigned int n) +{ + if (!(c_parser_peek_nth_token (parser, n)->type == CPP_OPEN_SQUARE + && c_parser_peek_nth_token (parser, n + 1)->type == CPP_OPEN_SQUARE)) + return false; + /* In C, '[[' must start attributes. In Objective-C, we need to + check whether '[[' is matched by ']]'. */ + if (!c_dialect_objc ()) + return true; + n += 2; + if (!c_parser_check_balanced_raw_token_sequence (parser, &n)) + return false; + c_token *token = c_parser_peek_nth_token_raw (parser, n); + if (token->type != CPP_CLOSE_SQUARE) + return false; + token = c_parser_peek_nth_token_raw (parser, n + 1); + return token->type == CPP_CLOSE_SQUARE; +} + +static tree +c_parser_std_attribute_specifier_sequence (c_parser *parser) +{ + tree attributes = NULL_TREE; + do + { + tree attrs = c_parser_std_attribute_specifier (parser, false); + attributes = chainon (attributes, attrs); + } + while (c_parser_nth_token_starts_std_attributes (parser, 1)); + return attributes; +} + +/* Parse a type name (C90 6.5.5, C99 6.7.6, C11 6.7.7). ALIGNAS_OK + says whether alignment specifiers are OK (only in cases that might + be the type name of a compound literal). + + type-name: + specifier-qualifier-list abstract-declarator[opt] +*/ + +struct c_type_name * +c_parser_type_name (c_parser *parser, bool alignas_ok) +{ + struct c_declspecs *specs = build_null_declspecs (); + struct c_declarator *declarator; + struct c_type_name *ret; + bool dummy = false; + c_parser_declspecs (parser, specs, false, true, true, alignas_ok, false, + false, true, cla_prefer_type); + if (!specs->declspecs_seen_p) + { + c_parser_error (parser, "expected specifier-qualifier-list"); + return NULL; + } + if (specs->type != error_mark_node) + { + pending_xref_error (); + finish_declspecs (specs); + } + declarator = c_parser_declarator (parser, + specs->typespec_kind != ctsk_none, + C_DTR_ABSTRACT, &dummy); + if (declarator == NULL) + return NULL; + ret = XOBNEW (&parser_obstack, struct c_type_name); + ret->specs = specs; + ret->declarator = declarator; + return ret; +} + +/* Parse an initializer (C90 6.5.7, C99 6.7.8, C11 6.7.9). + + initializer: + assignment-expression + { initializer-list } + { initializer-list , } + + initializer-list: + designation[opt] initializer + initializer-list , designation[opt] initializer + + designation: + designator-list = + + designator-list: + designator + designator-list designator + + designator: + array-designator + . identifier + + array-designator: + [ constant-expression ] + + GNU extensions: + + initializer: + { } + + designation: + array-designator + identifier : + + array-designator: + [ constant-expression ... constant-expression ] + + Any expression without commas is accepted in the syntax for the + constant-expressions, with non-constant expressions rejected later. + + This function is only used for top-level initializers; for nested + ones, see c_parser_initval. */ + +static struct c_expr +c_parser_initializer (c_parser *parser) +{ + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + return c_parser_braced_init (parser, NULL_TREE, false, NULL); + else + { + struct c_expr ret; + location_t loc = c_parser_peek_token (parser)->location; + ret = c_parser_expr_no_commas (parser, NULL); + if (TREE_CODE (ret.value) != STRING_CST + && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR) + ret = convert_lvalue_to_rvalue (loc, ret, true, true); + return ret; + } +} + +/* The location of the last comma within the current initializer list, + or UNKNOWN_LOCATION if not within one. */ + +location_t last_init_list_comma; + +/* Parse a braced initializer list. TYPE is the type specified for a + compound literal, and NULL_TREE for other initializers and for + nested braced lists. NESTED_P is true for nested braced lists, + false for the list of a compound literal or the list that is the + top-level initializer in a declaration. */ + +static struct c_expr +c_parser_braced_init (c_parser *parser, tree type, bool nested_p, + struct obstack *outer_obstack) +{ + struct c_expr ret; + struct obstack braced_init_obstack; + location_t brace_loc = c_parser_peek_token (parser)->location; + gcc_obstack_init (&braced_init_obstack); + gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); + matching_braces braces; + braces.consume_open (parser); + if (nested_p) + { + finish_implicit_inits (brace_loc, outer_obstack); + push_init_level (brace_loc, 0, &braced_init_obstack); + } + else + really_start_incremental_init (type); + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + pedwarn (brace_loc, OPT_Wpedantic, "ISO C forbids empty initializer braces"); + } + else + { + /* Parse a non-empty initializer list, possibly with a trailing + comma. */ + while (true) + { + c_parser_initelt (parser, &braced_init_obstack); + if (parser->error) + break; + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + last_init_list_comma = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + } + else + break; + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + break; + } + } + c_token *next_tok = c_parser_peek_token (parser); + if (next_tok->type != CPP_CLOSE_BRACE) + { + ret.set_error (); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + braces.skip_until_found_close (parser); + pop_init_level (brace_loc, 0, &braced_init_obstack, last_init_list_comma); + obstack_free (&braced_init_obstack, NULL); + return ret; + } + location_t close_loc = next_tok->location; + c_parser_consume_token (parser); + ret = pop_init_level (brace_loc, 0, &braced_init_obstack, close_loc); + obstack_free (&braced_init_obstack, NULL); + set_c_expr_source_range (&ret, brace_loc, close_loc); + return ret; +} + +/* Parse a nested initializer, including designators. */ + +static void +c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) +{ + /* Parse any designator or designator list. A single array + designator may have the subsequent "=" omitted in GNU C, but a + longer list or a structure member designator may not. */ + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + /* Old-style structure member designator. */ + set_init_label (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value, + c_parser_peek_token (parser)->location, + braced_init_obstack); + /* Use the colon as the error location. */ + pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_Wpedantic, + "obsolete use of designated initializer with %<:%>"); + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + else + { + /* des_seen is 0 if there have been no designators, 1 if there + has been a single array designator and 2 otherwise. */ + int des_seen = 0; + /* Location of a designator. */ + location_t des_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE) + || c_parser_next_token_is (parser, CPP_DOT)) + { + int des_prev = des_seen; + if (!des_seen) + des_loc = c_parser_peek_token (parser)->location; + if (des_seen < 2) + des_seen++; + if (c_parser_next_token_is (parser, CPP_DOT)) + { + des_seen = 2; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + set_init_label (des_loc, c_parser_peek_token (parser)->value, + c_parser_peek_token (parser)->location, + braced_init_obstack); + c_parser_consume_token (parser); + } + else + { + struct c_expr init; + init.set_error (); + init.original_code = ERROR_MARK; + init.original_type = NULL; + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_COMMA, NULL); + process_init_element (input_location, init, false, + braced_init_obstack); + return; + } + } + else + { + tree first, second; + location_t ellipsis_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + location_t array_index_loc = UNKNOWN_LOCATION; + /* ??? Following the old parser, [ objc-receiver + objc-message-args ] is accepted as an initializer, + being distinguished from a designator by what follows + the first assignment expression inside the square + brackets, but after a first array designator a + subsequent square bracket is for Objective-C taken to + start an expression, using the obsolete form of + designated initializer without '=', rather than + possibly being a second level of designation: in LALR + terms, the '[' is shifted rather than reducing + designator to designator-list. */ + if (des_prev == 1 && c_dialect_objc ()) + { + des_seen = des_prev; + break; + } + if (des_prev == 0 && c_dialect_objc ()) + { + /* This might be an array designator or an + Objective-C message expression. If the former, + continue parsing here; if the latter, parse the + remainder of the initializer given the starting + primary-expression. ??? It might make sense to + distinguish when des_prev == 1 as well; see + previous comment. */ + tree rec, args; + struct c_expr mexpr; + c_parser_consume_token (parser); + if (c_parser_peek_token (parser)->type == CPP_NAME + && ((c_parser_peek_token (parser)->id_kind + == C_ID_TYPENAME) + || (c_parser_peek_token (parser)->id_kind + == C_ID_CLASSNAME))) + { + /* Type name receiver. */ + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + rec = objc_get_class_reference (id); + goto parse_message_args; + } + first = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (first); + if (c_parser_next_token_is (parser, CPP_ELLIPSIS) + || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + goto array_desig_after_first; + /* Expression receiver. So far only one part + without commas has been parsed; there might be + more of the expression. */ + rec = first; + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + struct c_expr next; + location_t comma_loc, exp_loc; + comma_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + next = c_parser_expr_no_commas (parser, NULL); + next = convert_lvalue_to_rvalue (exp_loc, next, + true, true); + rec = build_compound_expr (comma_loc, rec, next.value); + } + parse_message_args: + /* Now parse the objc-message-args. */ + args = c_parser_objc_message_args (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + mexpr.value + = objc_build_message_expr (rec, args); + mexpr.original_code = ERROR_MARK; + mexpr.original_type = NULL; + /* Now parse and process the remainder of the + initializer, starting with this message + expression as a primary-expression. */ + c_parser_initval (parser, &mexpr, braced_init_obstack); + return; + } + c_parser_consume_token (parser); + array_index_loc = c_parser_peek_token (parser)->location; + first = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (first); + array_desig_after_first: + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + ellipsis_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + second = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (second); + } + else + second = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + { + c_parser_consume_token (parser); + set_init_index (array_index_loc, first, second, + braced_init_obstack); + if (second) + pedwarn (ellipsis_loc, OPT_Wpedantic, + "ISO C forbids specifying range of elements to initialize"); + } + else + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + } + } + if (des_seen >= 1) + { + if (c_parser_next_token_is (parser, CPP_EQ)) + { + pedwarn_c90 (des_loc, OPT_Wpedantic, + "ISO C90 forbids specifying subobject " + "to initialize"); + c_parser_consume_token (parser); + } + else + { + if (des_seen == 1) + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "obsolete use of designated initializer without %<=%>"); + else + { + struct c_expr init; + init.set_error (); + init.original_code = ERROR_MARK; + init.original_type = NULL; + c_parser_error (parser, "expected %<=%>"); + c_parser_skip_until_found (parser, CPP_COMMA, NULL); + process_init_element (input_location, init, false, + braced_init_obstack); + return; + } + } + } + } + c_parser_initval (parser, NULL, braced_init_obstack); +} + +/* Parse a nested initializer; as c_parser_initializer but parses + initializers within braced lists, after any designators have been + applied. If AFTER is not NULL then it is an Objective-C message + expression which is the primary-expression starting the + initializer. */ + +static void +c_parser_initval (c_parser *parser, struct c_expr *after, + struct obstack * braced_init_obstack) +{ + struct c_expr init; + gcc_assert (!after || c_dialect_objc ()); + location_t loc = c_parser_peek_token (parser)->location; + + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after) + init = c_parser_braced_init (parser, NULL_TREE, true, + braced_init_obstack); + else + { + init = c_parser_expr_no_commas (parser, after); + if (init.value != NULL_TREE + && TREE_CODE (init.value) != STRING_CST + && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR) + init = convert_lvalue_to_rvalue (loc, init, true, true); + } + process_init_element (loc, init, false, braced_init_obstack); +} + +/* Parse a compound statement (possibly a function body) (C90 6.6.2, + C99 6.8.2, C11 6.8.2, C2X 6.8.2). + + compound-statement: + { block-item-list[opt] } + { label-declarations block-item-list } + + block-item-list: + block-item + block-item-list block-item + + block-item: + label + nested-declaration + statement + + nested-declaration: + declaration + + GNU extensions: + + compound-statement: + { label-declarations block-item-list } + + nested-declaration: + __extension__ nested-declaration + nested-function-definition + + label-declarations: + label-declaration + label-declarations label-declaration + + label-declaration: + __label__ identifier-list ; + + Allowing the mixing of declarations and code is new in C99. The + GNU syntax also permits (not shown above) labels at the end of + compound statements, which yield an error. We don't allow labels + on declarations; this might seem like a natural extension, but + there would be a conflict between gnu-attributes on the label and + prefix gnu-attributes on the declaration. ??? The syntax follows the + old parser in requiring something after label declarations. + Although they are erroneous if the labels declared aren't defined, + is it useful for the syntax to be this way? + + OpenACC: + + block-item: + openacc-directive + + openacc-directive: + update-directive + + OpenMP: + + block-item: + openmp-directive + + openmp-directive: + barrier-directive + flush-directive + taskwait-directive + taskyield-directive + cancel-directive + cancellation-point-directive */ + +static tree +c_parser_compound_statement (c_parser *parser, location_t *endlocp) +{ + tree stmt; + location_t brace_loc; + brace_loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + { + /* Ensure a scope is entered and left anyway to avoid confusion + if we have just prepared to enter a function body. */ + stmt = c_begin_compound_stmt (true); + c_end_compound_stmt (brace_loc, stmt, true); + return error_mark_node; + } + stmt = c_begin_compound_stmt (true); + location_t end_loc = c_parser_compound_statement_nostart (parser); + if (endlocp) + *endlocp = end_loc; + + return c_end_compound_stmt (brace_loc, stmt, true); +} + +/* Parse a compound statement except for the opening brace. This is + used for parsing both compound statements and statement expressions + (which follow different paths to handling the opening). */ + +static location_t +c_parser_compound_statement_nostart (c_parser *parser) +{ + bool last_stmt = false; + bool last_label = false; + bool save_valid_for_pragma = valid_location_for_stdc_pragma_p (); + location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + location_t endloc = c_parser_peek_token (parser)->location; + add_debug_begin_stmt (endloc); + c_parser_consume_token (parser); + return endloc; + } + mark_valid_location_for_stdc_pragma (true); + if (c_parser_next_token_is_keyword (parser, RID_LABEL)) + { + /* Read zero or more forward-declarations for labels that nested + functions can jump to. */ + mark_valid_location_for_stdc_pragma (false); + while (c_parser_next_token_is_keyword (parser, RID_LABEL)) + { + label_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + /* Any identifiers, including those declared as type names, + are OK here. */ + while (true) + { + tree label; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + label + = declare_label (c_parser_peek_token (parser)->value); + C_DECLARED_LABEL_FLAG (label) = 1; + add_stmt (build_stmt (label_loc, DECL_EXPR, label)); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + pedwarn (label_loc, OPT_Wpedantic, "ISO C forbids label declarations"); + } + /* We must now have at least one statement, label or declaration. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); + c_parser_error (parser, "expected declaration or statement"); + location_t endloc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + return endloc; + } + while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) + { + location_t loc = c_parser_peek_token (parser)->location; + loc = expansion_point_location_if_in_system_header (loc); + /* Standard attributes may start a label, statement or declaration. */ + bool have_std_attrs + = c_parser_nth_token_starts_std_attributes (parser, 1); + tree std_attrs = NULL_TREE; + if (have_std_attrs) + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + if (c_parser_next_token_is_keyword (parser, RID_CASE) + || c_parser_next_token_is_keyword (parser, RID_DEFAULT) + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) + { + if (c_parser_next_token_is_keyword (parser, RID_CASE)) + label_loc = c_parser_peek_2nd_token (parser)->location; + else + label_loc = c_parser_peek_token (parser)->location; + last_label = true; + last_stmt = false; + mark_valid_location_for_stdc_pragma (false); + c_parser_label (parser, std_attrs); + } + else if (c_parser_next_tokens_start_declaration (parser) + || (have_std_attrs + && c_parser_next_token_is (parser, CPP_SEMICOLON))) + { + if (last_label) + pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "a label can only be part of a statement and " + "a declaration is not a statement"); + + mark_valid_location_for_stdc_pragma (false); + bool fallthru_attr_p = false; + c_parser_declaration_or_fndef (parser, true, !have_std_attrs, + true, true, true, NULL, + NULL, have_std_attrs, std_attrs, + NULL, &fallthru_attr_p); + + if (last_stmt && !fallthru_attr_p) + pedwarn_c90 (loc, OPT_Wdeclaration_after_statement, + "ISO C90 forbids mixed declarations and code"); + last_stmt = fallthru_attr_p; + last_label = false; + } + else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) + { + /* __extension__ can start a declaration, but is also an + unary operator that can start an expression. Consume all + but the last of a possible series of __extension__ to + determine which. If standard attributes have already + been seen, it must start a statement, not a declaration, + but standard attributes starting a declaration may appear + after __extension__. */ + while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD + && (c_parser_peek_2nd_token (parser)->keyword + == RID_EXTENSION)) + c_parser_consume_token (parser); + if (!have_std_attrs + && (c_token_starts_declaration (c_parser_peek_2nd_token (parser)) + || c_parser_nth_token_starts_std_attributes (parser, 2))) + { + int ext; + ext = disable_extension_diagnostics (); + c_parser_consume_token (parser); + last_label = false; + mark_valid_location_for_stdc_pragma (false); + c_parser_declaration_or_fndef (parser, true, true, true, true, + true); + /* Following the old parser, __extension__ does not + disable this diagnostic. */ + restore_extension_diagnostics (ext); + if (last_stmt) + pedwarn_c90 (loc, OPT_Wdeclaration_after_statement, + "ISO C90 forbids mixed declarations and code"); + last_stmt = false; + } + else + goto statement; + } + else if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + if (have_std_attrs) + c_parser_error (parser, "expected declaration or statement"); + /* External pragmas, and some omp pragmas, are not associated + with regular c code, and so are not to be considered statements + syntactically. This ensures that the user doesn't put them + places that would turn into syntax errors if the directive + were ignored. */ + if (c_parser_pragma (parser, + last_label ? pragma_stmt : pragma_compound, + NULL)) + last_label = false, last_stmt = true; + } + else if (c_parser_next_token_is (parser, CPP_EOF)) + { + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); + c_parser_error (parser, "expected declaration or statement"); + return c_parser_peek_token (parser)->location; + } + else if (c_parser_next_token_is_keyword (parser, RID_ELSE)) + { + if (parser->in_if_block) + { + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); + error_at (loc, "expected %<}%> before %"); + return c_parser_peek_token (parser)->location; + } + else + { + error_at (loc, "% without a previous %"); + c_parser_consume_token (parser); + continue; + } + } + else + { + statement: + c_warn_unused_attributes (std_attrs); + last_label = false; + last_stmt = true; + mark_valid_location_for_stdc_pragma (false); + c_parser_statement_after_labels (parser, NULL); + } + + parser->error = false; + } + if (last_label) + pedwarn_c11 (label_loc, OPT_Wpedantic, "label at end of compound statement"); + location_t endloc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + /* Restore the value we started with. */ + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); + return endloc; +} + +/* Parse all consecutive labels, possibly preceded by standard + attributes. In this context, a statement is required, not a + declaration, so attributes must be followed by a statement that is + not just a semicolon. */ + +static void +c_parser_all_labels (c_parser *parser) +{ + tree std_attrs = NULL; + if (c_parser_nth_token_starts_std_attributes (parser, 1)) + { + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_error (parser, "expected statement"); + } + while (c_parser_next_token_is_keyword (parser, RID_CASE) + || c_parser_next_token_is_keyword (parser, RID_DEFAULT) + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) + { + c_parser_label (parser, std_attrs); + std_attrs = NULL; + if (c_parser_nth_token_starts_std_attributes (parser, 1)) + { + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_error (parser, "expected statement"); + } + } + if (std_attrs) + c_warn_unused_attributes (std_attrs); +} + +/* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1). + + label: + identifier : gnu-attributes[opt] + case constant-expression : + default : + + GNU extensions: + + label: + case constant-expression ... constant-expression : + + The use of gnu-attributes on labels is a GNU extension. The syntax in + GNU C accepts any expressions without commas, non-constant + expressions being rejected later. Any standard + attribute-specifier-sequence before the first label has been parsed + in the caller, to distinguish statements from declarations. Any + attribute-specifier-sequence after the label is parsed in this + function. */ +static void +c_parser_label (c_parser *parser, tree std_attrs) +{ + location_t loc1 = c_parser_peek_token (parser)->location; + tree label = NULL_TREE; + + /* Remember whether this case or a user-defined label is allowed to fall + through to. */ + bool fallthrough_p = c_parser_peek_token (parser)->flags & PREV_FALLTHROUGH; + + if (c_parser_next_token_is_keyword (parser, RID_CASE)) + { + tree exp1, exp2; + c_parser_consume_token (parser); + exp1 = c_parser_expr_no_commas (parser, NULL).value; + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + label = do_case (loc1, exp1, NULL_TREE); + } + else if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + c_parser_consume_token (parser); + exp2 = c_parser_expr_no_commas (parser, NULL).value; + if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) + label = do_case (loc1, exp1, exp2); + } + else + c_parser_error (parser, "expected %<:%> or %<...%>"); + } + else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) + { + c_parser_consume_token (parser); + if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) + label = do_case (loc1, NULL_TREE, NULL_TREE); + } + else + { + tree name = c_parser_peek_token (parser)->value; + tree tlab; + tree attrs; + location_t loc2 = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is (parser, CPP_NAME)); + c_parser_consume_token (parser); + gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); + c_parser_consume_token (parser); + attrs = c_parser_gnu_attributes (parser); + tlab = define_label (loc2, name); + if (tlab) + { + decl_attributes (&tlab, attrs, 0); + decl_attributes (&tlab, std_attrs, 0); + label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab)); + } + if (attrs + && c_parser_next_tokens_start_declaration (parser)) + warning_at (loc2, OPT_Wattributes, "GNU-style attribute between" + " label and declaration appertains to the label"); + } + if (label) + { + if (TREE_CODE (label) == LABEL_EXPR) + FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p; + else + FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p; + } +} + +/* Parse a statement (C90 6.6, C99 6.8, C11 6.8). + + statement: + labeled-statement + attribute-specifier-sequence[opt] compound-statement + expression-statement + attribute-specifier-sequence[opt] selection-statement + attribute-specifier-sequence[opt] iteration-statement + attribute-specifier-sequence[opt] jump-statement + + labeled-statement: + attribute-specifier-sequence[opt] label statement + + expression-statement: + expression[opt] ; + attribute-specifier-sequence expression ; + + selection-statement: + if-statement + switch-statement + + iteration-statement: + while-statement + do-statement + for-statement + + jump-statement: + goto identifier ; + continue ; + break ; + return expression[opt] ; + + GNU extensions: + + statement: + attribute-specifier-sequence[opt] asm-statement + + jump-statement: + goto * expression ; + + expression-statement: + gnu-attributes ; + + Objective-C: + + statement: + attribute-specifier-sequence[opt] objc-throw-statement + attribute-specifier-sequence[opt] objc-try-catch-statement + attribute-specifier-sequence[opt] objc-synchronized-statement + + objc-throw-statement: + @throw expression ; + @throw ; + + OpenACC: + + statement: + attribute-specifier-sequence[opt] openacc-construct + + openacc-construct: + parallel-construct + kernels-construct + data-construct + loop-construct + + parallel-construct: + parallel-directive structured-block + + kernels-construct: + kernels-directive structured-block + + data-construct: + data-directive structured-block + + loop-construct: + loop-directive structured-block + + OpenMP: + + statement: + attribute-specifier-sequence[opt] openmp-construct + + openmp-construct: + parallel-construct + for-construct + simd-construct + for-simd-construct + sections-construct + single-construct + parallel-for-construct + parallel-for-simd-construct + parallel-sections-construct + master-construct + critical-construct + atomic-construct + ordered-construct + + parallel-construct: + parallel-directive structured-block + + for-construct: + for-directive iteration-statement + + simd-construct: + simd-directive iteration-statements + + for-simd-construct: + for-simd-directive iteration-statements + + sections-construct: + sections-directive section-scope + + single-construct: + single-directive structured-block + + parallel-for-construct: + parallel-for-directive iteration-statement + + parallel-for-simd-construct: + parallel-for-simd-directive iteration-statement + + parallel-sections-construct: + parallel-sections-directive section-scope + + master-construct: + master-directive structured-block + + critical-construct: + critical-directive structured-block + + atomic-construct: + atomic-directive expression-statement + + ordered-construct: + ordered-directive structured-block + + Transactional Memory: + + statement: + attribute-specifier-sequence[opt] transaction-statement + attribute-specifier-sequence[opt] transaction-cancel-statement + + IF_P is used to track whether there's a (possibly labeled) if statement + which is not enclosed in braces and has an else clause. This is used to + implement -Wparentheses. */ + +static void +c_parser_statement (c_parser *parser, bool *if_p, location_t *loc_after_labels) +{ + c_parser_all_labels (parser); + if (loc_after_labels) + *loc_after_labels = c_parser_peek_token (parser)->location; + c_parser_statement_after_labels (parser, if_p, NULL); +} + +/* Parse a statement, other than a labeled statement. CHAIN is a vector + of if-else-if conditions. All labels and standard attributes have + been parsed in the caller. + + IF_P is used to track whether there's a (possibly labeled) if statement + which is not enclosed in braces and has an else clause. This is used to + implement -Wparentheses. */ + +static void +c_parser_statement_after_labels (c_parser *parser, bool *if_p, + vec *chain) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree stmt = NULL_TREE; + bool in_if_block = parser->in_if_block; + parser->in_if_block = false; + if (if_p != NULL) + *if_p = false; + + if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE) + add_debug_begin_stmt (loc); + + restart: + switch (c_parser_peek_token (parser)->type) + { + case CPP_OPEN_BRACE: + add_stmt (c_parser_compound_statement (parser)); + break; + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_IF: + c_parser_if_statement (parser, if_p, chain); + break; + case RID_SWITCH: + c_parser_switch_statement (parser, if_p); + break; + case RID_WHILE: + c_parser_while_statement (parser, false, 0, if_p); + break; + case RID_DO: + c_parser_do_statement (parser, false, 0); + break; + case RID_FOR: + c_parser_for_statement (parser, false, 0, if_p); + break; + case RID_GOTO: + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + stmt = c_finish_goto_label (loc, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is (parser, CPP_MULT)) + { + struct c_expr val; + + c_parser_consume_token (parser); + val = c_parser_expression (parser); + val = convert_lvalue_to_rvalue (loc, val, false, true); + stmt = c_finish_goto_ptr (loc, val); + } + else + c_parser_error (parser, "expected identifier or %<*%>"); + goto expect_semicolon; + case RID_CONTINUE: + c_parser_consume_token (parser); + stmt = c_finish_bc_stmt (loc, objc_foreach_continue_label, false); + goto expect_semicolon; + case RID_BREAK: + c_parser_consume_token (parser); + stmt = c_finish_bc_stmt (loc, objc_foreach_break_label, true); + goto expect_semicolon; + case RID_RETURN: + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + stmt = c_finish_return (loc, NULL_TREE, NULL_TREE); + c_parser_consume_token (parser); + } + else + { + location_t xloc = c_parser_peek_token (parser)->location; + struct c_expr expr = c_parser_expression_conv (parser); + mark_exp_read (expr.value); + stmt = c_finish_return (EXPR_LOC_OR_LOC (expr.value, xloc), + expr.value, expr.original_type); + goto expect_semicolon; + } + break; + case RID_ASM: + stmt = c_parser_asm_statement (parser); + break; + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + stmt = c_parser_transaction (parser, + c_parser_peek_token (parser)->keyword); + break; + case RID_TRANSACTION_CANCEL: + stmt = c_parser_transaction_cancel (parser); + goto expect_semicolon; + case RID_AT_THROW: + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + stmt = objc_build_throw_stmt (loc, NULL_TREE); + c_parser_consume_token (parser); + } + else + { + struct c_expr expr = c_parser_expression (parser); + expr = convert_lvalue_to_rvalue (loc, expr, false, false); + expr.value = c_fully_fold (expr.value, false, NULL); + stmt = objc_build_throw_stmt (loc, expr.value); + goto expect_semicolon; + } + break; + case RID_AT_TRY: + gcc_assert (c_dialect_objc ()); + c_parser_objc_try_catch_finally_statement (parser); + break; + case RID_AT_SYNCHRONIZED: + gcc_assert (c_dialect_objc ()); + c_parser_objc_synchronized_statement (parser); + break; + case RID_ATTRIBUTE: + { + /* Allow '__attribute__((fallthrough));'. */ + tree attrs = c_parser_gnu_attributes (parser); + if (attribute_fallthrough_p (attrs)) + { + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + tree fn = build_call_expr_internal_loc (loc, + IFN_FALLTHROUGH, + void_type_node, 0); + add_stmt (fn); + /* Eat the ';'. */ + c_parser_consume_token (parser); + } + else + warning_at (loc, OPT_Wattributes, + "% attribute not followed " + "by %<;%>"); + } + else if (attrs != NULL_TREE) + warning_at (loc, OPT_Wattributes, "only attribute %" + " can be applied to a null statement"); + break; + } + default: + goto expr_stmt; + } + break; + case CPP_SEMICOLON: + c_parser_consume_token (parser); + break; + case CPP_CLOSE_PAREN: + case CPP_CLOSE_SQUARE: + /* Avoid infinite loop in error recovery: + c_parser_skip_until_found stops at a closing nesting + delimiter without consuming it, but here we need to consume + it to proceed further. */ + c_parser_error (parser, "expected statement"); + c_parser_consume_token (parser); + break; + case CPP_PRAGMA: + if (!c_parser_pragma (parser, pragma_stmt, if_p)) + goto restart; + break; + default: + expr_stmt: + stmt = c_finish_expr_stmt (loc, c_parser_expression_conv (parser).value); + expect_semicolon: + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + break; + } + /* Two cases cannot and do not have line numbers associated: If stmt + is degenerate, such as "2;", then stmt is an INTEGER_CST, which + cannot hold line numbers. But that's OK because the statement + will either be changed to a MODIFY_EXPR during gimplification of + the statement expr, or discarded. If stmt was compound, but + without new variables, we will have skipped the creation of a + BIND and will have a bare STATEMENT_LIST. But that's OK because + (recursively) all of the component statements should already have + line numbers assigned. ??? Can we discard no-op statements + earlier? */ + if (EXPR_LOCATION (stmt) == UNKNOWN_LOCATION) + protected_set_expr_location (stmt, loc); + + parser->in_if_block = in_if_block; +} + +/* Parse the condition from an if, do, while or for statements. */ + +static tree +c_parser_condition (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree cond; + cond = c_parser_expression_conv (parser).value; + cond = c_objc_common_truthvalue_conversion (loc, cond); + cond = c_fully_fold (cond, false, NULL); + if (warn_sequence_point) + verify_sequence_points (cond); + return cond; +} + +/* Parse a parenthesized condition from an if, do or while statement. + + condition: + ( expression ) +*/ +static tree +c_parser_paren_condition (c_parser *parser) +{ + tree cond; + matching_parens parens; + if (!parens.require_open (parser)) + return error_mark_node; + cond = c_parser_condition (parser); + parens.skip_until_found_close (parser); + return cond; +} + +/* Parse a statement which is a block in C99. + + IF_P is used to track whether there's a (possibly labeled) if statement + which is not enclosed in braces and has an else clause. This is used to + implement -Wparentheses. */ + +static tree +c_parser_c99_block_statement (c_parser *parser, bool *if_p, + location_t *loc_after_labels) +{ + tree block = c_begin_compound_stmt (flag_isoc99); + location_t loc = c_parser_peek_token (parser)->location; + c_parser_statement (parser, if_p, loc_after_labels); + return c_end_compound_stmt (loc, block, flag_isoc99); +} + +/* Parse the body of an if statement. This is just parsing a + statement but (a) it is a block in C99, (b) we track whether the + body is an if statement for the sake of -Wparentheses warnings, (c) + we handle an empty body specially for the sake of -Wempty-body + warnings, and (d) we call parser_compound_statement directly + because c_parser_statement_after_labels resets + parser->in_if_block. + + IF_P is used to track whether there's a (possibly labeled) if statement + which is not enclosed in braces and has an else clause. This is used to + implement -Wparentheses. */ + +static tree +c_parser_if_body (c_parser *parser, bool *if_p, + const token_indent_info &if_tinfo) +{ + tree block = c_begin_compound_stmt (flag_isoc99); + location_t body_loc = c_parser_peek_token (parser)->location; + location_t body_loc_after_labels = UNKNOWN_LOCATION; + token_indent_info body_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + + c_parser_all_labels (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + location_t loc = c_parser_peek_token (parser)->location; + add_stmt (build_empty_stmt (loc)); + c_parser_consume_token (parser); + if (!c_parser_next_token_is_keyword (parser, RID_ELSE)) + warning_at (loc, OPT_Wempty_body, + "suggest braces around empty body in an % statement"); + } + else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + add_stmt (c_parser_compound_statement (parser)); + else + { + body_loc_after_labels = c_parser_peek_token (parser)->location; + c_parser_statement_after_labels (parser, if_p); + } + + token_indent_info next_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + warn_for_misleading_indentation (if_tinfo, body_tinfo, next_tinfo); + if (body_loc_after_labels != UNKNOWN_LOCATION + && next_tinfo.type != CPP_SEMICOLON) + warn_for_multistatement_macros (body_loc_after_labels, next_tinfo.location, + if_tinfo.location, RID_IF); + + return c_end_compound_stmt (body_loc, block, flag_isoc99); +} + +/* Parse the else body of an if statement. This is just parsing a + statement but (a) it is a block in C99, (b) we handle an empty body + specially for the sake of -Wempty-body warnings. CHAIN is a vector + of if-else-if conditions. */ + +static tree +c_parser_else_body (c_parser *parser, const token_indent_info &else_tinfo, + vec *chain) +{ + location_t body_loc = c_parser_peek_token (parser)->location; + tree block = c_begin_compound_stmt (flag_isoc99); + token_indent_info body_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + location_t body_loc_after_labels = UNKNOWN_LOCATION; + + c_parser_all_labels (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + location_t loc = c_parser_peek_token (parser)->location; + warning_at (loc, + OPT_Wempty_body, + "suggest braces around empty body in an % statement"); + add_stmt (build_empty_stmt (loc)); + c_parser_consume_token (parser); + } + else + { + if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + body_loc_after_labels = c_parser_peek_token (parser)->location; + c_parser_statement_after_labels (parser, NULL, chain); + } + + token_indent_info next_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + warn_for_misleading_indentation (else_tinfo, body_tinfo, next_tinfo); + if (body_loc_after_labels != UNKNOWN_LOCATION + && next_tinfo.type != CPP_SEMICOLON) + warn_for_multistatement_macros (body_loc_after_labels, next_tinfo.location, + else_tinfo.location, RID_ELSE); + + return c_end_compound_stmt (body_loc, block, flag_isoc99); +} + +/* We might need to reclassify any previously-lexed identifier, e.g. + when we've left a for loop with an if-statement without else in the + body - we might have used a wrong scope for the token. See PR67784. */ + +static void +c_parser_maybe_reclassify_token (c_parser *parser) +{ + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *token = c_parser_peek_token (parser); + + if (token->id_kind != C_ID_CLASSNAME) + { + tree decl = lookup_name (token->value); + + token->id_kind = C_ID_ID; + if (decl) + { + if (TREE_CODE (decl) == TYPE_DECL) + token->id_kind = C_ID_TYPENAME; + } + else if (c_dialect_objc ()) + { + tree objc_interface_decl = objc_is_class_name (token->value); + /* Objective-C class names are in the same namespace as + variables and typedefs, and hence are shadowed by local + declarations. */ + if (objc_interface_decl) + { + token->value = objc_interface_decl; + token->id_kind = C_ID_CLASSNAME; + } + } + } + } +} + +/* Parse an if statement (C90 6.6.4, C99 6.8.4, C11 6.8.4). + + if-statement: + if ( expression ) statement + if ( expression ) statement else statement + + CHAIN is a vector of if-else-if conditions. + IF_P is used to track whether there's a (possibly labeled) if statement + which is not enclosed in braces and has an else clause. This is used to + implement -Wparentheses. */ + +static void +c_parser_if_statement (c_parser *parser, bool *if_p, vec *chain) +{ + tree block; + location_t loc; + tree cond; + bool nested_if = false; + tree first_body, second_body; + bool in_if_block; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF)); + token_indent_info if_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + c_parser_consume_token (parser); + block = c_begin_compound_stmt (flag_isoc99); + loc = c_parser_peek_token (parser)->location; + cond = c_parser_paren_condition (parser); + in_if_block = parser->in_if_block; + parser->in_if_block = true; + first_body = c_parser_if_body (parser, &nested_if, if_tinfo); + parser->in_if_block = in_if_block; + + if (warn_duplicated_cond) + warn_duplicated_cond_add_or_warn (EXPR_LOCATION (cond), cond, &chain); + + if (c_parser_next_token_is_keyword (parser, RID_ELSE)) + { + token_indent_info else_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + c_parser_consume_token (parser); + if (warn_duplicated_cond) + { + if (c_parser_next_token_is_keyword (parser, RID_IF) + && chain == NULL) + { + /* We've got "if (COND) else if (COND2)". Start the + condition chain and add COND as the first element. */ + chain = new vec (); + if (!CONSTANT_CLASS_P (cond) && !TREE_SIDE_EFFECTS (cond)) + chain->safe_push (cond); + } + else if (!c_parser_next_token_is_keyword (parser, RID_IF)) + /* This is if-else without subsequent if. Zap the condition + chain; we would have already warned at this point. */ + vec_free (chain); + } + second_body = c_parser_else_body (parser, else_tinfo, chain); + /* Set IF_P to true to indicate that this if statement has an + else clause. This may trigger the Wparentheses warning + below when we get back up to the parent if statement. */ + if (if_p != NULL) + *if_p = true; + } + else + { + second_body = NULL_TREE; + + /* Diagnose an ambiguous else if if-then-else is nested inside + if-then. */ + if (nested_if) + warning_at (loc, OPT_Wdangling_else, + "suggest explicit braces to avoid ambiguous %"); + + if (warn_duplicated_cond) + /* This if statement does not have an else clause. We don't + need the condition chain anymore. */ + vec_free (chain); + } + c_finish_if_stmt (loc, cond, first_body, second_body); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); + + c_parser_maybe_reclassify_token (parser); +} + +/* Parse a switch statement (C90 6.6.4, C99 6.8.4, C11 6.8.4). + + switch-statement: + switch (expression) statement +*/ + +static void +c_parser_switch_statement (c_parser *parser, bool *if_p) +{ + struct c_expr ce; + tree block, expr, body; + unsigned char save_in_statement; + location_t switch_loc = c_parser_peek_token (parser)->location; + location_t switch_cond_loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH)); + c_parser_consume_token (parser); + block = c_begin_compound_stmt (flag_isoc99); + bool explicit_cast_p = false; + matching_parens parens; + if (parens.require_open (parser)) + { + switch_cond_loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + explicit_cast_p = true; + ce = c_parser_expression (parser); + ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, true); + expr = ce.value; + /* ??? expr has no valid location? */ + parens.skip_until_found_close (parser); + } + else + { + switch_cond_loc = UNKNOWN_LOCATION; + expr = error_mark_node; + ce.original_type = error_mark_node; + } + c_start_switch (switch_loc, switch_cond_loc, expr, explicit_cast_p); + save_in_statement = in_statement; + in_statement |= IN_SWITCH_STMT; + location_t loc_after_labels; + bool open_brace_p = c_parser_peek_token (parser)->type == CPP_OPEN_BRACE; + body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels); + location_t next_loc = c_parser_peek_token (parser)->location; + if (!open_brace_p && c_parser_peek_token (parser)->type != CPP_SEMICOLON) + warn_for_multistatement_macros (loc_after_labels, next_loc, switch_loc, + RID_SWITCH); + c_finish_switch (body, ce.original_type); + in_statement = save_in_statement; + add_stmt (c_end_compound_stmt (switch_loc, block, flag_isoc99)); + c_parser_maybe_reclassify_token (parser); +} + +/* Parse a while statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). + + while-statement: + while (expression) statement + + IF_P is used to track whether there's a (possibly labeled) if statement + which is not enclosed in braces and has an else clause. This is used to + implement -Wparentheses. */ + +static void +c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, + bool *if_p) +{ + tree block, cond, body; + unsigned char save_in_statement; + location_t loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE)); + token_indent_info while_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + c_parser_consume_token (parser); + block = c_begin_compound_stmt (flag_isoc99); + loc = c_parser_peek_token (parser)->location; + cond = c_parser_paren_condition (parser); + if (ivdep && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_ivdep_kind), + integer_zero_node); + if (unroll && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_unroll_kind), + build_int_cst (integer_type_node, unroll)); + save_in_statement = in_statement; + in_statement = IN_ITERATION_STMT; + + token_indent_info body_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + + location_t loc_after_labels; + bool open_brace = c_parser_next_token_is (parser, CPP_OPEN_BRACE); + body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels); + add_stmt (build_stmt (loc, WHILE_STMT, cond, body)); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); + c_parser_maybe_reclassify_token (parser); + + token_indent_info next_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + warn_for_misleading_indentation (while_tinfo, body_tinfo, next_tinfo); + + if (next_tinfo.type != CPP_SEMICOLON && !open_brace) + warn_for_multistatement_macros (loc_after_labels, next_tinfo.location, + while_tinfo.location, RID_WHILE); + + in_statement = save_in_statement; +} + +/* Parse a do statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). + + do-statement: + do statement while ( expression ) ; +*/ + +static void +c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll) +{ + tree block, cond, body; + unsigned char save_in_statement; + location_t loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO)); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + warning_at (c_parser_peek_token (parser)->location, + OPT_Wempty_body, + "suggest braces around empty body in % statement"); + block = c_begin_compound_stmt (flag_isoc99); + loc = c_parser_peek_token (parser)->location; + save_in_statement = in_statement; + in_statement = IN_ITERATION_STMT; + body = c_parser_c99_block_statement (parser, NULL); + c_parser_require_keyword (parser, RID_WHILE, "expected %"); + in_statement = save_in_statement; + cond = c_parser_paren_condition (parser); + if (ivdep && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_ivdep_kind), + integer_zero_node); + if (unroll && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_unroll_kind), + build_int_cst (integer_type_node, unroll)); + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + c_parser_skip_to_end_of_block_or_statement (parser); + + add_stmt (build_stmt (loc, DO_STMT, cond, body)); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); +} + +/* Parse a for statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). + + for-statement: + for ( expression[opt] ; expression[opt] ; expression[opt] ) statement + for ( nested-declaration expression[opt] ; expression[opt] ) statement + + The form with a declaration is new in C99. + + ??? In accordance with the old parser, the declaration may be a + nested function, which is then rejected in check_for_loop_decls, + but does it make any sense for this to be included in the grammar? + Note in particular that the nested function does not include a + trailing ';', whereas the "declaration" production includes one. + Also, can we reject bad declarations earlier and cheaper than + check_for_loop_decls? + + In Objective-C, there are two additional variants: + + foreach-statement: + for ( expression in expresssion ) statement + for ( declaration in expression ) statement + + This is inconsistent with C, because the second variant is allowed + even if c99 is not enabled. + + The rest of the comment documents these Objective-C foreach-statement. + + Here is the canonical example of the first variant: + for (object in array) { do something with object } + we call the first expression ("object") the "object_expression" and + the second expression ("array") the "collection_expression". + object_expression must be an lvalue of type "id" (a generic Objective-C + object) because the loop works by assigning to object_expression the + various objects from the collection_expression. collection_expression + must evaluate to something of type "id" which responds to the method + countByEnumeratingWithState:objects:count:. + + The canonical example of the second variant is: + for (id object in array) { do something with object } + which is completely equivalent to + { + id object; + for (object in array) { do something with object } + } + Note that initizializing 'object' in some way (eg, "for ((object = + xxx) in array) { do something with object }") is possibly + technically valid, but completely pointless as 'object' will be + assigned to something else as soon as the loop starts. We should + most likely reject it (TODO). + + The beginning of the Objective-C foreach-statement looks exactly + like the beginning of the for-statement, and we can tell it is a + foreach-statement only because the initial declaration or + expression is terminated by 'in' instead of ';'. + + IF_P is used to track whether there's a (possibly labeled) if statement + which is not enclosed in braces and has an else clause. This is used to + implement -Wparentheses. */ + +static void +c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, + bool *if_p) +{ + tree block, cond, incr, body; + unsigned char save_in_statement; + tree save_objc_foreach_break_label, save_objc_foreach_continue_label; + /* The following are only used when parsing an ObjC foreach statement. */ + tree object_expression; + /* Silence the bogus uninitialized warning. */ + tree collection_expression = NULL; + location_t loc = c_parser_peek_token (parser)->location; + location_t for_loc = loc; + bool is_foreach_statement = false; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); + token_indent_info for_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + c_parser_consume_token (parser); + /* Open a compound statement in Objective-C as well, just in case this is + as foreach expression. */ + block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ()); + cond = error_mark_node; + incr = error_mark_node; + matching_parens parens; + if (parens.require_open (parser)) + { + /* Parse the initialization declaration or expression. */ + object_expression = error_mark_node; + parser->objc_could_be_foreach_context = c_dialect_objc (); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + parser->objc_could_be_foreach_context = false; + c_parser_consume_token (parser); + c_finish_expr_stmt (loc, NULL_TREE); + } + else if (c_parser_next_tokens_start_declaration (parser) + || c_parser_nth_token_starts_std_attributes (parser, 1)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + &object_expression); + parser->objc_could_be_foreach_context = false; + + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + c_parser_consume_token (parser); + is_foreach_statement = true; + if (check_for_loop_decls (for_loc, true) == NULL_TREE) + c_parser_error (parser, "multiple iterating variables in " + "fast enumeration"); + } + else + check_for_loop_decls (for_loc, flag_isoc99); + } + else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) + { + /* __extension__ can start a declaration, but is also an + unary operator that can start an expression. Consume all + but the last of a possible series of __extension__ to + determine which. */ + while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD + && (c_parser_peek_2nd_token (parser)->keyword + == RID_EXTENSION)) + c_parser_consume_token (parser); + if (c_token_starts_declaration (c_parser_peek_2nd_token (parser)) + || c_parser_nth_token_starts_std_attributes (parser, 2)) + { + int ext; + ext = disable_extension_diagnostics (); + c_parser_consume_token (parser); + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, &object_expression); + parser->objc_could_be_foreach_context = false; + + restore_extension_diagnostics (ext); + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + c_parser_consume_token (parser); + is_foreach_statement = true; + if (check_for_loop_decls (for_loc, true) == NULL_TREE) + c_parser_error (parser, "multiple iterating variables in " + "fast enumeration"); + } + else + check_for_loop_decls (for_loc, flag_isoc99); + } + else + goto init_expr; + } + else + { + init_expr: + { + struct c_expr ce; + tree init_expression; + ce = c_parser_expression (parser); + init_expression = ce.value; + parser->objc_could_be_foreach_context = false; + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + c_parser_consume_token (parser); + is_foreach_statement = true; + if (! lvalue_p (init_expression)) + c_parser_error (parser, "invalid iterating variable in " + "fast enumeration"); + object_expression + = c_fully_fold (init_expression, false, NULL); + } + else + { + ce = convert_lvalue_to_rvalue (loc, ce, true, false); + init_expression = ce.value; + c_finish_expr_stmt (loc, init_expression); + c_parser_skip_until_found (parser, CPP_SEMICOLON, + "expected %<;%>"); + } + } + } + /* Parse the loop condition. In the case of a foreach + statement, there is no loop condition. */ + gcc_assert (!parser->objc_could_be_foreach_context); + if (!is_foreach_statement) + { + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + if (ivdep) + { + c_parser_error (parser, "missing loop condition in loop " + "with % pragma"); + cond = error_mark_node; + } + else if (unroll) + { + c_parser_error (parser, "missing loop condition in loop " + "with % pragma"); + cond = error_mark_node; + } + else + { + c_parser_consume_token (parser); + cond = NULL_TREE; + } + } + else + { + cond = c_parser_condition (parser); + c_parser_skip_until_found (parser, CPP_SEMICOLON, + "expected %<;%>"); + } + if (ivdep && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_ivdep_kind), + integer_zero_node); + if (unroll && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_unroll_kind), + build_int_cst (integer_type_node, unroll)); + } + /* Parse the increment expression (the third expression in a + for-statement). In the case of a foreach-statement, this is + the expression that follows the 'in'. */ + loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + if (is_foreach_statement) + { + c_parser_error (parser, + "missing collection in fast enumeration"); + collection_expression = error_mark_node; + } + else + incr = c_process_expr_stmt (loc, NULL_TREE); + } + else + { + if (is_foreach_statement) + collection_expression + = c_fully_fold (c_parser_expression (parser).value, false, NULL); + else + { + struct c_expr ce = c_parser_expression (parser); + ce = convert_lvalue_to_rvalue (loc, ce, true, false); + incr = c_process_expr_stmt (loc, ce.value); + } + } + parens.skip_until_found_close (parser); + } + save_in_statement = in_statement; + if (is_foreach_statement) + { + in_statement = IN_OBJC_FOREACH; + save_objc_foreach_break_label = objc_foreach_break_label; + save_objc_foreach_continue_label = objc_foreach_continue_label; + objc_foreach_break_label = create_artificial_label (loc); + objc_foreach_continue_label = create_artificial_label (loc); + } + else + in_statement = IN_ITERATION_STMT; + + token_indent_info body_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + + location_t loc_after_labels; + bool open_brace = c_parser_next_token_is (parser, CPP_OPEN_BRACE); + body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels); + + if (is_foreach_statement) + objc_finish_foreach_loop (for_loc, object_expression, + collection_expression, body, + objc_foreach_break_label, + objc_foreach_continue_label); + else + add_stmt (build_stmt (for_loc, FOR_STMT, NULL_TREE, cond, incr, + body, NULL_TREE)); + add_stmt (c_end_compound_stmt (for_loc, block, + flag_isoc99 || c_dialect_objc ())); + c_parser_maybe_reclassify_token (parser); + + token_indent_info next_tinfo + = get_token_indent_info (c_parser_peek_token (parser)); + warn_for_misleading_indentation (for_tinfo, body_tinfo, next_tinfo); + + if (next_tinfo.type != CPP_SEMICOLON && !open_brace) + warn_for_multistatement_macros (loc_after_labels, next_tinfo.location, + for_tinfo.location, RID_FOR); + + in_statement = save_in_statement; + if (is_foreach_statement) + { + objc_foreach_break_label = save_objc_foreach_break_label; + objc_foreach_continue_label = save_objc_foreach_continue_label; + } +} + +/* Parse an asm statement, a GNU extension. This is a full-blown asm + statement with inputs, outputs, clobbers, and volatile, inline, and goto + tags allowed. + + asm-qualifier: + volatile + inline + goto + + asm-qualifier-list: + asm-qualifier-list asm-qualifier + asm-qualifier + + asm-statement: + asm asm-qualifier-list[opt] ( asm-argument ) ; + + asm-argument: + asm-string-literal + asm-string-literal : asm-operands[opt] + asm-string-literal : asm-operands[opt] : asm-operands[opt] + asm-string-literal : asm-operands[opt] : asm-operands[opt] \ + : asm-clobbers[opt] + asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \ + : asm-goto-operands + + The form with asm-goto-operands is valid if and only if the + asm-qualifier-list contains goto, and is the only allowed form in that case. + Duplicate asm-qualifiers are not allowed. + + The :: token is considered equivalent to two consecutive : tokens. */ + +static tree +c_parser_asm_statement (c_parser *parser) +{ + tree str, outputs, inputs, clobbers, labels, ret; + bool simple; + location_t asm_loc = c_parser_peek_token (parser)->location; + int section, nsections; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); + c_parser_consume_token (parser); + + /* Handle the asm-qualifier-list. */ + location_t volatile_loc = UNKNOWN_LOCATION; + location_t inline_loc = UNKNOWN_LOCATION; + location_t goto_loc = UNKNOWN_LOCATION; + for (;;) + { + c_token *token = c_parser_peek_token (parser); + location_t loc = token->location; + switch (token->keyword) + { + case RID_VOLATILE: + if (volatile_loc) + { + error_at (loc, "duplicate % qualifier %qE", token->value); + inform (volatile_loc, "first seen here"); + } + else + volatile_loc = loc; + c_parser_consume_token (parser); + continue; + + case RID_INLINE: + if (inline_loc) + { + error_at (loc, "duplicate % qualifier %qE", token->value); + inform (inline_loc, "first seen here"); + } + else + inline_loc = loc; + c_parser_consume_token (parser); + continue; + + case RID_GOTO: + if (goto_loc) + { + error_at (loc, "duplicate % qualifier %qE", token->value); + inform (goto_loc, "first seen here"); + } + else + goto_loc = loc; + c_parser_consume_token (parser); + continue; + + case RID_CONST: + case RID_RESTRICT: + error_at (loc, "%qE is not a valid % qualifier", token->value); + c_parser_consume_token (parser); + continue; + + default: + break; + } + break; + } + + bool is_volatile = (volatile_loc != UNKNOWN_LOCATION); + bool is_inline = (inline_loc != UNKNOWN_LOCATION); + bool is_goto = (goto_loc != UNKNOWN_LOCATION); + + ret = NULL; + + matching_parens parens; + if (!parens.require_open (parser)) + goto error; + + str = c_parser_asm_string_literal (parser); + if (str == NULL_TREE) + goto error_close_paren; + + simple = true; + outputs = NULL_TREE; + inputs = NULL_TREE; + clobbers = NULL_TREE; + labels = NULL_TREE; + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto) + goto done_asm; + + /* Parse each colon-delimited section of operands. */ + nsections = 3 + is_goto; + for (section = 0; section < nsections; ++section) + { + if (c_parser_next_token_is (parser, CPP_SCOPE)) + { + ++section; + if (section == nsections) + { + c_parser_error (parser, "expected %<)%>"); + goto error_close_paren; + } + c_parser_consume_token (parser); + } + else if (!c_parser_require (parser, CPP_COLON, + is_goto + ? G_("expected %<:%>") + : G_("expected %<:%> or %<)%>"), + UNKNOWN_LOCATION, is_goto)) + goto error_close_paren; + + /* Once past any colon, we're no longer a simple asm. */ + simple = false; + + if ((!c_parser_next_token_is (parser, CPP_COLON) + && !c_parser_next_token_is (parser, CPP_SCOPE) + && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + || section == 3) + switch (section) + { + case 0: + outputs = c_parser_asm_operands (parser); + break; + case 1: + inputs = c_parser_asm_operands (parser); + break; + case 2: + clobbers = c_parser_asm_clobbers (parser); + break; + case 3: + labels = c_parser_asm_goto_operands (parser); + break; + default: + gcc_unreachable (); + } + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto) + goto done_asm; + } + + done_asm: + if (!parens.require_close (parser)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + goto error; + } + + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + c_parser_skip_to_end_of_block_or_statement (parser); + + ret = build_asm_stmt (is_volatile, + build_asm_expr (asm_loc, str, outputs, inputs, + clobbers, labels, simple, is_inline)); + + error: + return ret; + + error_close_paren: + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + goto error; +} + +/* Parse asm operands, a GNU extension. + + asm-operands: + asm-operand + asm-operands , asm-operand + + asm-operand: + asm-string-literal ( expression ) + [ identifier ] asm-string-literal ( expression ) +*/ + +static tree +c_parser_asm_operands (c_parser *parser) +{ + tree list = NULL_TREE; + while (true) + { + tree name, str; + struct c_expr expr; + if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + name = build_string (IDENTIFIER_LENGTH (id), + IDENTIFIER_POINTER (id)); + } + else + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL); + return NULL_TREE; + } + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + } + else + name = NULL_TREE; + str = c_parser_asm_string_literal (parser); + if (str == NULL_TREE) + return NULL_TREE; + matching_parens parens; + if (!parens.require_open (parser)) + return NULL_TREE; + expr = c_parser_expression (parser); + mark_exp_read (expr.value); + if (!parens.require_close (parser)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return NULL_TREE; + } + list = chainon (list, build_tree_list (build_tree_list (name, str), + expr.value)); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + return list; +} + +/* Parse asm clobbers, a GNU extension. + + asm-clobbers: + asm-string-literal + asm-clobbers , asm-string-literal +*/ + +static tree +c_parser_asm_clobbers (c_parser *parser) +{ + tree list = NULL_TREE; + while (true) + { + tree str = c_parser_asm_string_literal (parser); + if (str) + list = tree_cons (NULL_TREE, str, list); + else + return NULL_TREE; + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + return list; +} + +/* Parse asm goto labels, a GNU extension. + + asm-goto-operands: + identifier + asm-goto-operands , identifier +*/ + +static tree +c_parser_asm_goto_operands (c_parser *parser) +{ + tree list = NULL_TREE; + while (true) + { + tree name, label; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *tok = c_parser_peek_token (parser); + name = tok->value; + label = lookup_label_for_goto (tok->location, name); + c_parser_consume_token (parser); + TREE_USED (label) = 1; + } + else + { + c_parser_error (parser, "expected identifier"); + return NULL_TREE; + } + + name = build_string (IDENTIFIER_LENGTH (name), + IDENTIFIER_POINTER (name)); + list = tree_cons (name, label, list); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + return nreverse (list); + } +} + +/* Parse a possibly concatenated sequence of string literals. + TRANSLATE says whether to translate them to the execution character + set; WIDE_OK says whether any kind of prefixed string literal is + permitted in this context. This code is based on that in + lex_string. */ + +struct c_expr +c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok) +{ + struct c_expr ret; + size_t count; + struct obstack str_ob; + struct obstack loc_ob; + cpp_string str, istr, *strs; + c_token *tok; + location_t loc, last_tok_loc; + enum cpp_ttype type; + tree value, string_tree; + + tok = c_parser_peek_token (parser); + loc = tok->location; + last_tok_loc = linemap_resolve_location (line_table, loc, + LRK_MACRO_DEFINITION_LOCATION, + NULL); + type = tok->type; + switch (type) + { + case CPP_STRING: + case CPP_WSTRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_UTF8STRING: + string_tree = tok->value; + break; + + default: + c_parser_error (parser, "expected string literal"); + ret.set_error (); + ret.value = NULL_TREE; + ret.original_code = ERROR_MARK; + ret.original_type = NULL_TREE; + return ret; + } + + /* Try to avoid the overhead of creating and destroying an obstack + for the common case of just one string. */ + switch (c_parser_peek_2nd_token (parser)->type) + { + default: + c_parser_consume_token (parser); + str.text = (const unsigned char *) TREE_STRING_POINTER (string_tree); + str.len = TREE_STRING_LENGTH (string_tree); + count = 1; + strs = &str; + break; + + case CPP_STRING: + case CPP_WSTRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_UTF8STRING: + gcc_obstack_init (&str_ob); + gcc_obstack_init (&loc_ob); + count = 0; + do + { + c_parser_consume_token (parser); + count++; + str.text = (const unsigned char *) TREE_STRING_POINTER (string_tree); + str.len = TREE_STRING_LENGTH (string_tree); + if (type != tok->type) + { + if (type == CPP_STRING) + type = tok->type; + else if (tok->type != CPP_STRING) + error ("unsupported non-standard concatenation " + "of string literals"); + } + obstack_grow (&str_ob, &str, sizeof (cpp_string)); + obstack_grow (&loc_ob, &last_tok_loc, sizeof (location_t)); + tok = c_parser_peek_token (parser); + string_tree = tok->value; + last_tok_loc + = linemap_resolve_location (line_table, tok->location, + LRK_MACRO_DEFINITION_LOCATION, NULL); + } + while (tok->type == CPP_STRING + || tok->type == CPP_WSTRING + || tok->type == CPP_STRING16 + || tok->type == CPP_STRING32 + || tok->type == CPP_UTF8STRING); + strs = (cpp_string *) obstack_finish (&str_ob); + } + + if (count > 1 && !in_system_header_at (input_location)) + warning (OPT_Wtraditional, + "traditional C rejects string constant concatenation"); + + if ((type == CPP_STRING || wide_ok) + && ((translate + ? cpp_interpret_string : cpp_interpret_string_notranslate) + (parse_in, strs, count, &istr, type))) + { + value = build_string (istr.len, (const char *) istr.text); + free (CONST_CAST (unsigned char *, istr.text)); + if (count > 1) + { + location_t *locs = (location_t *) obstack_finish (&loc_ob); + gcc_assert (g_string_concat_db); + g_string_concat_db->record_string_concatenation (count, locs); + } + } + else + { + if (type != CPP_STRING && !wide_ok) + { + error_at (loc, "a wide string is invalid in this context"); + type = CPP_STRING; + } + /* Callers cannot generally handle error_mark_node in this + context, so return the empty string instead. An error has + been issued, either above or from cpp_interpret_string. */ + switch (type) + { + default: + case CPP_STRING: + case CPP_UTF8STRING: + value = build_string (1, ""); + break; + case CPP_STRING16: + value = build_string (TYPE_PRECISION (char16_type_node) + / TYPE_PRECISION (char_type_node), + "\0"); /* char16_t is 16 bits */ + break; + case CPP_STRING32: + value = build_string (TYPE_PRECISION (char32_type_node) + / TYPE_PRECISION (char_type_node), + "\0\0\0"); /* char32_t is 32 bits */ + break; + case CPP_WSTRING: + value = build_string (TYPE_PRECISION (wchar_type_node) + / TYPE_PRECISION (char_type_node), + "\0\0\0"); /* widest supported wchar_t + is 32 bits */ + break; + } + } + + switch (type) + { + default: + case CPP_STRING: + case CPP_UTF8STRING: + TREE_TYPE (value) = char_array_type_node; + break; + case CPP_STRING16: + TREE_TYPE (value) = char16_array_type_node; + break; + case CPP_STRING32: + TREE_TYPE (value) = char32_array_type_node; + break; + case CPP_WSTRING: + TREE_TYPE (value) = wchar_array_type_node; + } + value = fix_string_type (value); + + if (count > 1) + { + obstack_free (&str_ob, 0); + obstack_free (&loc_ob, 0); + } + + ret.value = value; + ret.original_code = STRING_CST; + ret.original_type = NULL_TREE; + set_c_expr_source_range (&ret, get_range_from_loc (line_table, loc)); + parser->seen_string_literal = true; + return ret; +} + +/* Parse an expression other than a compound expression; that is, an + assignment expression (C90 6.3.16, C99 6.5.16, C11 6.5.16). If + AFTER is not NULL then it is an Objective-C message expression which + is the primary-expression starting the expression as an initializer. + + assignment-expression: + conditional-expression + unary-expression assignment-operator assignment-expression + + assignment-operator: one of + = *= /= %= += -= <<= >>= &= ^= |= + + In GNU C we accept any conditional expression on the LHS and + diagnose the invalid lvalue rather than producing a syntax + error. */ + +static struct c_expr +c_parser_expr_no_commas (c_parser *parser, struct c_expr *after, + tree omp_atomic_lhs) +{ + struct c_expr lhs, rhs, ret; + enum tree_code code; + location_t op_location, exp_location; + bool save_in_omp_for = c_in_omp_for; + c_in_omp_for = false; + gcc_assert (!after || c_dialect_objc ()); + lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs); + op_location = c_parser_peek_token (parser)->location; + switch (c_parser_peek_token (parser)->type) + { + case CPP_EQ: + code = NOP_EXPR; + break; + case CPP_MULT_EQ: + code = MULT_EXPR; + break; + case CPP_DIV_EQ: + code = TRUNC_DIV_EXPR; + break; + case CPP_MOD_EQ: + code = TRUNC_MOD_EXPR; + break; + case CPP_PLUS_EQ: + code = PLUS_EXPR; + break; + case CPP_MINUS_EQ: + code = MINUS_EXPR; + break; + case CPP_LSHIFT_EQ: + code = LSHIFT_EXPR; + break; + case CPP_RSHIFT_EQ: + code = RSHIFT_EXPR; + break; + case CPP_AND_EQ: + code = BIT_AND_EXPR; + break; + case CPP_XOR_EQ: + code = BIT_XOR_EXPR; + break; + case CPP_OR_EQ: + code = BIT_IOR_EXPR; + break; + default: + c_in_omp_for = save_in_omp_for; + return lhs; + } + c_parser_consume_token (parser); + exp_location = c_parser_peek_token (parser)->location; + rhs = c_parser_expr_no_commas (parser, NULL); + rhs = convert_lvalue_to_rvalue (exp_location, rhs, true, true); + + ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type, + code, exp_location, rhs.value, + rhs.original_type); + set_c_expr_source_range (&ret, lhs.get_start (), rhs.get_finish ()); + if (code == NOP_EXPR) + ret.original_code = MODIFY_EXPR; + else + { + suppress_warning (ret.value, OPT_Wparentheses); + ret.original_code = ERROR_MARK; + } + ret.original_type = NULL; + c_in_omp_for = save_in_omp_for; + return ret; +} + +/* Parse a conditional expression (C90 6.3.15, C99 6.5.15, C11 6.5.15). If + AFTER is not NULL then it is an Objective-C message expression which is + the primary-expression starting the expression as an initializer. + + conditional-expression: + logical-OR-expression + logical-OR-expression ? expression : conditional-expression + + GNU extensions: + + conditional-expression: + logical-OR-expression ? : conditional-expression +*/ + +static struct c_expr +c_parser_conditional_expression (c_parser *parser, struct c_expr *after, + tree omp_atomic_lhs) +{ + struct c_expr cond, exp1, exp2, ret; + location_t start, cond_loc, colon_loc; + + gcc_assert (!after || c_dialect_objc ()); + + cond = c_parser_binary_expression (parser, after, omp_atomic_lhs); + + if (c_parser_next_token_is_not (parser, CPP_QUERY)) + return cond; + if (cond.value != error_mark_node) + start = cond.get_start (); + else + start = UNKNOWN_LOCATION; + cond_loc = c_parser_peek_token (parser)->location; + cond = convert_lvalue_to_rvalue (cond_loc, cond, true, true); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COLON)) + { + tree eptype = NULL_TREE; + + location_t middle_loc = c_parser_peek_token (parser)->location; + pedwarn (middle_loc, OPT_Wpedantic, + "ISO C forbids omitting the middle term of a % expression"); + if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR) + { + eptype = TREE_TYPE (cond.value); + cond.value = TREE_OPERAND (cond.value, 0); + } + tree e = cond.value; + while (TREE_CODE (e) == COMPOUND_EXPR) + e = TREE_OPERAND (e, 1); + warn_for_omitted_condop (middle_loc, e); + /* Make sure first operand is calculated only once. */ + exp1.value = save_expr (default_conversion (cond.value)); + if (eptype) + exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value); + exp1.original_type = NULL; + exp1.src_range = cond.src_range; + cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value); + c_inhibit_evaluation_warnings += cond.value == truthvalue_true_node; + } + else + { + cond.value + = c_objc_common_truthvalue_conversion + (cond_loc, default_conversion (cond.value)); + c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node; + exp1 = c_parser_expression_conv (parser); + mark_exp_read (exp1.value); + c_inhibit_evaluation_warnings += + ((cond.value == truthvalue_true_node) + - (cond.value == truthvalue_false_node)); + } + + colon_loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; + ret.set_error (); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + { + location_t exp2_loc = c_parser_peek_token (parser)->location; + exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE); + exp2 = convert_lvalue_to_rvalue (exp2_loc, exp2, true, true); + } + c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; + location_t loc1 = make_location (exp1.get_start (), exp1.src_range); + location_t loc2 = make_location (exp2.get_start (), exp2.src_range); + if (__builtin_expect (omp_atomic_lhs != NULL, 0) + && (TREE_CODE (cond.value) == GT_EXPR + || TREE_CODE (cond.value) == LT_EXPR + || TREE_CODE (cond.value) == EQ_EXPR) + && c_tree_equal (exp2.value, omp_atomic_lhs) + && (c_tree_equal (TREE_OPERAND (cond.value, 0), omp_atomic_lhs) + || c_tree_equal (TREE_OPERAND (cond.value, 1), omp_atomic_lhs))) + ret.value = build3_loc (colon_loc, COND_EXPR, TREE_TYPE (omp_atomic_lhs), + cond.value, exp1.value, exp2.value); + else + ret.value + = build_conditional_expr (colon_loc, cond.value, + cond.original_code == C_MAYBE_CONST_EXPR, + exp1.value, exp1.original_type, loc1, + exp2.value, exp2.original_type, loc2); + ret.original_code = ERROR_MARK; + if (exp1.value == error_mark_node || exp2.value == error_mark_node) + ret.original_type = NULL; + else + { + tree t1, t2; + + /* If both sides are enum type, the default conversion will have + made the type of the result be an integer type. We want to + remember the enum types we started with. */ + t1 = exp1.original_type ? exp1.original_type : TREE_TYPE (exp1.value); + t2 = exp2.original_type ? exp2.original_type : TREE_TYPE (exp2.value); + ret.original_type = ((t1 != error_mark_node + && t2 != error_mark_node + && (TYPE_MAIN_VARIANT (t1) + == TYPE_MAIN_VARIANT (t2))) + ? t1 + : NULL); + } + set_c_expr_source_range (&ret, start, exp2.get_finish ()); + return ret; +} + +/* Parse a binary expression; that is, a logical-OR-expression (C90 + 6.3.5-6.3.14, C99 6.5.5-6.5.14, C11 6.5.5-6.5.14). If AFTER is not + NULL then it is an Objective-C message expression which is the + primary-expression starting the expression as an initializer. + + OMP_ATOMIC_LHS is NULL, unless parsing OpenMP #pragma omp atomic, + when it should be the unfolded lhs. In a valid OpenMP source, + one of the operands of the toplevel binary expression must be equal + to it. In that case, just return a build2 created binary operation + rather than result of parser_build_binary_op. + + multiplicative-expression: + cast-expression + multiplicative-expression * cast-expression + multiplicative-expression / cast-expression + multiplicative-expression % cast-expression + + additive-expression: + multiplicative-expression + additive-expression + multiplicative-expression + additive-expression - multiplicative-expression + + shift-expression: + additive-expression + shift-expression << additive-expression + shift-expression >> additive-expression + + relational-expression: + shift-expression + relational-expression < shift-expression + relational-expression > shift-expression + relational-expression <= shift-expression + relational-expression >= shift-expression + + equality-expression: + relational-expression + equality-expression == relational-expression + equality-expression != relational-expression + + AND-expression: + equality-expression + AND-expression & equality-expression + + exclusive-OR-expression: + AND-expression + exclusive-OR-expression ^ AND-expression + + inclusive-OR-expression: + exclusive-OR-expression + inclusive-OR-expression | exclusive-OR-expression + + logical-AND-expression: + inclusive-OR-expression + logical-AND-expression && inclusive-OR-expression + + logical-OR-expression: + logical-AND-expression + logical-OR-expression || logical-AND-expression +*/ + +static struct c_expr +c_parser_binary_expression (c_parser *parser, struct c_expr *after, + tree omp_atomic_lhs) +{ + /* A binary expression is parsed using operator-precedence parsing, + with the operands being cast expressions. All the binary + operators are left-associative. Thus a binary expression is of + form: + + E0 op1 E1 op2 E2 ... + + which we represent on a stack. On the stack, the precedence + levels are strictly increasing. When a new operator is + encountered of higher precedence than that at the top of the + stack, it is pushed; its LHS is the top expression, and its RHS + is everything parsed until it is popped. When a new operator is + encountered with precedence less than or equal to that at the top + of the stack, triples E[i-1] op[i] E[i] are popped and replaced + by the result of the operation until the operator at the top of + the stack has lower precedence than the new operator or there is + only one element on the stack; then the top expression is the LHS + of the new operator. In the case of logical AND and OR + expressions, we also need to adjust c_inhibit_evaluation_warnings + as appropriate when the operators are pushed and popped. */ + + struct { + /* The expression at this stack level. */ + struct c_expr expr; + /* The precedence of the operator on its left, PREC_NONE at the + bottom of the stack. */ + enum c_parser_prec prec; + /* The operation on its left. */ + enum tree_code op; + /* The source location of this operation. */ + location_t loc; + /* The sizeof argument if expr.original_code == {PAREN_,}SIZEOF_EXPR. */ + tree sizeof_arg; + } stack[NUM_PRECS]; + int sp; + /* Location of the binary operator. */ + location_t binary_loc = UNKNOWN_LOCATION; /* Quiet warning. */ +#define POP \ + do { \ + switch (stack[sp].op) \ + { \ + case TRUTH_ANDIF_EXPR: \ + c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ + == truthvalue_false_node); \ + break; \ + case TRUTH_ORIF_EXPR: \ + c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ + == truthvalue_true_node); \ + break; \ + case TRUNC_DIV_EXPR: \ + if ((stack[sp - 1].expr.original_code == SIZEOF_EXPR \ + || stack[sp - 1].expr.original_code == PAREN_SIZEOF_EXPR) \ + && (stack[sp].expr.original_code == SIZEOF_EXPR \ + || stack[sp].expr.original_code == PAREN_SIZEOF_EXPR)) \ + { \ + tree type0 = stack[sp - 1].sizeof_arg; \ + tree type1 = stack[sp].sizeof_arg; \ + tree first_arg = type0; \ + if (!TYPE_P (type0)) \ + type0 = TREE_TYPE (type0); \ + if (!TYPE_P (type1)) \ + type1 = TREE_TYPE (type1); \ + if (POINTER_TYPE_P (type0) \ + && comptypes (TREE_TYPE (type0), type1) \ + && !(TREE_CODE (first_arg) == PARM_DECL \ + && C_ARRAY_PARAMETER (first_arg) \ + && warn_sizeof_array_argument)) \ + { \ + auto_diagnostic_group d; \ + if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \ + "division % " \ + "does not compute the number of array " \ + "elements", \ + type0, type1)) \ + if (DECL_P (first_arg)) \ + inform (DECL_SOURCE_LOCATION (first_arg), \ + "first % operand was declared here"); \ + } \ + else if (TREE_CODE (type0) == ARRAY_TYPE \ + && !char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type0))) \ + && stack[sp].expr.original_code != PAREN_SIZEOF_EXPR) \ + maybe_warn_sizeof_array_div (stack[sp].loc, first_arg, type0, \ + stack[sp].sizeof_arg, type1); \ + } \ + break; \ + default: \ + break; \ + } \ + stack[sp - 1].expr \ + = convert_lvalue_to_rvalue (stack[sp - 1].loc, \ + stack[sp - 1].expr, true, true); \ + stack[sp].expr \ + = convert_lvalue_to_rvalue (stack[sp].loc, \ + stack[sp].expr, true, true); \ + if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 \ + && ((c_parser_next_token_is (parser, CPP_SEMICOLON) \ + && ((1 << stack[sp].prec) \ + & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) \ + | (1 << PREC_BITAND) | (1 << PREC_SHIFT) \ + | (1 << PREC_ADD) | (1 << PREC_MULT) \ + | (1 << PREC_EQ)))) \ + || ((c_parser_next_token_is (parser, CPP_QUERY) \ + || (omp_atomic_lhs == void_list_node \ + && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) \ + && (stack[sp].prec == PREC_REL || stack[sp].prec == PREC_EQ)))\ + && stack[sp].op != TRUNC_MOD_EXPR \ + && stack[sp].op != GE_EXPR \ + && stack[sp].op != LE_EXPR \ + && stack[sp].op != NE_EXPR \ + && stack[0].expr.value != error_mark_node \ + && stack[1].expr.value != error_mark_node \ + && (omp_atomic_lhs == void_list_node \ + || c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \ + || c_tree_equal (stack[1].expr.value, omp_atomic_lhs) \ + || (stack[sp].op == EQ_EXPR \ + && c_parser_peek_2nd_token (parser)->keyword == RID_IF))) \ + { \ + tree t = make_node (stack[1].op); \ + TREE_TYPE (t) = TREE_TYPE (stack[0].expr.value); \ + TREE_OPERAND (t, 0) = stack[0].expr.value; \ + TREE_OPERAND (t, 1) = stack[1].expr.value; \ + stack[0].expr.value = t; \ + } \ + else \ + stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ + stack[sp].op, \ + stack[sp - 1].expr, \ + stack[sp].expr); \ + sp--; \ + } while (0) + gcc_assert (!after || c_dialect_objc ()); + stack[0].loc = c_parser_peek_token (parser)->location; + stack[0].expr = c_parser_cast_expression (parser, after); + stack[0].prec = PREC_NONE; + stack[0].sizeof_arg = c_last_sizeof_arg; + sp = 0; + while (true) + { + enum c_parser_prec oprec; + enum tree_code ocode; + source_range src_range; + if (parser->error) + goto out; + switch (c_parser_peek_token (parser)->type) + { + case CPP_MULT: + oprec = PREC_MULT; + ocode = MULT_EXPR; + break; + case CPP_DIV: + oprec = PREC_MULT; + ocode = TRUNC_DIV_EXPR; + break; + case CPP_MOD: + oprec = PREC_MULT; + ocode = TRUNC_MOD_EXPR; + break; + case CPP_PLUS: + oprec = PREC_ADD; + ocode = PLUS_EXPR; + break; + case CPP_MINUS: + oprec = PREC_ADD; + ocode = MINUS_EXPR; + break; + case CPP_LSHIFT: + oprec = PREC_SHIFT; + ocode = LSHIFT_EXPR; + break; + case CPP_RSHIFT: + oprec = PREC_SHIFT; + ocode = RSHIFT_EXPR; + break; + case CPP_LESS: + oprec = PREC_REL; + ocode = LT_EXPR; + break; + case CPP_GREATER: + oprec = PREC_REL; + ocode = GT_EXPR; + break; + case CPP_LESS_EQ: + oprec = PREC_REL; + ocode = LE_EXPR; + break; + case CPP_GREATER_EQ: + oprec = PREC_REL; + ocode = GE_EXPR; + break; + case CPP_EQ_EQ: + oprec = PREC_EQ; + ocode = EQ_EXPR; + break; + case CPP_NOT_EQ: + oprec = PREC_EQ; + ocode = NE_EXPR; + break; + case CPP_AND: + oprec = PREC_BITAND; + ocode = BIT_AND_EXPR; + break; + case CPP_XOR: + oprec = PREC_BITXOR; + ocode = BIT_XOR_EXPR; + break; + case CPP_OR: + oprec = PREC_BITOR; + ocode = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + oprec = PREC_LOGAND; + ocode = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + oprec = PREC_LOGOR; + ocode = TRUTH_ORIF_EXPR; + break; + default: + /* Not a binary operator, so end of the binary + expression. */ + goto out; + } + binary_loc = c_parser_peek_token (parser)->location; + while (oprec <= stack[sp].prec) + POP; + c_parser_consume_token (parser); + switch (ocode) + { + case TRUTH_ANDIF_EXPR: + src_range = stack[sp].expr.src_range; + stack[sp].expr + = convert_lvalue_to_rvalue (stack[sp].loc, + stack[sp].expr, true, true); + stack[sp].expr.value = c_objc_common_truthvalue_conversion + (stack[sp].loc, default_conversion (stack[sp].expr.value)); + c_inhibit_evaluation_warnings += (stack[sp].expr.value + == truthvalue_false_node); + set_c_expr_source_range (&stack[sp].expr, src_range); + break; + case TRUTH_ORIF_EXPR: + src_range = stack[sp].expr.src_range; + stack[sp].expr + = convert_lvalue_to_rvalue (stack[sp].loc, + stack[sp].expr, true, true); + stack[sp].expr.value = c_objc_common_truthvalue_conversion + (stack[sp].loc, default_conversion (stack[sp].expr.value)); + c_inhibit_evaluation_warnings += (stack[sp].expr.value + == truthvalue_true_node); + set_c_expr_source_range (&stack[sp].expr, src_range); + break; + default: + break; + } + sp++; + stack[sp].loc = binary_loc; + stack[sp].expr = c_parser_cast_expression (parser, NULL); + stack[sp].prec = oprec; + stack[sp].op = ocode; + stack[sp].sizeof_arg = c_last_sizeof_arg; + } + out: + while (sp > 0) + POP; + return stack[0].expr; +#undef POP +} + +/* Parse a cast expression (C90 6.3.4, C99 6.5.4, C11 6.5.4). If AFTER + is not NULL then it is an Objective-C message expression which is the + primary-expression starting the expression as an initializer. + + cast-expression: + unary-expression + ( type-name ) unary-expression +*/ + +static struct c_expr +c_parser_cast_expression (c_parser *parser, struct c_expr *after) +{ + location_t cast_loc = c_parser_peek_token (parser)->location; + gcc_assert (!after || c_dialect_objc ()); + if (after) + return c_parser_postfix_expression_after_primary (parser, + cast_loc, *after); + /* If the expression begins with a parenthesized type name, it may + be either a cast or a compound literal; we need to see whether + the next character is '{' to tell the difference. If not, it is + an unary expression. Full detection of unknown typenames here + would require a 3-token lookahead. */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + struct c_type_name *type_name; + struct c_expr ret; + struct c_expr expr; + matching_parens parens; + parens.consume_open (parser); + type_name = c_parser_type_name (parser, true); + parens.skip_until_found_close (parser); + if (type_name == NULL) + { + ret.set_error (); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + + /* Save casted types in the function's used types hash table. */ + used_types_insert (type_name->specs->type); + + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + return c_parser_postfix_expression_after_paren_type (parser, type_name, + cast_loc); + if (type_name->specs->alignas_p) + error_at (type_name->specs->locations[cdw_alignas], + "alignment specified for type name in cast"); + { + location_t expr_loc = c_parser_peek_token (parser)->location; + expr = c_parser_cast_expression (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true); + } + ret.value = c_cast_expr (cast_loc, type_name, expr.value); + if (ret.value && expr.value) + set_c_expr_source_range (&ret, cast_loc, expr.get_finish ()); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + else + return c_parser_unary_expression (parser); +} + +/* Parse an unary expression (C90 6.3.3, C99 6.5.3, C11 6.5.3). + + unary-expression: + postfix-expression + ++ unary-expression + -- unary-expression + unary-operator cast-expression + sizeof unary-expression + sizeof ( type-name ) + + unary-operator: one of + & * + - ~ ! + + GNU extensions: + + unary-expression: + __alignof__ unary-expression + __alignof__ ( type-name ) + && identifier + + (C11 permits _Alignof with type names only.) + + unary-operator: one of + __extension__ __real__ __imag__ + + Transactional Memory: + + unary-expression: + transaction-expression + + In addition, the GNU syntax treats ++ and -- as unary operators, so + they may be applied to cast expressions with errors for non-lvalues + given later. */ + +static struct c_expr +c_parser_unary_expression (c_parser *parser) +{ + int ext; + struct c_expr ret, op; + location_t op_loc = c_parser_peek_token (parser)->location; + location_t exp_loc; + location_t finish; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS_PLUS: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op); + case CPP_MINUS_MINUS: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); + case CPP_AND: + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + mark_exp_read (op.value); + return parser_build_unary_op (op_loc, ADDR_EXPR, op); + case CPP_MULT: + { + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + finish = op.get_finish (); + op = convert_lvalue_to_rvalue (exp_loc, op, true, true); + location_t combined_loc = make_location (op_loc, op_loc, finish); + ret.value = build_indirect_ref (combined_loc, op.value, RO_UNARY_STAR); + ret.src_range.m_start = op_loc; + ret.src_range.m_finish = finish; + return ret; + } + case CPP_PLUS: + if (!c_dialect_objc () && !in_system_header_at (input_location)) + warning_at (op_loc, + OPT_Wtraditional, + "traditional C rejects the unary plus operator"); + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = convert_lvalue_to_rvalue (exp_loc, op, true, true); + return parser_build_unary_op (op_loc, CONVERT_EXPR, op); + case CPP_MINUS: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = convert_lvalue_to_rvalue (exp_loc, op, true, true); + return parser_build_unary_op (op_loc, NEGATE_EXPR, op); + case CPP_COMPL: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = convert_lvalue_to_rvalue (exp_loc, op, true, true); + return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); + case CPP_NOT: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = convert_lvalue_to_rvalue (exp_loc, op, true, true); + return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op); + case CPP_AND_AND: + /* Refer to the address of a label as a pointer. */ + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + ret.value = finish_label_address_expr + (c_parser_peek_token (parser)->value, op_loc); + set_c_expr_source_range (&ret, op_loc, + c_parser_peek_token (parser)->get_finish ()); + c_parser_consume_token (parser); + } + else + { + c_parser_error (parser, "expected identifier"); + ret.set_error (); + } + return ret; + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_SIZEOF: + return c_parser_sizeof_expression (parser); + case RID_ALIGNOF: + return c_parser_alignof_expression (parser); + case RID_BUILTIN_HAS_ATTRIBUTE: + return c_parser_has_attribute_expression (parser); + case RID_EXTENSION: + c_parser_consume_token (parser); + ext = disable_extension_diagnostics (); + ret = c_parser_cast_expression (parser, NULL); + restore_extension_diagnostics (ext); + return ret; + case RID_REALPART: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, REALPART_EXPR, op); + case RID_IMAGPART: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + return c_parser_transaction_expression (parser, + c_parser_peek_token (parser)->keyword); + default: + return c_parser_postfix_expression (parser); + } + default: + return c_parser_postfix_expression (parser); + } +} + +/* Parse a sizeof expression. */ + +static struct c_expr +c_parser_sizeof_expression (c_parser *parser) +{ + struct c_expr expr; + struct c_expr result; + location_t expr_loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); + + location_t start; + location_t finish = UNKNOWN_LOCATION; + + start = c_parser_peek_token (parser)->location; + + c_parser_consume_token (parser); + c_inhibit_evaluation_warnings++; + in_sizeof++; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + /* Either sizeof ( type-name ) or sizeof unary-expression + starting with a compound literal. */ + struct c_type_name *type_name; + matching_parens parens; + parens.consume_open (parser); + expr_loc = c_parser_peek_token (parser)->location; + type_name = c_parser_type_name (parser, true); + parens.skip_until_found_close (parser); + finish = parser->tokens_buf[0].location; + if (type_name == NULL) + { + struct c_expr ret; + c_inhibit_evaluation_warnings--; + in_sizeof--; + ret.set_error (); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + expr = c_parser_postfix_expression_after_paren_type (parser, + type_name, + expr_loc); + finish = expr.get_finish (); + goto sizeof_expr; + } + /* sizeof ( type-name ). */ + if (type_name->specs->alignas_p) + error_at (type_name->specs->locations[cdw_alignas], + "alignment specified for type name in %"); + c_inhibit_evaluation_warnings--; + in_sizeof--; + result = c_expr_sizeof_type (expr_loc, type_name); + } + else + { + expr_loc = c_parser_peek_token (parser)->location; + expr = c_parser_unary_expression (parser); + finish = expr.get_finish (); + sizeof_expr: + c_inhibit_evaluation_warnings--; + in_sizeof--; + mark_exp_read (expr.value); + if (TREE_CODE (expr.value) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) + error_at (expr_loc, "% applied to a bit-field"); + result = c_expr_sizeof_expr (expr_loc, expr); + } + if (finish == UNKNOWN_LOCATION) + finish = start; + set_c_expr_source_range (&result, start, finish); + return result; +} + +/* Parse an alignof expression. */ + +static struct c_expr +c_parser_alignof_expression (c_parser *parser) +{ + struct c_expr expr; + location_t start_loc = c_parser_peek_token (parser)->location; + location_t end_loc; + tree alignof_spelling = c_parser_peek_token (parser)->value; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF)); + bool is_c11_alignof = strcmp (IDENTIFIER_POINTER (alignof_spelling), + "_Alignof") == 0; + /* A diagnostic is not required for the use of this identifier in + the implementation namespace; only diagnose it for the C11 + spelling because of existing code using the other spellings. */ + if (is_c11_alignof) + { + if (flag_isoc99) + pedwarn_c99 (start_loc, OPT_Wpedantic, "ISO C99 does not support %qE", + alignof_spelling); + else + pedwarn_c99 (start_loc, OPT_Wpedantic, "ISO C90 does not support %qE", + alignof_spelling); + } + c_parser_consume_token (parser); + c_inhibit_evaluation_warnings++; + in_alignof++; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + /* Either __alignof__ ( type-name ) or __alignof__ + unary-expression starting with a compound literal. */ + location_t loc; + struct c_type_name *type_name; + struct c_expr ret; + matching_parens parens; + parens.consume_open (parser); + loc = c_parser_peek_token (parser)->location; + type_name = c_parser_type_name (parser, true); + end_loc = c_parser_peek_token (parser)->location; + parens.skip_until_found_close (parser); + if (type_name == NULL) + { + struct c_expr ret; + c_inhibit_evaluation_warnings--; + in_alignof--; + ret.set_error (); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + return ret; + } + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + expr = c_parser_postfix_expression_after_paren_type (parser, + type_name, + loc); + goto alignof_expr; + } + /* alignof ( type-name ). */ + if (type_name->specs->alignas_p) + error_at (type_name->specs->locations[cdw_alignas], + "alignment specified for type name in %qE", + alignof_spelling); + c_inhibit_evaluation_warnings--; + in_alignof--; + ret.value = c_sizeof_or_alignof_type (loc, groktypename (type_name, + NULL, NULL), + false, is_c11_alignof, 1); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + set_c_expr_source_range (&ret, start_loc, end_loc); + return ret; + } + else + { + struct c_expr ret; + expr = c_parser_unary_expression (parser); + end_loc = expr.src_range.m_finish; + alignof_expr: + mark_exp_read (expr.value); + c_inhibit_evaluation_warnings--; + in_alignof--; + if (is_c11_alignof) + pedwarn (start_loc, + OPT_Wpedantic, "ISO C does not allow %<%E (expression)%>", + alignof_spelling); + ret.value = c_alignof_expr (start_loc, expr.value); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + set_c_expr_source_range (&ret, start_loc, end_loc); + return ret; + } +} + +/* Parse the __builtin_has_attribute ([expr|type], attribute-spec) + expression. */ + +static struct c_expr +c_parser_has_attribute_expression (c_parser *parser) +{ + gcc_assert (c_parser_next_token_is_keyword (parser, + RID_BUILTIN_HAS_ATTRIBUTE)); + location_t start = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + c_inhibit_evaluation_warnings++; + + matching_parens parens; + if (!parens.require_open (parser)) + { + c_inhibit_evaluation_warnings--; + in_typeof--; + + struct c_expr result; + result.set_error (); + result.original_code = ERROR_MARK; + result.original_type = NULL; + return result; + } + + /* Treat the type argument the same way as in typeof for the purposes + of warnings. FIXME: Generalize this so the warning refers to + __builtin_has_attribute rather than typeof. */ + in_typeof++; + + /* The first operand: one of DECL, EXPR, or TYPE. */ + tree oper = NULL_TREE; + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + struct c_type_name *tname = c_parser_type_name (parser); + in_typeof--; + if (tname) + { + oper = groktypename (tname, NULL, NULL); + pop_maybe_used (variably_modified_type_p (oper, NULL_TREE)); + } + } + else + { + struct c_expr cexpr = c_parser_expr_no_commas (parser, NULL); + c_inhibit_evaluation_warnings--; + in_typeof--; + if (cexpr.value != error_mark_node) + { + mark_exp_read (cexpr.value); + oper = cexpr.value; + tree etype = TREE_TYPE (oper); + bool was_vm = variably_modified_type_p (etype, NULL_TREE); + /* This is returned with the type so that when the type is + evaluated, this can be evaluated. */ + if (was_vm) + oper = c_fully_fold (oper, false, NULL); + pop_maybe_used (was_vm); + } + } + + struct c_expr result; + result.original_code = ERROR_MARK; + result.original_type = NULL; + + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + { + /* Consume the closing parenthesis if that's the next token + in the likely case the built-in was invoked with fewer + than two arguments. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_consume_token (parser); + c_inhibit_evaluation_warnings--; + result.set_error (); + return result; + } + + bool save_translate_strings_p = parser->translate_strings_p; + + location_t atloc = c_parser_peek_token (parser)->location; + /* Parse a single attribute. Require no leading comma and do not + allow empty attributes. */ + tree attr = c_parser_gnu_attribute (parser, NULL_TREE, false, false); + + parser->translate_strings_p = save_translate_strings_p; + + location_t finish = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + + result.set_error (); + return result; + } + + if (!attr) + { + error_at (atloc, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + result.set_error (); + return result; + } + + result.original_code = INTEGER_CST; + result.original_type = boolean_type_node; + + if (has_attribute (atloc, oper, attr, default_conversion)) + result.value = boolean_true_node; + else + result.value = boolean_false_node; + + set_c_expr_source_range (&result, start, finish); + return result; +} + +/* Helper function to read arguments of builtins which are interfaces + for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and + others. The name of the builtin is passed using BNAME parameter. + Function returns true if there were no errors while parsing and + stores the arguments in CEXPR_LIST. If it returns true, + *OUT_CLOSE_PAREN_LOC is written to with the location of the closing + parenthesis. */ +static bool +c_parser_get_builtin_args (c_parser *parser, const char *bname, + vec **ret_cexpr_list, + bool choose_expr_p, + location_t *out_close_paren_loc) +{ + location_t loc = c_parser_peek_token (parser)->location; + vec *cexpr_list; + c_expr_t expr; + bool saved_force_folding_builtin_constant_p; + + *ret_cexpr_list = NULL; + if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) + { + error_at (loc, "cannot take address of %qs", bname); + return false; + } + + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + *out_close_paren_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + return true; + } + + saved_force_folding_builtin_constant_p + = force_folding_builtin_constant_p; + force_folding_builtin_constant_p |= choose_expr_p; + expr = c_parser_expr_no_commas (parser, NULL); + force_folding_builtin_constant_p + = saved_force_folding_builtin_constant_p; + vec_alloc (cexpr_list, 1); + vec_safe_push (cexpr_list, expr); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + expr = c_parser_expr_no_commas (parser, NULL); + vec_safe_push (cexpr_list, expr); + } + + *out_close_paren_loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return false; + + *ret_cexpr_list = cexpr_list; + return true; +} + +/* This represents a single generic-association. */ + +struct c_generic_association +{ + /* The location of the starting token of the type. */ + location_t type_location; + /* The association's type, or NULL_TREE for 'default'. */ + tree type; + /* The association's expression. */ + struct c_expr expression; +}; + +/* Parse a generic-selection. (C11 6.5.1.1). + + generic-selection: + _Generic ( assignment-expression , generic-assoc-list ) + + generic-assoc-list: + generic-association + generic-assoc-list , generic-association + + generic-association: + type-name : assignment-expression + default : assignment-expression +*/ + +static struct c_expr +c_parser_generic_selection (c_parser *parser) +{ + struct c_expr selector, error_expr; + tree selector_type; + struct c_generic_association matched_assoc; + int match_found = -1; + location_t generic_loc, selector_loc; + + error_expr.original_code = ERROR_MARK; + error_expr.original_type = NULL; + error_expr.set_error (); + matched_assoc.type_location = UNKNOWN_LOCATION; + matched_assoc.type = NULL_TREE; + matched_assoc.expression = error_expr; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_GENERIC)); + generic_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (flag_isoc99) + pedwarn_c99 (generic_loc, OPT_Wpedantic, + "ISO C99 does not support %<_Generic%>"); + else + pedwarn_c99 (generic_loc, OPT_Wpedantic, + "ISO C90 does not support %<_Generic%>"); + + matching_parens parens; + if (!parens.require_open (parser)) + return error_expr; + + c_inhibit_evaluation_warnings++; + selector_loc = c_parser_peek_token (parser)->location; + selector = c_parser_expr_no_commas (parser, NULL); + selector = default_function_array_conversion (selector_loc, selector); + c_inhibit_evaluation_warnings--; + + if (selector.value == error_mark_node) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return selector; + } + mark_exp_read (selector.value); + selector_type = TREE_TYPE (selector.value); + /* In ISO C terms, rvalues (including the controlling expression of + _Generic) do not have qualified types. */ + if (TREE_CODE (selector_type) != ARRAY_TYPE) + selector_type = TYPE_MAIN_VARIANT (selector_type); + /* In ISO C terms, _Noreturn is not part of the type of expressions + such as &abort, but in GCC it is represented internally as a type + qualifier. */ + if (FUNCTION_POINTER_TYPE_P (selector_type) + && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED) + selector_type + = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type))); + + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return error_expr; + } + + auto_vec associations; + while (1) + { + struct c_generic_association assoc, *iter; + unsigned int ix; + c_token *token = c_parser_peek_token (parser); + + assoc.type_location = token->location; + if (token->type == CPP_KEYWORD && token->keyword == RID_DEFAULT) + { + c_parser_consume_token (parser); + assoc.type = NULL_TREE; + } + else + { + struct c_type_name *type_name; + + type_name = c_parser_type_name (parser); + if (type_name == NULL) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return error_expr; + } + assoc.type = groktypename (type_name, NULL, NULL); + if (assoc.type == error_mark_node) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return error_expr; + } + + if (TREE_CODE (assoc.type) == FUNCTION_TYPE) + error_at (assoc.type_location, + "%<_Generic%> association has function type"); + else if (!COMPLETE_TYPE_P (assoc.type)) + error_at (assoc.type_location, + "%<_Generic%> association has incomplete type"); + + if (variably_modified_type_p (assoc.type, NULL_TREE)) + error_at (assoc.type_location, + "%<_Generic%> association has " + "variable length type"); + } + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return error_expr; + } + + assoc.expression = c_parser_expr_no_commas (parser, NULL); + if (assoc.expression.value == error_mark_node) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return error_expr; + } + + for (ix = 0; associations.iterate (ix, &iter); ++ix) + { + if (assoc.type == NULL_TREE) + { + if (iter->type == NULL_TREE) + { + error_at (assoc.type_location, + "duplicate % case in %<_Generic%>"); + inform (iter->type_location, "original % is here"); + } + } + else if (iter->type != NULL_TREE) + { + if (comptypes (assoc.type, iter->type)) + { + error_at (assoc.type_location, + "%<_Generic%> specifies two compatible types"); + inform (iter->type_location, "compatible type is here"); + } + } + } + + if (assoc.type == NULL_TREE) + { + if (match_found < 0) + { + matched_assoc = assoc; + match_found = associations.length (); + } + } + else if (comptypes (assoc.type, selector_type)) + { + if (match_found < 0 || matched_assoc.type == NULL_TREE) + { + matched_assoc = assoc; + match_found = associations.length (); + } + else + { + error_at (assoc.type_location, + "%<_Generic%> selector matches multiple associations"); + inform (matched_assoc.type_location, + "other match is here"); + } + } + + associations.safe_push (assoc); + + if (c_parser_peek_token (parser)->type != CPP_COMMA) + break; + c_parser_consume_token (parser); + } + + unsigned int ix; + struct c_generic_association *iter; + FOR_EACH_VEC_ELT (associations, ix, iter) + if (ix != (unsigned) match_found) + mark_exp_read (iter->expression.value); + + if (!parens.require_close (parser)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return error_expr; + } + + if (match_found < 0) + { + error_at (selector_loc, "%<_Generic%> selector of type %qT is not " + "compatible with any association", + selector_type); + return error_expr; + } + + return matched_assoc.expression; +} + +/* Check the validity of a function pointer argument *EXPR (argument + position POS) to __builtin_tgmath. Return the number of function + arguments if possibly valid; return 0 having reported an error if + not valid. */ + +static unsigned int +check_tgmath_function (c_expr *expr, unsigned int pos) +{ + tree type = TREE_TYPE (expr->value); + if (!FUNCTION_POINTER_TYPE_P (type)) + { + error_at (expr->get_location (), + "argument %u of %<__builtin_tgmath%> is not a function pointer", + pos); + return 0; + } + type = TREE_TYPE (type); + if (!prototype_p (type)) + { + error_at (expr->get_location (), + "argument %u of %<__builtin_tgmath%> is unprototyped", pos); + return 0; + } + if (stdarg_p (type)) + { + error_at (expr->get_location (), + "argument %u of %<__builtin_tgmath%> has variable arguments", + pos); + return 0; + } + unsigned int nargs = 0; + function_args_iterator iter; + tree t; + FOREACH_FUNCTION_ARGS (type, t, iter) + { + if (t == void_type_node) + break; + nargs++; + } + if (nargs == 0) + { + error_at (expr->get_location (), + "argument %u of %<__builtin_tgmath%> has no arguments", pos); + return 0; + } + return nargs; +} + +/* Ways in which a parameter or return value of a type-generic macro + may vary between the different functions the macro may call. */ +enum tgmath_parm_kind + { + tgmath_fixed, tgmath_real, tgmath_complex + }; + +/* Helper function for c_parser_postfix_expression. Parse predefined + identifiers. */ + +static struct c_expr +c_parser_predefined_identifier (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + switch (c_parser_peek_token (parser)->keyword) + { + case RID_FUNCTION_NAME: + pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " + "identifier", "__FUNCTION__"); + break; + case RID_PRETTY_FUNCTION_NAME: + pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " + "identifier", "__PRETTY_FUNCTION__"); + break; + case RID_C99_FUNCTION_NAME: + pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not support " + "%<__func__%> predefined identifier"); + break; + default: + gcc_unreachable (); + } + + struct c_expr expr; + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + expr.value = fname_decl (loc, c_parser_peek_token (parser)->keyword, + c_parser_peek_token (parser)->value); + set_c_expr_source_range (&expr, loc, loc); + c_parser_consume_token (parser); + return expr; +} + +/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2, + C11 6.5.1-6.5.2). Compound literals aren't handled here; callers have to + call c_parser_postfix_expression_after_paren_type on encountering them. + + postfix-expression: + primary-expression + postfix-expression [ expression ] + postfix-expression ( argument-expression-list[opt] ) + postfix-expression . identifier + postfix-expression -> identifier + postfix-expression ++ + postfix-expression -- + ( type-name ) { initializer-list } + ( type-name ) { initializer-list , } + + argument-expression-list: + argument-expression + argument-expression-list , argument-expression + + primary-expression: + identifier + constant + string-literal + ( expression ) + generic-selection + + GNU extensions: + + primary-expression: + __func__ + (treated as a keyword in GNU C) + __FUNCTION__ + __PRETTY_FUNCTION__ + ( compound-statement ) + __builtin_va_arg ( assignment-expression , type-name ) + __builtin_offsetof ( type-name , offsetof-member-designator ) + __builtin_choose_expr ( assignment-expression , + assignment-expression , + assignment-expression ) + __builtin_types_compatible_p ( type-name , type-name ) + __builtin_tgmath ( expr-list ) + __builtin_complex ( assignment-expression , assignment-expression ) + __builtin_shuffle ( assignment-expression , assignment-expression ) + __builtin_shuffle ( assignment-expression , + assignment-expression , + assignment-expression, ) + __builtin_convertvector ( assignment-expression , type-name ) + __builtin_assoc_barrier ( assignment-expression ) + + offsetof-member-designator: + identifier + offsetof-member-designator . identifier + offsetof-member-designator [ expression ] + + Objective-C: + + primary-expression: + [ objc-receiver objc-message-args ] + @selector ( objc-selector-arg ) + @protocol ( identifier ) + @encode ( type-name ) + objc-string-literal + Classname . identifier +*/ + +static struct c_expr +c_parser_postfix_expression (c_parser *parser) +{ + struct c_expr expr, e1; + struct c_type_name *t1, *t2; + location_t loc = c_parser_peek_token (parser)->location; + source_range tok_range = c_parser_peek_token (parser)->get_range (); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + switch (c_parser_peek_token (parser)->type) + { + case CPP_NUMBER: + expr.value = c_parser_peek_token (parser)->value; + set_c_expr_source_range (&expr, tok_range); + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (TREE_CODE (expr.value) == FIXED_CST + && !targetm.fixed_point_supported_p ()) + { + error_at (loc, "fixed-point types not supported for this target"); + expr.set_error (); + } + break; + case CPP_CHAR: + case CPP_CHAR16: + case CPP_CHAR32: + case CPP_UTF8CHAR: + case CPP_WCHAR: + expr.value = c_parser_peek_token (parser)->value; + /* For the purpose of warning when a pointer is compared with + a zero character constant. */ + expr.original_type = char_type_node; + set_c_expr_source_range (&expr, tok_range); + c_parser_consume_token (parser); + break; + case CPP_STRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_WSTRING: + case CPP_UTF8STRING: + expr = c_parser_string_literal (parser, parser->translate_strings_p, + true); + break; + case CPP_OBJC_STRING: + gcc_assert (c_dialect_objc ()); + expr.value + = objc_build_string_object (c_parser_peek_token (parser)->value); + set_c_expr_source_range (&expr, tok_range); + c_parser_consume_token (parser); + break; + case CPP_NAME: + switch (c_parser_peek_token (parser)->id_kind) + { + case C_ID_ID: + { + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + expr.value = build_external_ref (loc, id, + (c_parser_peek_token (parser)->type + == CPP_OPEN_PAREN), + &expr.original_type); + set_c_expr_source_range (&expr, tok_range); + break; + } + case C_ID_CLASSNAME: + { + /* Here we parse the Objective-C 2.0 Class.name dot + syntax. */ + tree class_name = c_parser_peek_token (parser)->value; + tree component; + c_parser_consume_token (parser); + gcc_assert (c_dialect_objc ()); + if (!c_parser_require (parser, CPP_DOT, "expected %<.%>")) + { + expr.set_error (); + break; + } + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + expr.set_error (); + break; + } + c_token *component_tok = c_parser_peek_token (parser); + component = component_tok->value; + location_t end_loc = component_tok->get_finish (); + c_parser_consume_token (parser); + expr.value = objc_build_class_component_ref (class_name, + component); + set_c_expr_source_range (&expr, loc, end_loc); + break; + } + default: + c_parser_error (parser, "expected expression"); + expr.set_error (); + break; + } + break; + case CPP_OPEN_PAREN: + /* A parenthesized expression, statement expression or compound + literal. */ + if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE) + { + /* A statement expression. */ + tree stmt; + location_t brace_loc; + c_parser_consume_token (parser); + brace_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + /* If we've not yet started the current function's statement list, + or we're in the parameter scope of an old-style function + declaration, statement expressions are not allowed. */ + if (!building_stmt_list_p () || old_style_parameter_scope ()) + { + error_at (loc, "braced-group within expression allowed " + "only inside a function"); + parser->error = true; + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.set_error (); + break; + } + stmt = c_begin_stmt_expr (); + c_parser_compound_statement_nostart (parser); + location_t close_loc = c_parser_peek_token (parser)->location; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids braced-groups within expressions"); + expr.value = c_finish_stmt_expr (brace_loc, stmt); + set_c_expr_source_range (&expr, loc, close_loc); + mark_exp_read (expr.value); + } + else + { + /* A parenthesized expression. */ + location_t loc_open_paren = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + expr = c_parser_expression (parser); + if (TREE_CODE (expr.value) == MODIFY_EXPR) + suppress_warning (expr.value, OPT_Wparentheses); + if (expr.original_code != C_MAYBE_CONST_EXPR + && expr.original_code != SIZEOF_EXPR) + expr.original_code = ERROR_MARK; + /* Remember that we saw ( ) around the sizeof. */ + if (expr.original_code == SIZEOF_EXPR) + expr.original_code = PAREN_SIZEOF_EXPR; + /* Don't change EXPR.ORIGINAL_TYPE. */ + location_t loc_close_paren = c_parser_peek_token (parser)->location; + set_c_expr_source_range (&expr, loc_open_paren, loc_close_paren); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>", loc_open_paren); + } + break; + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_FUNCTION_NAME: + case RID_PRETTY_FUNCTION_NAME: + case RID_C99_FUNCTION_NAME: + expr = c_parser_predefined_identifier (parser); + break; + case RID_VA_ARG: + { + location_t start_loc = loc; + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + e1 = c_parser_expr_no_commas (parser, NULL); + mark_exp_read (e1.value); + e1.value = c_fully_fold (e1.value, false, NULL); + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.set_error (); + break; + } + loc = c_parser_peek_token (parser)->location; + t1 = c_parser_type_name (parser); + location_t end_loc = c_parser_peek_token (parser)->get_finish (); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + if (t1 == NULL) + { + expr.set_error (); + } + else + { + tree type_expr = NULL_TREE; + expr.value = c_build_va_arg (start_loc, e1.value, loc, + groktypename (t1, &type_expr, NULL)); + if (type_expr) + { + expr.value = build2 (C_MAYBE_CONST_EXPR, + TREE_TYPE (expr.value), type_expr, + expr.value); + C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true; + } + set_c_expr_source_range (&expr, start_loc, end_loc); + } + } + break; + case RID_OFFSETOF: + { + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + t1 = c_parser_type_name (parser); + if (t1 == NULL) + parser->error = true; + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + gcc_assert (parser->error); + if (parser->error) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.set_error (); + break; + } + tree type = groktypename (t1, NULL, NULL); + tree offsetof_ref; + if (type == error_mark_node) + offsetof_ref = error_mark_node; + else + { + offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node); + SET_EXPR_LOCATION (offsetof_ref, loc); + } + /* Parse the second argument to __builtin_offsetof. We + must have one identifier, and beyond that we want to + accept sub structure and sub array references. */ + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *comp_tok = c_parser_peek_token (parser); + offsetof_ref = build_component_ref + (loc, offsetof_ref, comp_tok->value, comp_tok->location); + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_DOT) + || c_parser_next_token_is (parser, + CPP_OPEN_SQUARE) + || c_parser_next_token_is (parser, + CPP_DEREF)) + { + if (c_parser_next_token_is (parser, CPP_DEREF)) + { + loc = c_parser_peek_token (parser)->location; + offsetof_ref = build_array_ref (loc, + offsetof_ref, + integer_zero_node); + goto do_dot; + } + else if (c_parser_next_token_is (parser, CPP_DOT)) + { + do_dot: + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, + CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + c_token *comp_tok = c_parser_peek_token (parser); + offsetof_ref = build_component_ref + (loc, offsetof_ref, comp_tok->value, + comp_tok->location); + c_parser_consume_token (parser); + } + else + { + struct c_expr ce; + tree idx; + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + ce = c_parser_expression (parser); + ce = convert_lvalue_to_rvalue (loc, ce, false, false); + idx = ce.value; + idx = c_fully_fold (idx, false, NULL); + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + offsetof_ref = build_array_ref (loc, offsetof_ref, idx); + } + } + } + else + c_parser_error (parser, "expected identifier"); + location_t end_loc = c_parser_peek_token (parser)->get_finish (); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + expr.value = fold_offsetof (offsetof_ref); + set_c_expr_source_range (&expr, loc, end_loc); + } + break; + case RID_CHOOSE_EXPR: + { + vec *cexpr_list; + c_expr_t *e1_p, *e2_p, *e3_p; + tree c; + location_t close_paren_loc; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_choose_expr", + &cexpr_list, true, + &close_paren_loc)) + { + expr.set_error (); + break; + } + + if (vec_safe_length (cexpr_list) != 3) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_choose_expr%>"); + expr.set_error (); + break; + } + + e1_p = &(*cexpr_list)[0]; + e2_p = &(*cexpr_list)[1]; + e3_p = &(*cexpr_list)[2]; + + c = e1_p->value; + mark_exp_read (e2_p->value); + mark_exp_read (e3_p->value); + if (TREE_CODE (c) != INTEGER_CST + || !INTEGRAL_TYPE_P (TREE_TYPE (c))) + error_at (loc, + "first argument to %<__builtin_choose_expr%> not" + " a constant"); + constant_expression_warning (c); + expr = integer_zerop (c) ? *e3_p : *e2_p; + set_c_expr_source_range (&expr, loc, close_paren_loc); + break; + } + case RID_TYPES_COMPATIBLE_P: + { + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + t1 = c_parser_type_name (parser); + if (t1 == NULL) + { + expr.set_error (); + break; + } + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.set_error (); + break; + } + t2 = c_parser_type_name (parser); + if (t2 == NULL) + { + expr.set_error (); + break; + } + location_t close_paren_loc = c_parser_peek_token (parser)->location; + parens.skip_until_found_close (parser); + tree e1, e2; + e1 = groktypename (t1, NULL, NULL); + e2 = groktypename (t2, NULL, NULL); + if (e1 == error_mark_node || e2 == error_mark_node) + { + expr.set_error (); + break; + } + + e1 = TYPE_MAIN_VARIANT (e1); + e2 = TYPE_MAIN_VARIANT (e2); + + expr.value + = comptypes (e1, e2) ? integer_one_node : integer_zero_node; + set_c_expr_source_range (&expr, loc, close_paren_loc); + } + break; + case RID_BUILTIN_TGMATH: + { + vec *cexpr_list; + location_t close_paren_loc; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_tgmath", + &cexpr_list, false, + &close_paren_loc)) + { + expr.set_error (); + break; + } + + if (vec_safe_length (cexpr_list) < 3) + { + error_at (loc, "too few arguments to %<__builtin_tgmath%>"); + expr.set_error (); + break; + } + + unsigned int i; + c_expr_t *p; + FOR_EACH_VEC_ELT (*cexpr_list, i, p) + *p = convert_lvalue_to_rvalue (loc, *p, true, true); + unsigned int nargs = check_tgmath_function (&(*cexpr_list)[0], 1); + if (nargs == 0) + { + expr.set_error (); + break; + } + if (vec_safe_length (cexpr_list) < nargs) + { + error_at (loc, "too few arguments to %<__builtin_tgmath%>"); + expr.set_error (); + break; + } + unsigned int num_functions = vec_safe_length (cexpr_list) - nargs; + if (num_functions < 2) + { + error_at (loc, "too few arguments to %<__builtin_tgmath%>"); + expr.set_error (); + break; + } + + /* The first NUM_FUNCTIONS expressions are the function + pointers. The remaining NARGS expressions are the + arguments that are to be passed to one of those + functions, chosen following rules. */ + for (unsigned int j = 1; j < num_functions; j++) + { + unsigned int this_nargs + = check_tgmath_function (&(*cexpr_list)[j], j + 1); + if (this_nargs == 0) + { + expr.set_error (); + goto out; + } + if (this_nargs != nargs) + { + error_at ((*cexpr_list)[j].get_location (), + "argument %u of %<__builtin_tgmath%> has " + "wrong number of arguments", j + 1); + expr.set_error (); + goto out; + } + } + + /* The functions all have the same number of arguments. + Determine whether arguments and return types vary in + ways permitted for functions. */ + /* The first entry in each of these vectors is for the + return type, subsequent entries for parameter + types. */ + auto_vec parm_kind (nargs + 1); + auto_vec parm_first (nargs + 1); + auto_vec parm_complex (nargs + 1); + auto_vec parm_varies (nargs + 1); + tree first_type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[0].value)); + tree first_ret = TYPE_MAIN_VARIANT (TREE_TYPE (first_type)); + parm_first.quick_push (first_ret); + parm_complex.quick_push (TREE_CODE (first_ret) == COMPLEX_TYPE); + parm_varies.quick_push (false); + function_args_iterator iter; + tree t; + unsigned int argpos; + FOREACH_FUNCTION_ARGS (first_type, t, iter) + { + if (t == void_type_node) + break; + parm_first.quick_push (TYPE_MAIN_VARIANT (t)); + parm_complex.quick_push (TREE_CODE (t) == COMPLEX_TYPE); + parm_varies.quick_push (false); + } + for (unsigned int j = 1; j < num_functions; j++) + { + tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); + tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + if (ret != parm_first[0]) + { + parm_varies[0] = true; + if (!SCALAR_FLOAT_TYPE_P (parm_first[0]) + && !COMPLEX_FLOAT_TYPE_P (parm_first[0])) + { + error_at ((*cexpr_list)[0].get_location (), + "invalid type-generic return type for " + "argument %u of %<__builtin_tgmath%>", + 1); + expr.set_error (); + goto out; + } + if (!SCALAR_FLOAT_TYPE_P (ret) + && !COMPLEX_FLOAT_TYPE_P (ret)) + { + error_at ((*cexpr_list)[j].get_location (), + "invalid type-generic return type for " + "argument %u of %<__builtin_tgmath%>", + j + 1); + expr.set_error (); + goto out; + } + } + if (TREE_CODE (ret) == COMPLEX_TYPE) + parm_complex[0] = true; + argpos = 1; + FOREACH_FUNCTION_ARGS (type, t, iter) + { + if (t == void_type_node) + break; + t = TYPE_MAIN_VARIANT (t); + if (t != parm_first[argpos]) + { + parm_varies[argpos] = true; + if (!SCALAR_FLOAT_TYPE_P (parm_first[argpos]) + && !COMPLEX_FLOAT_TYPE_P (parm_first[argpos])) + { + error_at ((*cexpr_list)[0].get_location (), + "invalid type-generic type for " + "argument %u of argument %u of " + "%<__builtin_tgmath%>", argpos, 1); + expr.set_error (); + goto out; + } + if (!SCALAR_FLOAT_TYPE_P (t) + && !COMPLEX_FLOAT_TYPE_P (t)) + { + error_at ((*cexpr_list)[j].get_location (), + "invalid type-generic type for " + "argument %u of argument %u of " + "%<__builtin_tgmath%>", argpos, j + 1); + expr.set_error (); + goto out; + } + } + if (TREE_CODE (t) == COMPLEX_TYPE) + parm_complex[argpos] = true; + argpos++; + } + } + enum tgmath_parm_kind max_variation = tgmath_fixed; + for (unsigned int j = 0; j <= nargs; j++) + { + enum tgmath_parm_kind this_kind; + if (parm_varies[j]) + { + if (parm_complex[j]) + max_variation = this_kind = tgmath_complex; + else + { + this_kind = tgmath_real; + if (max_variation != tgmath_complex) + max_variation = tgmath_real; + } + } + else + this_kind = tgmath_fixed; + parm_kind.quick_push (this_kind); + } + if (max_variation == tgmath_fixed) + { + error_at (loc, "function arguments of %<__builtin_tgmath%> " + "all have the same type"); + expr.set_error (); + break; + } + + /* Identify a parameter (not the return type) that varies, + including with complex types if any variation includes + complex types; there must be at least one such + parameter. */ + unsigned int tgarg = 0; + for (unsigned int j = 1; j <= nargs; j++) + if (parm_kind[j] == max_variation) + { + tgarg = j; + break; + } + if (tgarg == 0) + { + error_at (loc, "function arguments of %<__builtin_tgmath%> " + "lack type-generic parameter"); + expr.set_error (); + break; + } + + /* Determine the type of the relevant parameter for each + function. */ + auto_vec tg_type (num_functions); + for (unsigned int j = 0; j < num_functions; j++) + { + tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); + argpos = 1; + FOREACH_FUNCTION_ARGS (type, t, iter) + { + if (argpos == tgarg) + { + tg_type.quick_push (TYPE_MAIN_VARIANT (t)); + break; + } + argpos++; + } + } + + /* Verify that the corresponding types are different for + all the listed functions. Also determine whether all + the types are complex, whether all the types are + standard or binary, and whether all the types are + decimal. */ + bool all_complex = true; + bool all_binary = true; + bool all_decimal = true; + hash_set tg_types; + FOR_EACH_VEC_ELT (tg_type, i, t) + { + if (TREE_CODE (t) == COMPLEX_TYPE) + all_decimal = false; + else + { + all_complex = false; + if (DECIMAL_FLOAT_TYPE_P (t)) + all_binary = false; + else + all_decimal = false; + } + if (tg_types.add (t)) + { + error_at ((*cexpr_list)[i].get_location (), + "duplicate type-generic parameter type for " + "function argument %u of %<__builtin_tgmath%>", + i + 1); + expr.set_error (); + goto out; + } + } + + /* Verify that other parameters and the return type whose + types vary have their types varying in the correct + way. */ + for (unsigned int j = 0; j < num_functions; j++) + { + tree exp_type = tg_type[j]; + tree exp_real_type = exp_type; + if (TREE_CODE (exp_type) == COMPLEX_TYPE) + exp_real_type = TREE_TYPE (exp_type); + tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); + tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + if ((parm_kind[0] == tgmath_complex && ret != exp_type) + || (parm_kind[0] == tgmath_real && ret != exp_real_type)) + { + error_at ((*cexpr_list)[j].get_location (), + "bad return type for function argument %u " + "of %<__builtin_tgmath%>", j + 1); + expr.set_error (); + goto out; + } + argpos = 1; + FOREACH_FUNCTION_ARGS (type, t, iter) + { + if (t == void_type_node) + break; + t = TYPE_MAIN_VARIANT (t); + if ((parm_kind[argpos] == tgmath_complex + && t != exp_type) + || (parm_kind[argpos] == tgmath_real + && t != exp_real_type)) + { + error_at ((*cexpr_list)[j].get_location (), + "bad type for argument %u of " + "function argument %u of " + "%<__builtin_tgmath%>", argpos, j + 1); + expr.set_error (); + goto out; + } + argpos++; + } + } + + /* The functions listed are a valid set of functions for a + macro to select between. Identify the + matching function, if any. First, the argument types + must be combined following rules. Integer + types are treated as _Decimal64 if any type-generic + argument is decimal, or if the only alternatives for + type-generic arguments are of decimal types, and are + otherwise treated as double (or _Complex double for + complex integer types, or _Float64 or _Complex _Float64 + if all the return types are the same _FloatN or + _FloatNx type). After that adjustment, types are + combined following the usual arithmetic conversions. + If the function only accepts complex arguments, a + complex type is produced. */ + bool arg_complex = all_complex; + bool arg_binary = all_binary; + bool arg_int_decimal = all_decimal; + for (unsigned int j = 1; j <= nargs; j++) + { + if (parm_kind[j] == tgmath_fixed) + continue; + c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1]; + tree type = TREE_TYPE (ce->value); + if (!INTEGRAL_TYPE_P (type) + && !SCALAR_FLOAT_TYPE_P (type) + && TREE_CODE (type) != COMPLEX_TYPE) + { + error_at (ce->get_location (), + "invalid type of argument %u of type-generic " + "function", j); + expr.set_error (); + goto out; + } + if (DECIMAL_FLOAT_TYPE_P (type)) + { + arg_int_decimal = true; + if (all_complex) + { + error_at (ce->get_location (), + "decimal floating-point argument %u to " + "complex-only type-generic function", j); + expr.set_error (); + goto out; + } + else if (all_binary) + { + error_at (ce->get_location (), + "decimal floating-point argument %u to " + "binary-only type-generic function", j); + expr.set_error (); + goto out; + } + else if (arg_complex) + { + error_at (ce->get_location (), + "both complex and decimal floating-point " + "arguments to type-generic function"); + expr.set_error (); + goto out; + } + else if (arg_binary) + { + error_at (ce->get_location (), + "both binary and decimal floating-point " + "arguments to type-generic function"); + expr.set_error (); + goto out; + } + } + else if (TREE_CODE (type) == COMPLEX_TYPE) + { + arg_complex = true; + if (COMPLEX_FLOAT_TYPE_P (type)) + arg_binary = true; + if (all_decimal) + { + error_at (ce->get_location (), + "complex argument %u to " + "decimal-only type-generic function", j); + expr.set_error (); + goto out; + } + else if (arg_int_decimal) + { + error_at (ce->get_location (), + "both complex and decimal floating-point " + "arguments to type-generic function"); + expr.set_error (); + goto out; + } + } + else if (SCALAR_FLOAT_TYPE_P (type)) + { + arg_binary = true; + if (all_decimal) + { + error_at (ce->get_location (), + "binary argument %u to " + "decimal-only type-generic function", j); + expr.set_error (); + goto out; + } + else if (arg_int_decimal) + { + error_at (ce->get_location (), + "both binary and decimal floating-point " + "arguments to type-generic function"); + expr.set_error (); + goto out; + } + } + } + /* For a macro rounding its result to a narrower type, map + integer types to _Float64 not double if the return type + is a _FloatN or _FloatNx type. */ + bool arg_int_float64 = false; + if (parm_kind[0] == tgmath_fixed + && SCALAR_FLOAT_TYPE_P (parm_first[0]) + && float64_type_node != NULL_TREE) + for (unsigned int j = 0; j < NUM_FLOATN_NX_TYPES; j++) + if (parm_first[0] == FLOATN_TYPE_NODE (j)) + { + arg_int_float64 = true; + break; + } + tree arg_real = NULL_TREE; + for (unsigned int j = 1; j <= nargs; j++) + { + if (parm_kind[j] == tgmath_fixed) + continue; + c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1]; + tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ce->value)); + if (TREE_CODE (type) == COMPLEX_TYPE) + type = TREE_TYPE (type); + if (INTEGRAL_TYPE_P (type)) + type = (arg_int_decimal + ? dfloat64_type_node + : arg_int_float64 + ? float64_type_node + : double_type_node); + if (arg_real == NULL_TREE) + arg_real = type; + else + arg_real = common_type (arg_real, type); + if (arg_real == error_mark_node) + { + expr.set_error (); + goto out; + } + } + tree arg_type = (arg_complex + ? build_complex_type (arg_real) + : arg_real); + + /* Look for a function to call with type-generic parameter + type ARG_TYPE. */ + c_expr_t *fn = NULL; + for (unsigned int j = 0; j < num_functions; j++) + { + if (tg_type[j] == arg_type) + { + fn = &(*cexpr_list)[j]; + break; + } + } + if (fn == NULL + && parm_kind[0] == tgmath_fixed + && SCALAR_FLOAT_TYPE_P (parm_first[0])) + { + /* Presume this is a macro that rounds its result to a + narrower type, and look for the first function with + at least the range and precision of the argument + type. */ + for (unsigned int j = 0; j < num_functions; j++) + { + if (arg_complex + != (TREE_CODE (tg_type[j]) == COMPLEX_TYPE)) + continue; + tree real_tg_type = (arg_complex + ? TREE_TYPE (tg_type[j]) + : tg_type[j]); + if (DECIMAL_FLOAT_TYPE_P (arg_real) + != DECIMAL_FLOAT_TYPE_P (real_tg_type)) + continue; + scalar_float_mode arg_mode + = SCALAR_FLOAT_TYPE_MODE (arg_real); + scalar_float_mode tg_mode + = SCALAR_FLOAT_TYPE_MODE (real_tg_type); + const real_format *arg_fmt = REAL_MODE_FORMAT (arg_mode); + const real_format *tg_fmt = REAL_MODE_FORMAT (tg_mode); + if (arg_fmt->b == tg_fmt->b + && arg_fmt->p <= tg_fmt->p + && arg_fmt->emax <= tg_fmt->emax + && (arg_fmt->emin - arg_fmt->p + >= tg_fmt->emin - tg_fmt->p)) + { + fn = &(*cexpr_list)[j]; + break; + } + } + } + if (fn == NULL) + { + error_at (loc, "no matching function for type-generic call"); + expr.set_error (); + break; + } + + /* Construct a call to FN. */ + vec *args; + vec_alloc (args, nargs); + vec *origtypes; + vec_alloc (origtypes, nargs); + auto_vec arg_loc (nargs); + for (unsigned int j = 0; j < nargs; j++) + { + c_expr_t *ce = &(*cexpr_list)[num_functions + j]; + args->quick_push (ce->value); + arg_loc.quick_push (ce->get_location ()); + origtypes->quick_push (ce->original_type); + } + expr.value = c_build_function_call_vec (loc, arg_loc, fn->value, + args, origtypes); + set_c_expr_source_range (&expr, loc, close_paren_loc); + break; + } + case RID_BUILTIN_CALL_WITH_STATIC_CHAIN: + { + vec *cexpr_list; + c_expr_t *e2_p; + tree chain_value; + location_t close_paren_loc; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_call_with_static_chain", + &cexpr_list, false, + &close_paren_loc)) + { + expr.set_error (); + break; + } + if (vec_safe_length (cexpr_list) != 2) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_call_with_static_chain%>"); + expr.set_error (); + break; + } + + expr = (*cexpr_list)[0]; + e2_p = &(*cexpr_list)[1]; + *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true); + chain_value = e2_p->value; + mark_exp_read (chain_value); + + if (TREE_CODE (expr.value) != CALL_EXPR) + error_at (loc, "first argument to " + "%<__builtin_call_with_static_chain%> " + "must be a call expression"); + else if (TREE_CODE (TREE_TYPE (chain_value)) != POINTER_TYPE) + error_at (loc, "second argument to " + "%<__builtin_call_with_static_chain%> " + "must be a pointer type"); + else + CALL_EXPR_STATIC_CHAIN (expr.value) = chain_value; + set_c_expr_source_range (&expr, loc, close_paren_loc); + break; + } + case RID_BUILTIN_COMPLEX: + { + vec *cexpr_list; + c_expr_t *e1_p, *e2_p; + location_t close_paren_loc; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_complex", + &cexpr_list, false, + &close_paren_loc)) + { + expr.set_error (); + break; + } + + if (vec_safe_length (cexpr_list) != 2) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_complex%>"); + expr.set_error (); + break; + } + + e1_p = &(*cexpr_list)[0]; + e2_p = &(*cexpr_list)[1]; + + *e1_p = convert_lvalue_to_rvalue (loc, *e1_p, true, true); + if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR) + e1_p->value = convert (TREE_TYPE (e1_p->value), + TREE_OPERAND (e1_p->value, 0)); + *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true); + if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR) + e2_p->value = convert (TREE_TYPE (e2_p->value), + TREE_OPERAND (e2_p->value, 0)); + if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) + || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) + || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2_p->value)) + || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2_p->value))) + { + error_at (loc, "%<__builtin_complex%> operand " + "not of real binary floating-point type"); + expr.set_error (); + break; + } + if (TYPE_MAIN_VARIANT (TREE_TYPE (e1_p->value)) + != TYPE_MAIN_VARIANT (TREE_TYPE (e2_p->value))) + { + error_at (loc, + "%<__builtin_complex%> operands of different types"); + expr.set_error (); + break; + } + pedwarn_c90 (loc, OPT_Wpedantic, + "ISO C90 does not support complex types"); + expr.value = build2_loc (loc, COMPLEX_EXPR, + build_complex_type + (TYPE_MAIN_VARIANT + (TREE_TYPE (e1_p->value))), + e1_p->value, e2_p->value); + set_c_expr_source_range (&expr, loc, close_paren_loc); + break; + } + case RID_BUILTIN_SHUFFLE: + { + vec *cexpr_list; + unsigned int i; + c_expr_t *p; + location_t close_paren_loc; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_shuffle", + &cexpr_list, false, + &close_paren_loc)) + { + expr.set_error (); + break; + } + + FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) + *p = convert_lvalue_to_rvalue (loc, *p, true, true); + + if (vec_safe_length (cexpr_list) == 2) + expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, + NULL_TREE, + (*cexpr_list)[1].value); + + else if (vec_safe_length (cexpr_list) == 3) + expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, + (*cexpr_list)[1].value, + (*cexpr_list)[2].value); + else + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_shuffle%>"); + expr.set_error (); + } + set_c_expr_source_range (&expr, loc, close_paren_loc); + break; + } + case RID_BUILTIN_SHUFFLEVECTOR: + { + vec *cexpr_list; + unsigned int i; + c_expr_t *p; + location_t close_paren_loc; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_shufflevector", + &cexpr_list, false, + &close_paren_loc)) + { + expr.set_error (); + break; + } + + FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) + *p = convert_lvalue_to_rvalue (loc, *p, true, true); + + if (vec_safe_length (cexpr_list) < 3) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_shuffle%>"); + expr.set_error (); + } + else + { + auto_vec mask; + for (i = 2; i < cexpr_list->length (); ++i) + mask.safe_push ((*cexpr_list)[i].value); + expr.value = c_build_shufflevector (loc, (*cexpr_list)[0].value, + (*cexpr_list)[1].value, + mask); + } + set_c_expr_source_range (&expr, loc, close_paren_loc); + break; + } + case RID_BUILTIN_CONVERTVECTOR: + { + location_t start_loc = loc; + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + e1 = c_parser_expr_no_commas (parser, NULL); + mark_exp_read (e1.value); + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.set_error (); + break; + } + loc = c_parser_peek_token (parser)->location; + t1 = c_parser_type_name (parser); + location_t end_loc = c_parser_peek_token (parser)->get_finish (); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + if (t1 == NULL) + expr.set_error (); + else + { + tree type_expr = NULL_TREE; + expr.value = c_build_vec_convert (start_loc, e1.value, loc, + groktypename (t1, &type_expr, + NULL)); + set_c_expr_source_range (&expr, start_loc, end_loc); + } + } + break; + case RID_BUILTIN_ASSOC_BARRIER: + { + location_t start_loc = loc; + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + e1 = c_parser_expr_no_commas (parser, NULL); + mark_exp_read (e1.value); + location_t end_loc = c_parser_peek_token (parser)->get_finish (); + parens.skip_until_found_close (parser); + expr.value = build1_loc (loc, PAREN_EXPR, TREE_TYPE (e1.value), + e1.value); + set_c_expr_source_range (&expr, start_loc, end_loc); + } + break; + case RID_AT_SELECTOR: + { + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + tree sel = c_parser_objc_selector_arg (parser); + location_t close_loc = c_parser_peek_token (parser)->location; + parens.skip_until_found_close (parser); + expr.value = objc_build_selector_expr (loc, sel); + set_c_expr_source_range (&expr, loc, close_loc); + } + break; + case RID_AT_PROTOCOL: + { + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.set_error (); + break; + } + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + location_t close_loc = c_parser_peek_token (parser)->location; + parens.skip_until_found_close (parser); + expr.value = objc_build_protocol_expr (id); + set_c_expr_source_range (&expr, loc, close_loc); + } + break; + case RID_AT_ENCODE: + { + /* Extension to support C-structures in the archiver. */ + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + t1 = c_parser_type_name (parser); + if (t1 == NULL) + { + expr.set_error (); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + break; + } + location_t close_loc = c_parser_peek_token (parser)->location; + parens.skip_until_found_close (parser); + tree type = groktypename (t1, NULL, NULL); + expr.value = objc_build_encode_expr (type); + set_c_expr_source_range (&expr, loc, close_loc); + } + break; + case RID_GENERIC: + expr = c_parser_generic_selection (parser); + break; + default: + c_parser_error (parser, "expected expression"); + expr.set_error (); + break; + } + break; + case CPP_OPEN_SQUARE: + if (c_dialect_objc ()) + { + tree receiver, args; + c_parser_consume_token (parser); + receiver = c_parser_objc_receiver (parser); + args = c_parser_objc_message_args (parser); + location_t close_loc = c_parser_peek_token (parser)->location; + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + expr.value = objc_build_message_expr (receiver, args); + set_c_expr_source_range (&expr, loc, close_loc); + break; + } + /* Else fall through to report error. */ + /* FALLTHRU */ + default: + c_parser_error (parser, "expected expression"); + expr.set_error (); + break; + } + out: + return c_parser_postfix_expression_after_primary + (parser, EXPR_LOC_OR_LOC (expr.value, loc), expr); +} + +/* Parse a postfix expression after a parenthesized type name: the + brace-enclosed initializer of a compound literal, possibly followed + by some postfix operators. This is separate because it is not + possible to tell until after the type name whether a cast + expression has a cast or a compound literal, or whether the operand + of sizeof is a parenthesized type name or starts with a compound + literal. TYPE_LOC is the location where TYPE_NAME starts--the + location of the first token after the parentheses around the type + name. */ + +static struct c_expr +c_parser_postfix_expression_after_paren_type (c_parser *parser, + struct c_type_name *type_name, + location_t type_loc) +{ + tree type; + struct c_expr init; + bool non_const; + struct c_expr expr; + location_t start_loc; + tree type_expr = NULL_TREE; + bool type_expr_const = true; + check_compound_literal_type (type_loc, type_name); + rich_location richloc (line_table, type_loc); + start_init (NULL_TREE, NULL, 0, &richloc); + type = groktypename (type_name, &type_expr, &type_expr_const); + start_loc = c_parser_peek_token (parser)->location; + if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) + { + error_at (type_loc, "compound literal has variable size"); + type = error_mark_node; + } + init = c_parser_braced_init (parser, type, false, NULL); + finish_init (); + maybe_warn_string_init (type_loc, type, init); + + if (type != error_mark_node + && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)) + && current_function_decl) + { + error ("compound literal qualified by address-space qualifier"); + type = error_mark_node; + } + + pedwarn_c90 (start_loc, OPT_Wpedantic, "ISO C90 forbids compound literals"); + non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) + ? CONSTRUCTOR_NON_CONST (init.value) + : init.original_code == C_MAYBE_CONST_EXPR); + non_const |= !type_expr_const; + unsigned int alignas_align = 0; + if (type != error_mark_node + && type_name->specs->align_log != -1) + { + alignas_align = 1U << type_name->specs->align_log; + if (alignas_align < min_align_of_type (type)) + { + error_at (type_name->specs->locations[cdw_alignas], + "%<_Alignas%> specifiers cannot reduce " + "alignment of compound literal"); + alignas_align = 0; + } + } + expr.value = build_compound_literal (start_loc, type, init.value, non_const, + alignas_align); + set_c_expr_source_range (&expr, init.src_range); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + if (type != error_mark_node + && expr.value != error_mark_node + && type_expr) + { + if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR) + { + gcc_assert (C_MAYBE_CONST_EXPR_PRE (expr.value) == NULL_TREE); + C_MAYBE_CONST_EXPR_PRE (expr.value) = type_expr; + } + else + { + gcc_assert (!non_const); + expr.value = build2 (C_MAYBE_CONST_EXPR, type, + type_expr, expr.value); + } + } + return c_parser_postfix_expression_after_primary (parser, start_loc, expr); +} + +/* Callback function for sizeof_pointer_memaccess_warning to compare + types. */ + +static bool +sizeof_ptr_memacc_comptypes (tree type1, tree type2) +{ + return comptypes (type1, type2) == 1; +} + +/* Warn for patterns where abs-like function appears to be used incorrectly, + gracefully ignore any non-abs-like function. The warning location should + be LOC. FNDECL is the declaration of called function, it must be a + BUILT_IN_NORMAL function. ARG is the first and only argument of the + call. */ + +static void +warn_for_abs (location_t loc, tree fndecl, tree arg) +{ + /* Avoid warning in unreachable subexpressions. */ + if (c_inhibit_evaluation_warnings) + return; + + tree atype = TREE_TYPE (arg); + + /* Casts from pointers (and thus arrays and fndecls) will generate + -Wint-conversion warnings. Most other wrong types hopefully lead to type + mismatch errors. TODO: Think about what to do with FIXED_POINT_TYPE_P + types and possibly other exotic types. */ + if (!INTEGRAL_TYPE_P (atype) + && !SCALAR_FLOAT_TYPE_P (atype) + && TREE_CODE (atype) != COMPLEX_TYPE) + return; + + enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); + + switch (fcode) + { + case BUILT_IN_ABS: + case BUILT_IN_LABS: + case BUILT_IN_LLABS: + case BUILT_IN_IMAXABS: + if (!INTEGRAL_TYPE_P (atype)) + { + if (SCALAR_FLOAT_TYPE_P (atype)) + warning_at (loc, OPT_Wabsolute_value, + "using integer absolute value function %qD when " + "argument is of floating-point type %qT", + fndecl, atype); + else if (TREE_CODE (atype) == COMPLEX_TYPE) + warning_at (loc, OPT_Wabsolute_value, + "using integer absolute value function %qD when " + "argument is of complex type %qT", fndecl, atype); + else + gcc_unreachable (); + return; + } + if (TYPE_UNSIGNED (atype)) + warning_at (loc, OPT_Wabsolute_value, + "taking the absolute value of unsigned type %qT " + "has no effect", atype); + break; + + CASE_FLT_FN (BUILT_IN_FABS): + CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS): + if (!SCALAR_FLOAT_TYPE_P (atype) + || DECIMAL_FLOAT_MODE_P (TYPE_MODE (atype))) + { + if (INTEGRAL_TYPE_P (atype)) + warning_at (loc, OPT_Wabsolute_value, + "using floating-point absolute value function %qD " + "when argument is of integer type %qT", fndecl, atype); + else if (DECIMAL_FLOAT_TYPE_P (atype)) + warning_at (loc, OPT_Wabsolute_value, + "using floating-point absolute value function %qD " + "when argument is of decimal floating-point type %qT", + fndecl, atype); + else if (TREE_CODE (atype) == COMPLEX_TYPE) + warning_at (loc, OPT_Wabsolute_value, + "using floating-point absolute value function %qD when " + "argument is of complex type %qT", fndecl, atype); + else + gcc_unreachable (); + return; + } + break; + + CASE_FLT_FN (BUILT_IN_CABS): + if (TREE_CODE (atype) != COMPLEX_TYPE) + { + if (INTEGRAL_TYPE_P (atype)) + warning_at (loc, OPT_Wabsolute_value, + "using complex absolute value function %qD when " + "argument is of integer type %qT", fndecl, atype); + else if (SCALAR_FLOAT_TYPE_P (atype)) + warning_at (loc, OPT_Wabsolute_value, + "using complex absolute value function %qD when " + "argument is of floating-point type %qT", + fndecl, atype); + else + gcc_unreachable (); + + return; + } + break; + + case BUILT_IN_FABSD32: + case BUILT_IN_FABSD64: + case BUILT_IN_FABSD128: + if (!DECIMAL_FLOAT_TYPE_P (atype)) + { + if (INTEGRAL_TYPE_P (atype)) + warning_at (loc, OPT_Wabsolute_value, + "using decimal floating-point absolute value " + "function %qD when argument is of integer type %qT", + fndecl, atype); + else if (SCALAR_FLOAT_TYPE_P (atype)) + warning_at (loc, OPT_Wabsolute_value, + "using decimal floating-point absolute value " + "function %qD when argument is of floating-point " + "type %qT", fndecl, atype); + else if (TREE_CODE (atype) == COMPLEX_TYPE) + warning_at (loc, OPT_Wabsolute_value, + "using decimal floating-point absolute value " + "function %qD when argument is of complex type %qT", + fndecl, atype); + else + gcc_unreachable (); + return; + } + break; + + default: + return; + } + + if (!TYPE_ARG_TYPES (TREE_TYPE (fndecl))) + return; + + tree ftype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); + if (TREE_CODE (atype) == COMPLEX_TYPE) + { + gcc_assert (TREE_CODE (ftype) == COMPLEX_TYPE); + atype = TREE_TYPE (atype); + ftype = TREE_TYPE (ftype); + } + + if (TYPE_PRECISION (ftype) < TYPE_PRECISION (atype)) + warning_at (loc, OPT_Wabsolute_value, + "absolute value function %qD given an argument of type %qT " + "but has parameter of type %qT which may cause truncation " + "of value", fndecl, atype, ftype); +} + + +/* Parse a postfix expression after the initial primary or compound + literal; that is, parse a series of postfix operators. + + EXPR_LOC is the location of the primary expression. */ + +static struct c_expr +c_parser_postfix_expression_after_primary (c_parser *parser, + location_t expr_loc, + struct c_expr expr) +{ + struct c_expr orig_expr; + tree ident, idx; + location_t sizeof_arg_loc[3], comp_loc; + tree sizeof_arg[3]; + unsigned int literal_zero_mask; + unsigned int i; + vec *exprlist; + vec *origtypes = NULL; + vec arg_loc = vNULL; + location_t start; + location_t finish; + + while (true) + { + location_t op_loc = c_parser_peek_token (parser)->location; + switch (c_parser_peek_token (parser)->type) + { + case CPP_OPEN_SQUARE: + /* Array reference. */ + c_parser_consume_token (parser); + idx = c_parser_expression (parser).value; + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + start = expr.get_start (); + finish = parser->tokens_buf[0].location; + expr.value = build_array_ref (op_loc, expr.value, idx); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + break; + case CPP_OPEN_PAREN: + /* Function call. */ + { + matching_parens parens; + parens.consume_open (parser); + for (i = 0; i < 3; i++) + { + sizeof_arg[i] = NULL_TREE; + sizeof_arg_loc[i] = UNKNOWN_LOCATION; + } + literal_zero_mask = 0; + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + exprlist = NULL; + else + exprlist = c_parser_expr_list (parser, true, false, &origtypes, + sizeof_arg_loc, sizeof_arg, + &arg_loc, &literal_zero_mask); + parens.skip_until_found_close (parser); + } + orig_expr = expr; + mark_exp_read (expr.value); + if (warn_sizeof_pointer_memaccess) + sizeof_pointer_memaccess_warning (sizeof_arg_loc, + expr.value, exprlist, + sizeof_arg, + sizeof_ptr_memacc_comptypes); + if (TREE_CODE (expr.value) == FUNCTION_DECL) + { + if (fndecl_built_in_p (expr.value, BUILT_IN_MEMSET) + && vec_safe_length (exprlist) == 3) + { + tree arg0 = (*exprlist)[0]; + tree arg2 = (*exprlist)[2]; + warn_for_memset (expr_loc, arg0, arg2, literal_zero_mask); + } + if (warn_absolute_value + && fndecl_built_in_p (expr.value, BUILT_IN_NORMAL) + && vec_safe_length (exprlist) == 1) + warn_for_abs (expr_loc, expr.value, (*exprlist)[0]); + } + + start = expr.get_start (); + finish = parser->tokens_buf[0].get_finish (); + expr.value + = c_build_function_call_vec (expr_loc, arg_loc, expr.value, + exprlist, origtypes); + set_c_expr_source_range (&expr, start, finish); + + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) == INTEGER_CST + && TREE_CODE (orig_expr.value) == FUNCTION_DECL + && fndecl_built_in_p (orig_expr.value, BUILT_IN_CONSTANT_P)) + expr.original_code = C_MAYBE_CONST_EXPR; + expr.original_type = NULL; + if (exprlist) + { + release_tree_vector (exprlist); + release_tree_vector (origtypes); + } + arg_loc.release (); + break; + case CPP_DOT: + /* Structure element reference. */ + c_parser_consume_token (parser); + expr = default_function_array_conversion (expr_loc, expr); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *comp_tok = c_parser_peek_token (parser); + ident = comp_tok->value; + comp_loc = comp_tok->location; + } + else + { + c_parser_error (parser, "expected identifier"); + expr.set_error (); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + return expr; + } + start = expr.get_start (); + finish = c_parser_peek_token (parser)->get_finish (); + c_parser_consume_token (parser); + expr.value = build_component_ref (op_loc, expr.value, ident, + comp_loc); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } + break; + case CPP_DEREF: + /* Structure element reference. */ + c_parser_consume_token (parser); + expr = convert_lvalue_to_rvalue (expr_loc, expr, true, false); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *comp_tok = c_parser_peek_token (parser); + ident = comp_tok->value; + comp_loc = comp_tok->location; + } + else + { + c_parser_error (parser, "expected identifier"); + expr.set_error (); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + return expr; + } + start = expr.get_start (); + finish = c_parser_peek_token (parser)->get_finish (); + c_parser_consume_token (parser); + expr.value = build_component_ref (op_loc, + build_indirect_ref (op_loc, + expr.value, + RO_ARROW), + ident, comp_loc); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } + break; + case CPP_PLUS_PLUS: + /* Postincrement. */ + start = expr.get_start (); + finish = c_parser_peek_token (parser)->get_finish (); + c_parser_consume_token (parser); + expr = default_function_array_read_conversion (expr_loc, expr); + expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR, + expr.value, false); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + break; + case CPP_MINUS_MINUS: + /* Postdecrement. */ + start = expr.get_start (); + finish = c_parser_peek_token (parser)->get_finish (); + c_parser_consume_token (parser); + expr = default_function_array_read_conversion (expr_loc, expr); + expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR, + expr.value, false); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + break; + default: + return expr; + } + } +} + +/* Parse an expression (C90 6.3.17, C99 6.5.17, C11 6.5.17). + + expression: + assignment-expression + expression , assignment-expression +*/ + +static struct c_expr +c_parser_expression (c_parser *parser) +{ + location_t tloc = c_parser_peek_token (parser)->location; + struct c_expr expr; + expr = c_parser_expr_no_commas (parser, NULL); + if (c_parser_next_token_is (parser, CPP_COMMA)) + expr = convert_lvalue_to_rvalue (tloc, expr, true, false); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + struct c_expr next; + tree lhsval; + location_t loc = c_parser_peek_token (parser)->location; + location_t expr_loc; + c_parser_consume_token (parser); + expr_loc = c_parser_peek_token (parser)->location; + lhsval = expr.value; + while (TREE_CODE (lhsval) == COMPOUND_EXPR + || TREE_CODE (lhsval) == NOP_EXPR) + { + if (TREE_CODE (lhsval) == COMPOUND_EXPR) + lhsval = TREE_OPERAND (lhsval, 1); + else + lhsval = TREE_OPERAND (lhsval, 0); + } + if (DECL_P (lhsval) || handled_component_p (lhsval)) + mark_exp_read (lhsval); + next = c_parser_expr_no_commas (parser, NULL); + next = convert_lvalue_to_rvalue (expr_loc, next, true, false); + expr.value = build_compound_expr (loc, expr.value, next.value); + expr.original_code = COMPOUND_EXPR; + expr.original_type = next.original_type; + } + return expr; +} + +/* Parse an expression and convert functions or arrays to pointers and + lvalues to rvalues. */ + +static struct c_expr +c_parser_expression_conv (c_parser *parser) +{ + struct c_expr expr; + location_t loc = c_parser_peek_token (parser)->location; + expr = c_parser_expression (parser); + expr = convert_lvalue_to_rvalue (loc, expr, true, false); + return expr; +} + +/* Helper function of c_parser_expr_list. Check if IDXth (0 based) + argument is a literal zero alone and if so, set it in literal_zero_mask. */ + +static inline void +c_parser_check_literal_zero (c_parser *parser, unsigned *literal_zero_mask, + unsigned int idx) +{ + if (idx >= HOST_BITS_PER_INT) + return; + + c_token *tok = c_parser_peek_token (parser); + switch (tok->type) + { + case CPP_NUMBER: + case CPP_CHAR: + case CPP_WCHAR: + case CPP_CHAR16: + case CPP_CHAR32: + case CPP_UTF8CHAR: + /* If a parameter is literal zero alone, remember it + for -Wmemset-transposed-args warning. */ + if (integer_zerop (tok->value) + && !TREE_OVERFLOW (tok->value) + && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA + || c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN)) + *literal_zero_mask |= 1U << idx; + default: + break; + } +} + +/* Parse a non-empty list of expressions. If CONVERT_P, convert + functions and arrays to pointers and lvalues to rvalues. If + FOLD_P, fold the expressions. If LOCATIONS is non-NULL, save the + locations of function arguments into this vector. + + nonempty-expr-list: + assignment-expression + nonempty-expr-list , assignment-expression +*/ + +static vec * +c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, + vec **p_orig_types, + location_t *sizeof_arg_loc, tree *sizeof_arg, + vec *locations, + unsigned int *literal_zero_mask) +{ + vec *ret; + vec *orig_types; + struct c_expr expr; + unsigned int idx = 0; + + ret = make_tree_vector (); + if (p_orig_types == NULL) + orig_types = NULL; + else + orig_types = make_tree_vector (); + + if (literal_zero_mask) + c_parser_check_literal_zero (parser, literal_zero_mask, 0); + expr = c_parser_expr_no_commas (parser, NULL); + if (convert_p) + expr = convert_lvalue_to_rvalue (expr.get_location (), expr, true, true); + if (fold_p) + expr.value = c_fully_fold (expr.value, false, NULL); + ret->quick_push (expr.value); + if (orig_types) + orig_types->quick_push (expr.original_type); + if (locations) + locations->safe_push (expr.get_location ()); + if (sizeof_arg != NULL + && (expr.original_code == SIZEOF_EXPR + || expr.original_code == PAREN_SIZEOF_EXPR)) + { + sizeof_arg[0] = c_last_sizeof_arg; + sizeof_arg_loc[0] = c_last_sizeof_loc; + } + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + if (literal_zero_mask) + c_parser_check_literal_zero (parser, literal_zero_mask, idx + 1); + expr = c_parser_expr_no_commas (parser, NULL); + if (convert_p) + expr = convert_lvalue_to_rvalue (expr.get_location (), expr, true, + true); + if (fold_p) + expr.value = c_fully_fold (expr.value, false, NULL); + vec_safe_push (ret, expr.value); + if (orig_types) + vec_safe_push (orig_types, expr.original_type); + if (locations) + locations->safe_push (expr.get_location ()); + if (++idx < 3 + && sizeof_arg != NULL + && (expr.original_code == SIZEOF_EXPR + || expr.original_code == PAREN_SIZEOF_EXPR)) + { + sizeof_arg[idx] = c_last_sizeof_arg; + sizeof_arg_loc[idx] = c_last_sizeof_loc; + } + } + if (orig_types) + *p_orig_types = orig_types; + return ret; +} + +/* Parse Objective-C-specific constructs. */ + +/* Parse an objc-class-definition. + + objc-class-definition: + @interface identifier objc-superclass[opt] objc-protocol-refs[opt] + objc-class-instance-variables[opt] objc-methodprotolist @end + @implementation identifier objc-superclass[opt] + objc-class-instance-variables[opt] + @interface identifier ( identifier ) objc-protocol-refs[opt] + objc-methodprotolist @end + @interface identifier ( ) objc-protocol-refs[opt] + objc-methodprotolist @end + @implementation identifier ( identifier ) + + objc-superclass: + : identifier + + "@interface identifier (" must start "@interface identifier ( + identifier ) ...": objc-methodprotolist in the first production may + not start with a parenthesized identifier as a declarator of a data + definition with no declaration specifiers if the objc-superclass, + objc-protocol-refs and objc-class-instance-variables are omitted. */ + +static void +c_parser_objc_class_definition (c_parser *parser, tree attributes) +{ + bool iface_p; + tree id1; + tree superclass; + if (c_parser_next_token_is_keyword (parser, RID_AT_INTERFACE)) + iface_p = true; + else if (c_parser_next_token_is_keyword (parser, RID_AT_IMPLEMENTATION)) + iface_p = false; + else + gcc_unreachable (); + + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + return; + } + id1 = c_parser_peek_token (parser)->value; + location_t loc1 = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + /* We have a category or class extension. */ + tree id2; + tree proto = NULL_TREE; + matching_parens parens; + parens.consume_open (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + /* We have a class extension. */ + id2 = NULL_TREE; + } + else + { + c_parser_error (parser, "expected identifier or %<)%>"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return; + } + } + else + { + id2 = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + parens.skip_until_found_close (parser); + if (!iface_p) + { + objc_start_category_implementation (id1, id2); + return; + } + if (c_parser_next_token_is (parser, CPP_LESS)) + proto = c_parser_objc_protocol_refs (parser); + objc_start_category_interface (id1, id2, proto, attributes); + c_parser_objc_methodprotolist (parser); + c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); + objc_finish_interface (); + return; + } + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + return; + } + superclass = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + superclass = NULL_TREE; + if (iface_p) + { + tree proto = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_LESS)) + proto = c_parser_objc_protocol_refs (parser); + objc_start_class_interface (id1, loc1, superclass, proto, attributes); + } + else + objc_start_class_implementation (id1, superclass); + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + c_parser_objc_class_instance_variables (parser); + if (iface_p) + { + objc_continue_interface (); + c_parser_objc_methodprotolist (parser); + c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); + objc_finish_interface (); + } + else + { + objc_continue_implementation (); + return; + } +} + +/* Parse objc-class-instance-variables. + + objc-class-instance-variables: + { objc-instance-variable-decl-list[opt] } + + objc-instance-variable-decl-list: + objc-visibility-spec + objc-instance-variable-decl ; + ; + objc-instance-variable-decl-list objc-visibility-spec + objc-instance-variable-decl-list objc-instance-variable-decl ; + objc-instance-variable-decl-list ; + + objc-visibility-spec: + @private + @protected + @public + + objc-instance-variable-decl: + struct-declaration +*/ + +static void +c_parser_objc_class_instance_variables (c_parser *parser) +{ + gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); + c_parser_consume_token (parser); + while (c_parser_next_token_is_not (parser, CPP_EOF)) + { + tree decls; + /* Parse any stray semicolon. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "extra semicolon"); + c_parser_consume_token (parser); + continue; + } + /* Stop if at the end of the instance variables. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + c_parser_consume_token (parser); + break; + } + /* Parse any objc-visibility-spec. */ + if (c_parser_next_token_is_keyword (parser, RID_AT_PRIVATE)) + { + c_parser_consume_token (parser); + objc_set_visibility (OBJC_IVAR_VIS_PRIVATE); + continue; + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED)) + { + c_parser_consume_token (parser); + objc_set_visibility (OBJC_IVAR_VIS_PROTECTED); + continue; + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_PUBLIC)) + { + c_parser_consume_token (parser); + objc_set_visibility (OBJC_IVAR_VIS_PUBLIC); + continue; + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_PACKAGE)) + { + c_parser_consume_token (parser); + objc_set_visibility (OBJC_IVAR_VIS_PACKAGE); + continue; + } + else if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + c_parser_pragma (parser, pragma_external, NULL); + continue; + } + + /* Parse some comma-separated declarations. */ + decls = c_parser_struct_declaration (parser); + if (decls == NULL) + { + /* There is a syntax error. We want to skip the offending + tokens up to the next ';' (included) or '}' + (excluded). */ + + /* First, skip manually a ')' or ']'. This is because they + reduce the nesting level, so c_parser_skip_until_found() + wouldn't be able to skip past them. */ + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_CLOSE_PAREN || token->type == CPP_CLOSE_SQUARE) + c_parser_consume_token (parser); + + /* Then, do the standard skipping. */ + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + + /* We hopefully recovered. Start normal parsing again. */ + parser->error = false; + continue; + } + else + { + /* Comma-separated instance variables are chained together + in reverse order; add them one by one. */ + tree ivar = nreverse (decls); + for (; ivar; ivar = DECL_CHAIN (ivar)) + objc_add_instance_variable (copy_node (ivar)); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } +} + +/* Parse an objc-class-declaration. + + objc-class-declaration: + @class identifier-list ; +*/ + +static void +c_parser_objc_class_declaration (c_parser *parser) +{ + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_CLASS)); + c_parser_consume_token (parser); + /* Any identifiers, including those declared as type names, are OK + here. */ + while (true) + { + tree id; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; + } + id = c_parser_peek_token (parser)->value; + objc_declare_class (id); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); +} + +/* Parse an objc-alias-declaration. + + objc-alias-declaration: + @compatibility_alias identifier identifier ; +*/ + +static void +c_parser_objc_alias_declaration (c_parser *parser) +{ + tree id1, id2; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_ALIAS)); + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + return; + } + id1 = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + return; + } + id2 = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + objc_declare_alias (id1, id2); +} + +/* Parse an objc-protocol-definition. + + objc-protocol-definition: + @protocol identifier objc-protocol-refs[opt] objc-methodprotolist @end + @protocol identifier-list ; + + "@protocol identifier ;" should be resolved as "@protocol + identifier-list ;": objc-methodprotolist may not start with a + semicolon in the first alternative if objc-protocol-refs are + omitted. */ + +static void +c_parser_objc_protocol_definition (c_parser *parser, tree attributes) +{ + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL)); + + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + return; + } + if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA + || c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON) + { + /* Any identifiers, including those declared as type names, are + OK here. */ + while (true) + { + tree id; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + id = c_parser_peek_token (parser)->value; + objc_declare_protocol (id, attributes); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + tree id = c_parser_peek_token (parser)->value; + tree proto = NULL_TREE; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_LESS)) + proto = c_parser_objc_protocol_refs (parser); + parser->objc_pq_context = true; + objc_start_protocol (id, proto, attributes); + c_parser_objc_methodprotolist (parser); + c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); + parser->objc_pq_context = false; + objc_finish_interface (); + } +} + +/* Parse an objc-method-type. + + objc-method-type: + + + - + + Return true if it is a class method (+) and false if it is + an instance method (-). +*/ +static inline bool +c_parser_objc_method_type (c_parser *parser) +{ + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + c_parser_consume_token (parser); + return true; + case CPP_MINUS: + c_parser_consume_token (parser); + return false; + default: + gcc_unreachable (); + } +} + +/* Parse an objc-method-definition. + + objc-method-definition: + objc-method-type objc-method-decl ;[opt] compound-statement +*/ + +static void +c_parser_objc_method_definition (c_parser *parser) +{ + bool is_class_method = c_parser_objc_method_type (parser); + tree decl, attributes = NULL_TREE, expr = NULL_TREE; + parser->objc_pq_context = true; + decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, + &expr); + if (decl == error_mark_node) + return; /* Bail here. */ + + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_parser_consume_token (parser); + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "extra semicolon in method definition specified"); + } + + if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + c_parser_error (parser, "expected %<{%>"); + return; + } + + parser->objc_pq_context = false; + if (objc_start_method_definition (is_class_method, decl, attributes, expr)) + { + add_stmt (c_parser_compound_statement (parser)); + objc_finish_method_definition (current_function_decl); + } + else + { + /* This code is executed when we find a method definition + outside of an @implementation context (or invalid for other + reasons). Parse the method (to keep going) but do not emit + any code. + */ + c_parser_compound_statement (parser); + } +} + +/* Parse an objc-methodprotolist. + + objc-methodprotolist: + empty + objc-methodprotolist objc-methodproto + objc-methodprotolist declaration + objc-methodprotolist ; + @optional + @required + + The declaration is a data definition, which may be missing + declaration specifiers under the same rules and diagnostics as + other data definitions outside functions, and the stray semicolon + is diagnosed the same way as a stray semicolon outside a + function. */ + +static void +c_parser_objc_methodprotolist (c_parser *parser) +{ + while (true) + { + /* The list is terminated by @end. */ + switch (c_parser_peek_token (parser)->type) + { + case CPP_SEMICOLON: + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "ISO C does not allow extra %<;%> outside of a function"); + c_parser_consume_token (parser); + break; + case CPP_PLUS: + case CPP_MINUS: + c_parser_objc_methodproto (parser); + break; + case CPP_PRAGMA: + c_parser_pragma (parser, pragma_external, NULL); + break; + case CPP_EOF: + return; + default: + if (c_parser_next_token_is_keyword (parser, RID_AT_END)) + return; + else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)) + c_parser_objc_at_property_declaration (parser); + else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL)) + { + objc_set_method_opt (true); + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_REQUIRED)) + { + objc_set_method_opt (false); + c_parser_consume_token (parser); + } + else + c_parser_declaration_or_fndef (parser, false, false, true, + false, true); + break; + } + } +} + +/* Parse an objc-methodproto. + + objc-methodproto: + objc-method-type objc-method-decl ; +*/ + +static void +c_parser_objc_methodproto (c_parser *parser) +{ + bool is_class_method = c_parser_objc_method_type (parser); + tree decl, attributes = NULL_TREE; + + /* Remember protocol qualifiers in prototypes. */ + parser->objc_pq_context = true; + decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, + NULL); + /* Forget protocol qualifiers now. */ + parser->objc_pq_context = false; + + /* Do not allow the presence of attributes to hide an erroneous + method implementation in the interface section. */ + if (!c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_parser_error (parser, "expected %<;%>"); + return; + } + + if (decl != error_mark_node) + objc_add_method_declaration (is_class_method, decl, attributes); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); +} + +/* If we are at a position that method attributes may be present, check that + there are not any parsed already (a syntax error) and then collect any + specified at the current location. Finally, if new attributes were present, + check that the next token is legal ( ';' for decls and '{' for defs). */ + +static bool +c_parser_objc_maybe_method_attributes (c_parser* parser, tree* attributes) +{ + bool bad = false; + if (*attributes) + { + c_parser_error (parser, + "method attributes must be specified at the end only"); + *attributes = NULL_TREE; + bad = true; + } + + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + *attributes = c_parser_gnu_attributes (parser); + + /* If there were no attributes here, just report any earlier error. */ + if (*attributes == NULL_TREE || bad) + return bad; + + /* If the attributes are followed by a ; or {, then just report any earlier + error. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + return bad; + + /* We've got attributes, but not at the end. */ + c_parser_error (parser, + "expected %<;%> or %<{%> after method attribute definition"); + return true; +} + +/* Parse an objc-method-decl. + + objc-method-decl: + ( objc-type-name ) objc-selector + objc-selector + ( objc-type-name ) objc-keyword-selector objc-optparmlist + objc-keyword-selector objc-optparmlist + gnu-attributes + + objc-keyword-selector: + objc-keyword-decl + objc-keyword-selector objc-keyword-decl + + objc-keyword-decl: + objc-selector : ( objc-type-name ) identifier + objc-selector : identifier + : ( objc-type-name ) identifier + : identifier + + objc-optparmlist: + objc-optparms objc-optellipsis + + objc-optparms: + empty + objc-opt-parms , parameter-declaration + + objc-optellipsis: + empty + , ... +*/ + +static tree +c_parser_objc_method_decl (c_parser *parser, bool is_class_method, + tree *attributes, tree *expr) +{ + tree type = NULL_TREE; + tree sel; + tree parms = NULL_TREE; + bool ellipsis = false; + bool attr_err = false; + + *attributes = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + matching_parens parens; + parens.consume_open (parser); + type = c_parser_objc_type_name (parser); + parens.skip_until_found_close (parser); + } + sel = c_parser_objc_selector (parser); + /* If there is no selector, or a colon follows, we have an + objc-keyword-selector. If there is a selector, and a colon does + not follow, that selector ends the objc-method-decl. */ + if (!sel || c_parser_next_token_is (parser, CPP_COLON)) + { + tree tsel = sel; + tree list = NULL_TREE; + while (true) + { + tree atype = NULL_TREE, id, keyworddecl; + tree param_attr = NULL_TREE; + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + break; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + atype = c_parser_objc_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + } + /* New ObjC allows attributes on method parameters. */ + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + param_attr = c_parser_gnu_attributes (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + return error_mark_node; + } + id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + keyworddecl = objc_build_keyword_decl (tsel, atype, id, param_attr); + list = chainon (list, keyworddecl); + tsel = c_parser_objc_selector (parser); + if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON)) + break; + } + + attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; + + /* Parse the optional parameter list. Optional Objective-C + method parameters follow the C syntax, and may include '...' + to denote a variable number of arguments. */ + parms = make_node (TREE_LIST); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + struct c_parm *parm; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + ellipsis = true; + c_parser_consume_token (parser); + attr_err |= c_parser_objc_maybe_method_attributes + (parser, attributes) ; + break; + } + parm = c_parser_parameter_declaration (parser, NULL_TREE, false); + if (parm == NULL) + break; + parms = chainon (parms, + build_tree_list (NULL_TREE, grokparm (parm, expr))); + } + sel = list; + } + else + attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; + + if (sel == NULL) + { + c_parser_error (parser, "objective-c method declaration is expected"); + return error_mark_node; + } + + if (attr_err) + return error_mark_node; + + return objc_build_method_signature (is_class_method, type, sel, parms, ellipsis); +} + +/* Parse an objc-type-name. + + objc-type-name: + objc-type-qualifiers[opt] type-name + objc-type-qualifiers[opt] + + objc-type-qualifiers: + objc-type-qualifier + objc-type-qualifiers objc-type-qualifier + + objc-type-qualifier: one of + in out inout bycopy byref oneway +*/ + +static tree +c_parser_objc_type_name (c_parser *parser) +{ + tree quals = NULL_TREE; + struct c_type_name *type_name = NULL; + tree type = NULL_TREE; + while (true) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_KEYWORD + && (token->keyword == RID_IN + || token->keyword == RID_OUT + || token->keyword == RID_INOUT + || token->keyword == RID_BYCOPY + || token->keyword == RID_BYREF + || token->keyword == RID_ONEWAY)) + { + quals = chainon (build_tree_list (NULL_TREE, token->value), quals); + c_parser_consume_token (parser); + } + else + break; + } + if (c_parser_next_tokens_start_typename (parser, cla_prefer_type)) + type_name = c_parser_type_name (parser); + if (type_name) + type = groktypename (type_name, NULL, NULL); + + /* If the type is unknown, and error has already been produced and + we need to recover from the error. In that case, use NULL_TREE + for the type, as if no type had been specified; this will use the + default type ('id') which is good for error recovery. */ + if (type == error_mark_node) + type = NULL_TREE; + + return build_tree_list (quals, type); +} + +/* Parse objc-protocol-refs. + + objc-protocol-refs: + < identifier-list > +*/ + +static tree +c_parser_objc_protocol_refs (c_parser *parser) +{ + tree list = NULL_TREE; + gcc_assert (c_parser_next_token_is (parser, CPP_LESS)); + c_parser_consume_token (parser); + /* Any identifiers, including those declared as type names, are OK + here. */ + while (true) + { + tree id; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + id = c_parser_peek_token (parser)->value; + list = chainon (list, build_tree_list (NULL_TREE, id)); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_require (parser, CPP_GREATER, "expected %<>%>"); + return list; +} + +/* Parse an objc-try-catch-finally-statement. + + objc-try-catch-finally-statement: + @try compound-statement objc-catch-list[opt] + @try compound-statement objc-catch-list[opt] @finally compound-statement + + objc-catch-list: + @catch ( objc-catch-parameter-declaration ) compound-statement + objc-catch-list @catch ( objc-catch-parameter-declaration ) compound-statement + + objc-catch-parameter-declaration: + parameter-declaration + '...' + + where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS. + + PS: This function is identical to cp_parser_objc_try_catch_finally_statement + for C++. Keep them in sync. */ + +static void +c_parser_objc_try_catch_finally_statement (c_parser *parser) +{ + location_t location; + tree stmt; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY)); + c_parser_consume_token (parser); + location = c_parser_peek_token (parser)->location; + objc_maybe_warn_exceptions (location); + stmt = c_parser_compound_statement (parser); + objc_begin_try_stmt (location, stmt); + + while (c_parser_next_token_is_keyword (parser, RID_AT_CATCH)) + { + struct c_parm *parm; + tree parameter_declaration = error_mark_node; + bool seen_open_paren = false; + + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + seen_open_paren = true; + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + /* We have "@catch (...)" (where the '...' are literally + what is in the code). Skip the '...'. + parameter_declaration is set to NULL_TREE, and + objc_being_catch_clauses() knows that that means + '...'. */ + c_parser_consume_token (parser); + parameter_declaration = NULL_TREE; + } + else + { + /* We have "@catch (NSException *exception)" or something + like that. Parse the parameter declaration. */ + parm = c_parser_parameter_declaration (parser, NULL_TREE, false); + if (parm == NULL) + parameter_declaration = error_mark_node; + else + parameter_declaration = grokparm (parm, NULL); + } + if (seen_open_paren) + parens.require_close (parser); + else + { + /* If there was no open parenthesis, we are recovering from + an error, and we are trying to figure out what mistake + the user has made. */ + + /* If there is an immediate closing parenthesis, the user + probably forgot the opening one (ie, they typed "@catch + NSException *e)". Parse the closing parenthesis and keep + going. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_consume_token (parser); + + /* If these is no immediate closing parenthesis, the user + probably doesn't know that parenthesis are required at + all (ie, they typed "@catch NSException *e"). So, just + forget about the closing parenthesis and keep going. */ + } + objc_begin_catch_clause (parameter_declaration); + if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + c_parser_compound_statement_nostart (parser); + objc_finish_catch_clause (); + } + if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY)) + { + c_parser_consume_token (parser); + location = c_parser_peek_token (parser)->location; + stmt = c_parser_compound_statement (parser); + objc_build_finally_clause (location, stmt); + } + objc_finish_try_stmt (); +} + +/* Parse an objc-synchronized-statement. + + objc-synchronized-statement: + @synchronized ( expression ) compound-statement +*/ + +static void +c_parser_objc_synchronized_statement (c_parser *parser) +{ + location_t loc; + tree expr, stmt; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED)); + c_parser_consume_token (parser); + loc = c_parser_peek_token (parser)->location; + objc_maybe_warn_exceptions (loc); + matching_parens parens; + if (parens.require_open (parser)) + { + struct c_expr ce = c_parser_expression (parser); + ce = convert_lvalue_to_rvalue (loc, ce, false, false); + expr = ce.value; + expr = c_fully_fold (expr, false, NULL); + parens.skip_until_found_close (parser); + } + else + expr = error_mark_node; + stmt = c_parser_compound_statement (parser); + objc_build_synchronized (loc, expr, stmt); +} + +/* Parse an objc-selector; return NULL_TREE without an error if the + next token is not an objc-selector. + + objc-selector: + identifier + one of + enum struct union if else while do for switch case default + break continue return goto asm sizeof typeof __alignof + unsigned long const short volatile signed restrict _Complex + in out inout bycopy byref oneway int char float double void _Bool + _Atomic + + ??? Why this selection of keywords but not, for example, storage + class specifiers? */ + +static tree +c_parser_objc_selector (c_parser *parser) +{ + c_token *token = c_parser_peek_token (parser); + tree value = token->value; + if (token->type == CPP_NAME) + { + c_parser_consume_token (parser); + return value; + } + if (token->type != CPP_KEYWORD) + return NULL_TREE; + switch (token->keyword) + { + case RID_ENUM: + case RID_STRUCT: + case RID_UNION: + case RID_IF: + case RID_ELSE: + case RID_WHILE: + case RID_DO: + case RID_FOR: + case RID_SWITCH: + case RID_CASE: + case RID_DEFAULT: + case RID_BREAK: + case RID_CONTINUE: + case RID_RETURN: + case RID_GOTO: + case RID_ASM: + case RID_SIZEOF: + case RID_TYPEOF: + case RID_ALIGNOF: + case RID_UNSIGNED: + case RID_LONG: + case RID_CONST: + case RID_SHORT: + case RID_VOLATILE: + case RID_SIGNED: + case RID_RESTRICT: + case RID_COMPLEX: + case RID_IN: + case RID_OUT: + case RID_INOUT: + case RID_BYCOPY: + case RID_BYREF: + case RID_ONEWAY: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + CASE_RID_FLOATN_NX: + case RID_VOID: + case RID_BOOL: + case RID_ATOMIC: + case RID_AUTO_TYPE: + case RID_INT_N_0: + case RID_INT_N_1: + case RID_INT_N_2: + case RID_INT_N_3: + c_parser_consume_token (parser); + return value; + default: + return NULL_TREE; + } +} + +/* Parse an objc-selector-arg. + + objc-selector-arg: + objc-selector + objc-keywordname-list + + objc-keywordname-list: + objc-keywordname + objc-keywordname-list objc-keywordname + + objc-keywordname: + objc-selector : + : +*/ + +static tree +c_parser_objc_selector_arg (c_parser *parser) +{ + tree sel = c_parser_objc_selector (parser); + tree list = NULL_TREE; + if (sel + && c_parser_next_token_is_not (parser, CPP_COLON) + && c_parser_next_token_is_not (parser, CPP_SCOPE)) + return sel; + while (true) + { + if (c_parser_next_token_is (parser, CPP_SCOPE)) + { + c_parser_consume_token (parser); + list = chainon (list, build_tree_list (sel, NULL_TREE)); + list = chainon (list, build_tree_list (NULL_TREE, NULL_TREE)); + } + else + { + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + return list; + list = chainon (list, build_tree_list (sel, NULL_TREE)); + } + sel = c_parser_objc_selector (parser); + if (!sel + && c_parser_next_token_is_not (parser, CPP_COLON) + && c_parser_next_token_is_not (parser, CPP_SCOPE)) + break; + } + return list; +} + +/* Parse an objc-receiver. + + objc-receiver: + expression + class-name + type-name +*/ + +static tree +c_parser_objc_receiver (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + + if (c_parser_peek_token (parser)->type == CPP_NAME + && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME + || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) + { + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + return objc_get_class_reference (id); + } + struct c_expr ce = c_parser_expression (parser); + ce = convert_lvalue_to_rvalue (loc, ce, false, false); + return c_fully_fold (ce.value, false, NULL); +} + +/* Parse objc-message-args. + + objc-message-args: + objc-selector + objc-keywordarg-list + + objc-keywordarg-list: + objc-keywordarg + objc-keywordarg-list objc-keywordarg + + objc-keywordarg: + objc-selector : objc-keywordexpr + : objc-keywordexpr +*/ + +static tree +c_parser_objc_message_args (c_parser *parser) +{ + tree sel = c_parser_objc_selector (parser); + tree list = NULL_TREE; + if (sel && c_parser_next_token_is_not (parser, CPP_COLON)) + return sel; + while (true) + { + tree keywordexpr; + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + return error_mark_node; + keywordexpr = c_parser_objc_keywordexpr (parser); + list = chainon (list, build_tree_list (sel, keywordexpr)); + sel = c_parser_objc_selector (parser); + if (!sel && c_parser_next_token_is_not (parser, CPP_COLON)) + break; + } + return list; +} + +/* Parse an objc-keywordexpr. + + objc-keywordexpr: + nonempty-expr-list +*/ + +static tree +c_parser_objc_keywordexpr (c_parser *parser) +{ + tree ret; + vec *expr_list = c_parser_expr_list (parser, true, true, + NULL, NULL, NULL, NULL); + if (vec_safe_length (expr_list) == 1) + { + /* Just return the expression, remove a level of + indirection. */ + ret = (*expr_list)[0]; + } + else + { + /* We have a comma expression, we will collapse later. */ + ret = build_tree_list_vec (expr_list); + } + release_tree_vector (expr_list); + return ret; +} + +/* A check, needed in several places, that ObjC interface, implementation or + method definitions are not prefixed by incorrect items. */ +static bool +c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, + struct c_declspecs *specs) +{ + if (!specs->declspecs_seen_p || specs->non_sc_seen_p + || specs->typespec_kind != ctsk_none) + { + c_parser_error (parser, + "no type or storage class may be specified here,"); + c_parser_skip_to_end_of_block_or_statement (parser); + return true; + } + return false; +} + +/* Parse an Objective-C @property declaration. The syntax is: + + objc-property-declaration: + '@property' objc-property-attributes[opt] struct-declaration ; + + objc-property-attributes: + '(' objc-property-attribute-list ')' + + objc-property-attribute-list: + objc-property-attribute + objc-property-attribute-list, objc-property-attribute + + objc-property-attribute + 'getter' = identifier + 'setter' = identifier + 'readonly' + 'readwrite' + 'assign' + 'retain' + 'copy' + 'nonatomic' + + For example: + @property NSString *name; + @property (readonly) id object; + @property (retain, nonatomic, getter=getTheName) id name; + @property int a, b, c; + + PS: This function is identical to cp_parser_objc_at_propery_declaration + for C++. Keep them in sync. */ +static void +c_parser_objc_at_property_declaration (c_parser *parser) +{ + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)); + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); /* Eat '@property'. */ + + /* Parse the optional attribute list. + + A list of parsed, but not verified, attributes. */ + vec prop_attr_list = vNULL; + + bool syntax_error = false; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + matching_parens parens; + + location_t attr_start = c_parser_peek_token (parser)->location; + /* Eat the '(' */ + parens.consume_open (parser); + + /* Property attribute keywords are valid now. */ + parser->objc_property_attr_context = true; + + /* Allow @property (), with a warning. */ + location_t attr_end = c_parser_peek_token (parser)->location; + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + location_t attr_comb = make_location (attr_end, attr_start, attr_end); + warning_at (attr_comb, OPT_Wattributes, + "empty property attribute list"); + } + else + while (true) + { + c_token *token = c_parser_peek_token (parser); + attr_start = token->location; + attr_end = get_finish (token->location); + location_t attr_comb = make_location (attr_start, attr_start, + attr_end); + + if (token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA) + { + warning_at (attr_comb, OPT_Wattributes, + "missing property attribute"); + if (token->type == CPP_CLOSE_PAREN) + break; + c_parser_consume_token (parser); + continue; + } + + tree attr_name = NULL_TREE; + enum rid keyword = RID_MAX; /* Not a valid property attribute. */ + bool add_at = false; + if (token->type == CPP_KEYWORD) + { + keyword = token->keyword; + if (OBJC_IS_AT_KEYWORD (keyword)) + { + /* For '@' keywords the token value has the keyword, + prepend the '@' for diagnostics. */ + attr_name = token->value; + add_at = true; + } + else + attr_name = ridpointers[(int)keyword]; + } + else if (token->type == CPP_NAME) + attr_name = token->value; + c_parser_consume_token (parser); + + enum objc_property_attribute_kind prop_kind + = objc_prop_attr_kind_for_rid (keyword); + property_attribute_info *prop + = new property_attribute_info (attr_name, attr_comb, prop_kind); + prop_attr_list.safe_push (prop); + + tree meth_name; + switch (prop->prop_kind) + { + default: break; + case OBJC_PROPERTY_ATTR_UNKNOWN: + if (attr_name) + error_at (attr_comb, "unknown property attribute %<%s%s%>", + add_at ? "@" : "", IDENTIFIER_POINTER (attr_name)); + else + error_at (attr_comb, "unknown property attribute"); + prop->parse_error = syntax_error = true; + break; + + case OBJC_PROPERTY_ATTR_GETTER: + case OBJC_PROPERTY_ATTR_SETTER: + if (c_parser_next_token_is_not (parser, CPP_EQ)) + { + attr_comb = make_location (attr_end, attr_start, attr_end); + error_at (attr_comb, "expected %<=%> after Objective-C %qE", + attr_name); + prop->parse_error = syntax_error = true; + break; + } + token = c_parser_peek_token (parser); + attr_end = token->location; + c_parser_consume_token (parser); /* eat the = */ + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + attr_comb = make_location (attr_end, attr_start, attr_end); + error_at (attr_comb, "expected %qE selector name", + attr_name); + prop->parse_error = syntax_error = true; + break; + } + /* Get the end of the method name, and consume the name. */ + token = c_parser_peek_token (parser); + attr_end = get_finish (token->location); + meth_name = token->value; + c_parser_consume_token (parser); + if (prop->prop_kind == OBJC_PROPERTY_ATTR_SETTER) + { + if (c_parser_next_token_is_not (parser, CPP_COLON)) + { + attr_comb = make_location (attr_end, attr_start, + attr_end); + error_at (attr_comb, "setter method names must" + " terminate with %<:%>"); + prop->parse_error = syntax_error = true; + } + else + { + attr_end = get_finish (c_parser_peek_token + (parser)->location); + c_parser_consume_token (parser); + } + attr_comb = make_location (attr_start, attr_start, + attr_end); + } + else + attr_comb = make_location (attr_start, attr_start, + attr_end); + prop->ident = meth_name; + /* Updated location including all that was successfully + parsed. */ + prop->prop_loc = attr_comb; + break; + } + + /* If we see a comma here, then keep going - even if we already + saw a syntax error. For simple mistakes e.g. (asign, getter=x) + this makes a more useful output and avoid spurious warnings about + missing attributes that are, in fact, specified after the one with + the syntax error. */ + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + parser->objc_property_attr_context = false; + + if (syntax_error && c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + /* We don't really want to chew the whole of the file looking for a + matching closing parenthesis, so we will try to read the decl and + let the error handling for that close out the statement. */ + ; + else + syntax_error = false, parens.skip_until_found_close (parser); + } + + /* 'properties' is the list of properties that we read. Usually a + single one, but maybe more (eg, in "@property int a, b, c;" there + are three). */ + tree properties = c_parser_struct_declaration (parser); + + if (properties == error_mark_node) + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + else + { + if (properties == NULL_TREE) + c_parser_error (parser, "expected identifier"); + else + { + /* Comma-separated properties are chained together in reverse order; + add them one by one. */ + properties = nreverse (properties); + for (; properties; properties = TREE_CHAIN (properties)) + objc_add_property_declaration (loc, copy_node (properties), + prop_attr_list); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + + while (!prop_attr_list.is_empty()) + delete prop_attr_list.pop (); + prop_attr_list.release (); + parser->error = false; +} + +/* Parse an Objective-C @synthesize declaration. The syntax is: + + objc-synthesize-declaration: + @synthesize objc-synthesize-identifier-list ; + + objc-synthesize-identifier-list: + objc-synthesize-identifier + objc-synthesize-identifier-list, objc-synthesize-identifier + + objc-synthesize-identifier + identifier + identifier = identifier + + For example: + @synthesize MyProperty; + @synthesize OneProperty, AnotherProperty=MyIvar, YetAnotherProperty; + + PS: This function is identical to cp_parser_objc_at_synthesize_declaration + for C++. Keep them in sync. +*/ +static void +c_parser_objc_at_synthesize_declaration (c_parser *parser) +{ + tree list = NULL_TREE; + location_t loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNTHESIZE)); + loc = c_parser_peek_token (parser)->location; + + c_parser_consume_token (parser); + while (true) + { + tree property, ivar; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + /* Once we find the semicolon, we can resume normal parsing. + We have to reset parser->error manually because + c_parser_skip_until_found() won't reset it for us if the + next token is precisely a semicolon. */ + parser->error = false; + return; + } + property = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_EQ)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; + } + ivar = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + ivar = NULL_TREE; + list = chainon (list, build_tree_list (ivar, property)); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + objc_add_synthesize_declaration (loc, list); +} + +/* Parse an Objective-C @dynamic declaration. The syntax is: + + objc-dynamic-declaration: + @dynamic identifier-list ; + + For example: + @dynamic MyProperty; + @dynamic MyProperty, AnotherProperty; + + PS: This function is identical to cp_parser_objc_at_dynamic_declaration + for C++. Keep them in sync. +*/ +static void +c_parser_objc_at_dynamic_declaration (c_parser *parser) +{ + tree list = NULL_TREE; + location_t loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_DYNAMIC)); + loc = c_parser_peek_token (parser)->location; + + c_parser_consume_token (parser); + while (true) + { + tree property; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; + } + property = c_parser_peek_token (parser)->value; + list = chainon (list, build_tree_list (NULL_TREE, property)); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + objc_add_dynamic_declaration (loc, list); +} + + +/* Parse a pragma GCC ivdep. */ + +static bool +c_parse_pragma_ivdep (c_parser *parser) +{ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + return true; +} + +/* Parse a pragma GCC unroll. */ + +static unsigned short +c_parser_pragma_unroll (c_parser *parser) +{ + unsigned short unroll; + c_parser_consume_pragma (parser); + location_t location = c_parser_peek_token (parser)->location; + tree expr = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (expr); + expr = c_fully_fold (expr, false, NULL); + HOST_WIDE_INT lunroll = 0; + if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) + || TREE_CODE (expr) != INTEGER_CST + || (lunroll = tree_to_shwi (expr)) < 0 + || lunroll >= USHRT_MAX) + { + error_at (location, "%<#pragma GCC unroll%> requires an" + " assignment-expression that evaluates to a non-negative" + " integral constant less than %u", USHRT_MAX); + unroll = 0; + } + else + { + unroll = (unsigned short)lunroll; + if (unroll == 0) + unroll = 1; + } + + c_parser_skip_to_pragma_eol (parser); + return unroll; +} + +/* Handle pragmas. Some OpenMP pragmas are associated with, and therefore + should be considered, statements. ALLOW_STMT is true if we're within + the context of a function and such pragmas are to be allowed. Returns + true if we actually parsed such a pragma. */ + +static bool +c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) +{ + unsigned int id; + const char *construct = NULL; + + id = c_parser_peek_token (parser)->pragma_kind; + gcc_assert (id != PRAGMA_NONE); + + switch (id) + { + case PRAGMA_OACC_DECLARE: + c_parser_oacc_declare (parser); + return false; + + case PRAGMA_OACC_ENTER_DATA: + if (context != pragma_compound) + { + construct = "acc enter data"; + in_compound: + if (context == pragma_stmt) + { + error_at (c_parser_peek_token (parser)->location, + "%<#pragma %s%> may only be used in compound " + "statements", construct); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return true; + } + goto bad_stmt; + } + c_parser_oacc_enter_exit_data (parser, true); + return false; + + case PRAGMA_OACC_EXIT_DATA: + if (context != pragma_compound) + { + construct = "acc exit data"; + goto in_compound; + } + c_parser_oacc_enter_exit_data (parser, false); + return false; + + case PRAGMA_OACC_ROUTINE: + if (context != pragma_external) + { + error_at (c_parser_peek_token (parser)->location, + "%<#pragma acc routine%> must be at file scope"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + c_parser_oacc_routine (parser, context); + return false; + + case PRAGMA_OACC_UPDATE: + if (context != pragma_compound) + { + construct = "acc update"; + goto in_compound; + } + c_parser_oacc_update (parser); + return false; + + case PRAGMA_OMP_BARRIER: + if (context != pragma_compound) + { + construct = "omp barrier"; + goto in_compound; + } + c_parser_omp_barrier (parser); + return false; + + case PRAGMA_OMP_DEPOBJ: + if (context != pragma_compound) + { + construct = "omp depobj"; + goto in_compound; + } + c_parser_omp_depobj (parser); + return false; + + case PRAGMA_OMP_FLUSH: + if (context != pragma_compound) + { + construct = "omp flush"; + goto in_compound; + } + c_parser_omp_flush (parser); + return false; + + case PRAGMA_OMP_TASKWAIT: + if (context != pragma_compound) + { + construct = "omp taskwait"; + goto in_compound; + } + c_parser_omp_taskwait (parser); + return false; + + case PRAGMA_OMP_TASKYIELD: + if (context != pragma_compound) + { + construct = "omp taskyield"; + goto in_compound; + } + c_parser_omp_taskyield (parser); + return false; + + case PRAGMA_OMP_CANCEL: + if (context != pragma_compound) + { + construct = "omp cancel"; + goto in_compound; + } + c_parser_omp_cancel (parser); + return false; + + case PRAGMA_OMP_CANCELLATION_POINT: + return c_parser_omp_cancellation_point (parser, context); + + case PRAGMA_OMP_THREADPRIVATE: + c_parser_omp_threadprivate (parser); + return false; + + case PRAGMA_OMP_TARGET: + return c_parser_omp_target (parser, context, if_p); + + case PRAGMA_OMP_END_DECLARE_TARGET: + c_parser_omp_end_declare_target (parser); + return false; + + case PRAGMA_OMP_SCAN: + error_at (c_parser_peek_token (parser)->location, + "%<#pragma omp scan%> may only be used in " + "a loop construct with % % clause"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + + case PRAGMA_OMP_SECTION: + error_at (c_parser_peek_token (parser)->location, + "%<#pragma omp section%> may only be used in " + "%<#pragma omp sections%> construct"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + + case PRAGMA_OMP_DECLARE: + return c_parser_omp_declare (parser, context); + + case PRAGMA_OMP_REQUIRES: + if (context != pragma_external) + { + error_at (c_parser_peek_token (parser)->location, + "%<#pragma omp requires%> may only be used at file scope"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + c_parser_omp_requires (parser); + return false; + + case PRAGMA_OMP_NOTHING: + c_parser_omp_nothing (parser); + return false; + + case PRAGMA_OMP_ERROR: + return c_parser_omp_error (parser, context); + + case PRAGMA_OMP_ORDERED: + return c_parser_omp_ordered (parser, context, if_p); + + case PRAGMA_IVDEP: + { + const bool ivdep = c_parse_pragma_ivdep (parser); + unsigned short unroll; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_UNROLL) + unroll = c_parser_pragma_unroll (parser); + else + unroll = 0; + if (!c_parser_next_token_is_keyword (parser, RID_FOR) + && !c_parser_next_token_is_keyword (parser, RID_WHILE) + && !c_parser_next_token_is_keyword (parser, RID_DO)) + { + c_parser_error (parser, "for, while or do statement expected"); + return false; + } + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + c_parser_for_statement (parser, ivdep, unroll, if_p); + else if (c_parser_next_token_is_keyword (parser, RID_WHILE)) + c_parser_while_statement (parser, ivdep, unroll, if_p); + else + c_parser_do_statement (parser, ivdep, unroll); + } + return true; + + case PRAGMA_UNROLL: + { + unsigned short unroll = c_parser_pragma_unroll (parser); + bool ivdep; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_IVDEP) + ivdep = c_parse_pragma_ivdep (parser); + else + ivdep = false; + if (!c_parser_next_token_is_keyword (parser, RID_FOR) + && !c_parser_next_token_is_keyword (parser, RID_WHILE) + && !c_parser_next_token_is_keyword (parser, RID_DO)) + { + c_parser_error (parser, "for, while or do statement expected"); + return false; + } + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + c_parser_for_statement (parser, ivdep, unroll, if_p); + else if (c_parser_next_token_is_keyword (parser, RID_WHILE)) + c_parser_while_statement (parser, ivdep, unroll, if_p); + else + c_parser_do_statement (parser, ivdep, unroll); + } + return true; + + case PRAGMA_GCC_PCH_PREPROCESS: + c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + + case PRAGMA_OACC_WAIT: + if (context != pragma_compound) + { + construct = "acc wait"; + goto in_compound; + } + /* FALL THROUGH. */ + + default: + if (id < PRAGMA_FIRST_EXTERNAL) + { + if (context != pragma_stmt && context != pragma_compound) + { + bad_stmt: + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + c_parser_omp_construct (parser, if_p); + return true; + } + break; + } + + c_parser_consume_pragma (parser); + c_invoke_pragma_handler (id); + + /* Skip to EOL, but suppress any error message. Those will have been + generated by the handler routine through calling error, as opposed + to calling c_parser_error. */ + parser->error = true; + c_parser_skip_to_pragma_eol (parser); + + return false; +} + +/* The interface the pragma parsers have to the lexer. */ + +enum cpp_ttype +pragma_lex (tree *value, location_t *loc) +{ + c_token *tok = c_parser_peek_token (the_parser); + enum cpp_ttype ret = tok->type; + + *value = tok->value; + if (loc) + *loc = tok->location; + + if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) + ret = CPP_EOF; + else if (ret == CPP_STRING) + *value = c_parser_string_literal (the_parser, false, false).value; + else + { + if (ret == CPP_KEYWORD) + ret = CPP_NAME; + c_parser_consume_token (the_parser); + } + + return ret; +} + +static void +c_parser_pragma_pch_preprocess (c_parser *parser) +{ + tree name = NULL; + + parser->lex_joined_string = true; + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_STRING)) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + c_parser_error (parser, "expected string literal"); + c_parser_skip_to_pragma_eol (parser); + parser->lex_joined_string = false; + + if (name) + c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); +} + +/* OpenACC and OpenMP parsing routines. */ + +/* Returns name of the next clause. + If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and + the token is not consumed. Otherwise appropriate pragma_omp_clause is + returned and the token is consumed. */ + +static pragma_omp_clause +c_parser_omp_clause_name (c_parser *parser) +{ + pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; + + if (c_parser_next_token_is_keyword (parser, RID_AUTO)) + result = PRAGMA_OACC_CLAUSE_AUTO; + else if (c_parser_next_token_is_keyword (parser, RID_IF)) + result = PRAGMA_OMP_CLAUSE_IF; + else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) + result = PRAGMA_OMP_CLAUSE_DEFAULT; + else if (c_parser_next_token_is_keyword (parser, RID_FOR)) + result = PRAGMA_OMP_CLAUSE_FOR; + else if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + switch (p[0]) + { + case 'a': + if (!strcmp ("affinity", p)) + result = PRAGMA_OMP_CLAUSE_AFFINITY; + else if (!strcmp ("aligned", p)) + result = PRAGMA_OMP_CLAUSE_ALIGNED; + else if (!strcmp ("allocate", p)) + result = PRAGMA_OMP_CLAUSE_ALLOCATE; + else if (!strcmp ("async", p)) + result = PRAGMA_OACC_CLAUSE_ASYNC; + else if (!strcmp ("attach", p)) + result = PRAGMA_OACC_CLAUSE_ATTACH; + break; + case 'b': + if (!strcmp ("bind", p)) + result = PRAGMA_OMP_CLAUSE_BIND; + break; + case 'c': + if (!strcmp ("collapse", p)) + result = PRAGMA_OMP_CLAUSE_COLLAPSE; + else if (!strcmp ("copy", p)) + result = PRAGMA_OACC_CLAUSE_COPY; + else if (!strcmp ("copyin", p)) + result = PRAGMA_OMP_CLAUSE_COPYIN; + else if (!strcmp ("copyout", p)) + result = PRAGMA_OACC_CLAUSE_COPYOUT; + else if (!strcmp ("copyprivate", p)) + result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; + else if (!strcmp ("create", p)) + result = PRAGMA_OACC_CLAUSE_CREATE; + break; + case 'd': + if (!strcmp ("defaultmap", p)) + result = PRAGMA_OMP_CLAUSE_DEFAULTMAP; + else if (!strcmp ("delete", p)) + result = PRAGMA_OACC_CLAUSE_DELETE; + else if (!strcmp ("depend", p)) + result = PRAGMA_OMP_CLAUSE_DEPEND; + else if (!strcmp ("detach", p)) + result = PRAGMA_OACC_CLAUSE_DETACH; + else if (!strcmp ("device", p)) + result = PRAGMA_OMP_CLAUSE_DEVICE; + else if (!strcmp ("deviceptr", p)) + result = PRAGMA_OACC_CLAUSE_DEVICEPTR; + else if (!strcmp ("device_resident", p)) + result = PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT; + else if (!strcmp ("device_type", p)) + result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE; + else if (!strcmp ("dist_schedule", p)) + result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; + break; + case 'f': + if (!strcmp ("filter", p)) + result = PRAGMA_OMP_CLAUSE_FILTER; + else if (!strcmp ("final", p)) + result = PRAGMA_OMP_CLAUSE_FINAL; + else if (!strcmp ("finalize", p)) + result = PRAGMA_OACC_CLAUSE_FINALIZE; + else if (!strcmp ("firstprivate", p)) + result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + else if (!strcmp ("from", p)) + result = PRAGMA_OMP_CLAUSE_FROM; + break; + case 'g': + if (!strcmp ("gang", p)) + result = PRAGMA_OACC_CLAUSE_GANG; + else if (!strcmp ("grainsize", p)) + result = PRAGMA_OMP_CLAUSE_GRAINSIZE; + break; + case 'h': + if (!strcmp ("hint", p)) + result = PRAGMA_OMP_CLAUSE_HINT; + else if (!strcmp ("host", p)) + result = PRAGMA_OACC_CLAUSE_HOST; + break; + case 'i': + if (!strcmp ("if_present", p)) + result = PRAGMA_OACC_CLAUSE_IF_PRESENT; + else if (!strcmp ("in_reduction", p)) + result = PRAGMA_OMP_CLAUSE_IN_REDUCTION; + else if (!strcmp ("inbranch", p)) + result = PRAGMA_OMP_CLAUSE_INBRANCH; + else if (!strcmp ("independent", p)) + result = PRAGMA_OACC_CLAUSE_INDEPENDENT; + else if (!strcmp ("is_device_ptr", p)) + result = PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR; + break; + case 'l': + if (!strcmp ("lastprivate", p)) + result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + else if (!strcmp ("linear", p)) + result = PRAGMA_OMP_CLAUSE_LINEAR; + else if (!strcmp ("link", p)) + result = PRAGMA_OMP_CLAUSE_LINK; + break; + case 'm': + if (!strcmp ("map", p)) + result = PRAGMA_OMP_CLAUSE_MAP; + else if (!strcmp ("mergeable", p)) + result = PRAGMA_OMP_CLAUSE_MERGEABLE; + break; + case 'n': + if (!strcmp ("no_create", p)) + result = PRAGMA_OACC_CLAUSE_NO_CREATE; + else if (!strcmp ("nogroup", p)) + result = PRAGMA_OMP_CLAUSE_NOGROUP; + else if (!strcmp ("nohost", p)) + result = PRAGMA_OACC_CLAUSE_NOHOST; + else if (!strcmp ("nontemporal", p)) + result = PRAGMA_OMP_CLAUSE_NONTEMPORAL; + else if (!strcmp ("notinbranch", p)) + result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; + else if (!strcmp ("nowait", p)) + result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_gangs", p)) + result = PRAGMA_OACC_CLAUSE_NUM_GANGS; + else if (!strcmp ("num_tasks", p)) + result = PRAGMA_OMP_CLAUSE_NUM_TASKS; + else if (!strcmp ("num_teams", p)) + result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; + else if (!strcmp ("num_threads", p)) + result = PRAGMA_OMP_CLAUSE_NUM_THREADS; + else if (!strcmp ("num_workers", p)) + result = PRAGMA_OACC_CLAUSE_NUM_WORKERS; + break; + case 'o': + if (!strcmp ("ordered", p)) + result = PRAGMA_OMP_CLAUSE_ORDERED; + else if (!strcmp ("order", p)) + result = PRAGMA_OMP_CLAUSE_ORDER; + break; + case 'p': + if (!strcmp ("parallel", p)) + result = PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("present", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT; + /* As of OpenACC 2.5, these are now aliases of the non-present_or + clauses. */ + else if (!strcmp ("present_or_copy", p) + || !strcmp ("pcopy", p)) + result = PRAGMA_OACC_CLAUSE_COPY; + else if (!strcmp ("present_or_copyin", p) + || !strcmp ("pcopyin", p)) + result = PRAGMA_OACC_CLAUSE_COPYIN; + else if (!strcmp ("present_or_copyout", p) + || !strcmp ("pcopyout", p)) + result = PRAGMA_OACC_CLAUSE_COPYOUT; + else if (!strcmp ("present_or_create", p) + || !strcmp ("pcreate", p)) + result = PRAGMA_OACC_CLAUSE_CREATE; + else if (!strcmp ("priority", p)) + result = PRAGMA_OMP_CLAUSE_PRIORITY; + else if (!strcmp ("private", p)) + result = PRAGMA_OMP_CLAUSE_PRIVATE; + else if (!strcmp ("proc_bind", p)) + result = PRAGMA_OMP_CLAUSE_PROC_BIND; + break; + case 'r': + if (!strcmp ("reduction", p)) + result = PRAGMA_OMP_CLAUSE_REDUCTION; + break; + case 's': + if (!strcmp ("safelen", p)) + result = PRAGMA_OMP_CLAUSE_SAFELEN; + else if (!strcmp ("schedule", p)) + result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("sections", p)) + result = PRAGMA_OMP_CLAUSE_SECTIONS; + else if (!strcmp ("self", p)) /* "self" is a synonym for "host". */ + result = PRAGMA_OACC_CLAUSE_HOST; + else if (!strcmp ("seq", p)) + result = PRAGMA_OACC_CLAUSE_SEQ; + else if (!strcmp ("shared", p)) + result = PRAGMA_OMP_CLAUSE_SHARED; + else if (!strcmp ("simd", p)) + result = PRAGMA_OMP_CLAUSE_SIMD; + else if (!strcmp ("simdlen", p)) + result = PRAGMA_OMP_CLAUSE_SIMDLEN; + break; + case 't': + if (!strcmp ("task_reduction", p)) + result = PRAGMA_OMP_CLAUSE_TASK_REDUCTION; + else if (!strcmp ("taskgroup", p)) + result = PRAGMA_OMP_CLAUSE_TASKGROUP; + else if (!strcmp ("thread_limit", p)) + result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; + else if (!strcmp ("threads", p)) + result = PRAGMA_OMP_CLAUSE_THREADS; + else if (!strcmp ("tile", p)) + result = PRAGMA_OACC_CLAUSE_TILE; + else if (!strcmp ("to", p)) + result = PRAGMA_OMP_CLAUSE_TO; + break; + case 'u': + if (!strcmp ("uniform", p)) + result = PRAGMA_OMP_CLAUSE_UNIFORM; + else if (!strcmp ("untied", p)) + result = PRAGMA_OMP_CLAUSE_UNTIED; + else if (!strcmp ("use_device", p)) + result = PRAGMA_OACC_CLAUSE_USE_DEVICE; + else if (!strcmp ("use_device_addr", p)) + result = PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR; + else if (!strcmp ("use_device_ptr", p)) + result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR; + break; + case 'v': + if (!strcmp ("vector", p)) + result = PRAGMA_OACC_CLAUSE_VECTOR; + else if (!strcmp ("vector_length", p)) + result = PRAGMA_OACC_CLAUSE_VECTOR_LENGTH; + break; + case 'w': + if (!strcmp ("wait", p)) + result = PRAGMA_OACC_CLAUSE_WAIT; + else if (!strcmp ("worker", p)) + result = PRAGMA_OACC_CLAUSE_WORKER; + break; + } + } + + if (result != PRAGMA_OMP_CLAUSE_NONE) + c_parser_consume_token (parser); + + return result; +} + +/* Validate that a clause of the given type does not already exist. */ + +static void +check_no_duplicate_clause (tree clauses, enum omp_clause_code code, + const char *name) +{ + if (tree c = omp_find_clause (clauses, code)) + error_at (OMP_CLAUSE_LOCATION (c), "too many %qs clauses", name); +} + +/* OpenACC 2.0 + Parse wait clause or wait directive parameters. */ + +static tree +c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list) +{ + vec *args; + tree t, args_tree; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + args = c_parser_expr_list (parser, false, true, NULL, NULL, NULL, NULL); + args_tree = build_tree_list_vec (args); + + for (t = args_tree; t; t = TREE_CHAIN (t)) + { + tree targ = TREE_VALUE (t); + + if (targ != error_mark_node) + { + if (!INTEGRAL_TYPE_P (TREE_TYPE (targ))) + { + c_parser_error (parser, "expression must be integral"); + targ = error_mark_node; + } + else + { + tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT); + + OMP_CLAUSE_DECL (c) = targ; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + } + } + + release_tree_vector (args); + parens.require_close (parser); + return list; +} + +/* OpenACC 2.0, OpenMP 2.5: + variable-list: + identifier + variable-list , identifier + + If KIND is nonzero, create the appropriate node and install the + decl in OMP_CLAUSE_DECL and add the node to the head of the list. + If KIND is nonzero, CLAUSE_LOC is the location of the clause. + + If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; + return the list created. + + The optional ALLOW_DEREF argument is true if list items can use the deref + (->) operator. */ + +struct omp_dim +{ + tree low_bound, length; + location_t loc; + bool no_colon; + omp_dim (tree lb, tree len, location_t lo, bool nc) + : low_bound (lb), length (len), loc (lo), no_colon (nc) {} +}; + +static tree +c_parser_omp_variable_list (c_parser *parser, + location_t clause_loc, + enum omp_clause_code kind, tree list, + bool allow_deref = false) +{ + auto_vec dims; + bool array_section_p; + auto_vec tokens; + unsigned int tokens_avail = 0; + bool first = true; + + while (1) + { + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) + { + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + struct c_expr expr = c_parser_expr_no_commas (parser, NULL); + if (expr.value != error_mark_node) + { + tree u = build_omp_clause (clause_loc, kind); + OMP_CLAUSE_DECL (u) = expr.value; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } + + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + + c_parser_consume_token (parser); + first = false; + continue; + } + + tokens.truncate (0); + unsigned int nesting_depth = 0; + while (1) + { + c_token *token = c_parser_peek_token (parser); + switch (token->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + break; + case CPP_OPEN_BRACE: + case CPP_OPEN_PAREN: + case CPP_OPEN_SQUARE: + ++nesting_depth; + goto add; + case CPP_CLOSE_BRACE: + case CPP_CLOSE_PAREN: + case CPP_CLOSE_SQUARE: + if (nesting_depth-- == 0) + break; + goto add; + case CPP_COMMA: + if (nesting_depth == 0) + break; + goto add; + default: + add: + tokens.safe_push (*token); + c_parser_consume_token (parser); + continue; + } + break; + } + + /* Make sure nothing tries to read past the end of the tokens. */ + c_token eof_token; + memset (&eof_token, 0, sizeof (eof_token)); + eof_token.type = CPP_EOF; + tokens.safe_push (eof_token); + tokens.safe_push (eof_token); + + tokens_avail = parser->tokens_avail; + gcc_assert (parser->tokens == &parser->tokens_buf[0]); + parser->tokens = tokens.address (); + parser->tokens_avail = tokens.length (); + } + + tree t = NULL_TREE; + + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + t = lookup_name (c_parser_peek_token (parser)->value); + + if (t == NULL_TREE) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + t = error_mark_node; + } + + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is (parser, CPP_KEYWORD) + && (c_parser_peek_token (parser)->keyword == RID_FUNCTION_NAME + || (c_parser_peek_token (parser)->keyword + == RID_PRETTY_FUNCTION_NAME) + || (c_parser_peek_token (parser)->keyword + == RID_C99_FUNCTION_NAME))) + t = c_parser_predefined_identifier (parser).value; + else + { + if (first) + c_parser_error (parser, "expected identifier"); + break; + } + + if (t == error_mark_node) + ; + else if (kind != 0) + { + switch (kind) + { + case OMP_CLAUSE__CACHE_: + /* The OpenACC cache directive explicitly only allows "array + elements or subarrays". */ + if (c_parser_peek_token (parser)->type != CPP_OPEN_SQUARE) + { + c_parser_error (parser, "expected %<[%>"); + t = error_mark_node; + break; + } + /* FALLTHROUGH */ + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + start_component_ref: + while (c_parser_next_token_is (parser, CPP_DOT) + || (allow_deref + && c_parser_next_token_is (parser, CPP_DEREF))) + { + location_t op_loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_DEREF)) + t = build_simple_mem_ref (t); + c_parser_consume_token (parser); + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + t = error_mark_node; + break; + } + + c_token *comp_tok = c_parser_peek_token (parser); + tree ident = comp_tok->value; + location_t comp_loc = comp_tok->location; + c_parser_consume_token (parser); + t = build_component_ref (op_loc, t, ident, comp_loc); + } + /* FALLTHROUGH */ + case OMP_CLAUSE_AFFINITY: + case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_IN_REDUCTION: + case OMP_CLAUSE_TASK_REDUCTION: + array_section_p = false; + dims.truncate (0); + while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + { + location_t loc = UNKNOWN_LOCATION; + tree low_bound = NULL_TREE, length = NULL_TREE; + bool no_colon = false; + + c_parser_consume_token (parser); + if (!c_parser_next_token_is (parser, CPP_COLON)) + { + location_t expr_loc + = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expression (parser); + expr = convert_lvalue_to_rvalue (expr_loc, expr, + false, true); + low_bound = expr.value; + loc = expr_loc; + } + if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + { + length = integer_one_node; + no_colon = true; + } + else + { + /* Look for `:'. */ + if (!c_parser_require (parser, CPP_COLON, + "expected %<:%>")) + { + t = error_mark_node; + break; + } + array_section_p = true; + if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + { + location_t expr_loc + = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expression (parser); + expr = convert_lvalue_to_rvalue (expr_loc, expr, + false, true); + length = expr.value; + } + } + /* Look for the closing `]'. */ + if (!c_parser_require (parser, CPP_CLOSE_SQUARE, + "expected %<]%>")) + { + t = error_mark_node; + break; + } + + dims.safe_push (omp_dim (low_bound, length, loc, no_colon)); + } + + if (t != error_mark_node) + { + if ((kind == OMP_CLAUSE_MAP + || kind == OMP_CLAUSE_FROM + || kind == OMP_CLAUSE_TO) + && !array_section_p + && (c_parser_next_token_is (parser, CPP_DOT) + || (allow_deref + && c_parser_next_token_is (parser, + CPP_DEREF)))) + { + for (unsigned i = 0; i < dims.length (); i++) + { + gcc_assert (dims[i].length == integer_one_node); + t = build_array_ref (dims[i].loc, + t, dims[i].low_bound); + } + goto start_component_ref; + } + else + for (unsigned i = 0; i < dims.length (); i++) + t = tree_cons (dims[i].low_bound, dims[i].length, t); + } + + if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) + && t != error_mark_node + && parser->tokens_avail != 2) + { + if (array_section_p) + { + error_at (c_parser_peek_token (parser)->location, + "expected %<)%> or %<,%>"); + t = error_mark_node; + } + else + { + parser->tokens = tokens.address (); + parser->tokens_avail = tokens.length (); + + t = c_parser_expr_no_commas (parser, NULL).value; + if (t != error_mark_node && parser->tokens_avail != 2) + { + error_at (c_parser_peek_token (parser)->location, + "expected %<)%> or %<,%>"); + t = error_mark_node; + } + } + } + break; + default: + break; + } + + if (t != error_mark_node) + { + tree u = build_omp_clause (clause_loc, kind); + OMP_CLAUSE_DECL (u) = t; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } + } + else + list = tree_cons (t, NULL_TREE, list); + + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) + { + parser->tokens = &parser->tokens_buf[0]; + parser->tokens_avail = tokens_avail; + } + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + + c_parser_consume_token (parser); + first = false; + } + + return list; +} + +/* Similarly, but expect leading and trailing parenthesis. This is a very + common case for OpenACC and OpenMP clauses. The optional ALLOW_DEREF + argument is true if list items can use the deref (->) operator. */ + +static tree +c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, + tree list, bool allow_deref = false) +{ + /* The clauses location. */ + location_t loc = c_parser_peek_token (parser)->location; + + matching_parens parens; + if (parens.require_open (parser)) + { + list = c_parser_omp_variable_list (parser, loc, kind, list, allow_deref); + parens.skip_until_found_close (parser); + } + return list; +} + +/* OpenACC 2.0: + copy ( variable-list ) + copyin ( variable-list ) + copyout ( variable-list ) + create ( variable-list ) + delete ( variable-list ) + present ( variable-list ) + + OpenACC 2.6: + no_create ( variable-list ) + attach ( variable-list ) + detach ( variable-list ) */ + +static tree +c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind, + tree list) +{ + enum gomp_map_kind kind; + switch (c_kind) + { + case PRAGMA_OACC_CLAUSE_ATTACH: + kind = GOMP_MAP_ATTACH; + break; + case PRAGMA_OACC_CLAUSE_COPY: + kind = GOMP_MAP_TOFROM; + break; + case PRAGMA_OACC_CLAUSE_COPYIN: + kind = GOMP_MAP_TO; + break; + case PRAGMA_OACC_CLAUSE_COPYOUT: + kind = GOMP_MAP_FROM; + break; + case PRAGMA_OACC_CLAUSE_CREATE: + kind = GOMP_MAP_ALLOC; + break; + case PRAGMA_OACC_CLAUSE_DELETE: + kind = GOMP_MAP_RELEASE; + break; + case PRAGMA_OACC_CLAUSE_DETACH: + kind = GOMP_MAP_DETACH; + break; + case PRAGMA_OACC_CLAUSE_DEVICE: + kind = GOMP_MAP_FORCE_TO; + break; + case PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT: + kind = GOMP_MAP_DEVICE_RESIDENT; + break; + case PRAGMA_OACC_CLAUSE_HOST: + kind = GOMP_MAP_FORCE_FROM; + break; + case PRAGMA_OACC_CLAUSE_LINK: + kind = GOMP_MAP_LINK; + break; + case PRAGMA_OACC_CLAUSE_NO_CREATE: + kind = GOMP_MAP_IF_PRESENT; + break; + case PRAGMA_OACC_CLAUSE_PRESENT: + kind = GOMP_MAP_FORCE_PRESENT; + break; + default: + gcc_unreachable (); + } + tree nl, c; + nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list, true); + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_SET_MAP_KIND (c, kind); + + return nl; +} + +/* OpenACC 2.0: + deviceptr ( variable-list ) */ + +static tree +c_parser_oacc_data_clause_deviceptr (c_parser *parser, tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree vars, t; + + /* Can't use OMP_CLAUSE_MAP here (that is, can't use the generic + c_parser_oacc_data_clause), as for PRAGMA_OACC_CLAUSE_DEVICEPTR, + variable-list must only allow for pointer variables. */ + vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); + for (t = vars; t && t; t = TREE_CHAIN (t)) + { + tree v = TREE_PURPOSE (t); + + /* FIXME diagnostics: Ideally we should keep individual + locations for all the variables in the var list to make the + following errors more precise. Perhaps + c_parser_omp_var_list_parens() should construct a list of + locations to go along with the var list. */ + + if (!VAR_P (v) && TREE_CODE (v) != PARM_DECL) + error_at (loc, "%qD is not a variable", v); + else if (TREE_TYPE (v) == error_mark_node) + ; + else if (!POINTER_TYPE_P (TREE_TYPE (v))) + error_at (loc, "%qD is not a pointer variable", v); + + tree u = build_omp_clause (loc, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (u, GOMP_MAP_FORCE_DEVICEPTR); + OMP_CLAUSE_DECL (u) = v; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } + + return list; +} + +/* OpenACC 2.0, OpenMP 3.0: + collapse ( constant-expression ) */ + +static tree +c_parser_omp_clause_collapse (c_parser *parser, tree list) +{ + tree c, num = error_mark_node; + HOST_WIDE_INT n; + location_t loc; + + check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse"); + check_no_duplicate_clause (list, OMP_CLAUSE_TILE, "tile"); + + loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + num = c_parser_expr_no_commas (parser, NULL).value; + parens.skip_until_found_close (parser); + } + if (num == error_mark_node) + return list; + mark_exp_read (num); + num = c_fully_fold (num, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) + || !tree_fits_shwi_p (num) + || (n = tree_to_shwi (num)) <= 0 + || (int) n != n) + { + error_at (loc, + "collapse argument needs positive constant integer expression"); + return list; + } + c = build_omp_clause (loc, OMP_CLAUSE_COLLAPSE); + OMP_CLAUSE_COLLAPSE_EXPR (c) = num; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + copyin ( variable-list ) */ + +static tree +c_parser_omp_clause_copyin (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list); +} + +/* OpenMP 2.5: + copyprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_copyprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list); +} + +/* OpenMP 2.5: + default ( none | shared ) + + OpenMP 5.1: + default ( private | firstprivate ) + + OpenACC: + default ( none | present ) */ + +static tree +c_parser_omp_clause_default (c_parser *parser, tree list, bool is_oacc) +{ + enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; + location_t loc = c_parser_peek_token (parser)->location; + tree c; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + switch (p[0]) + { + case 'n': + if (strcmp ("none", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_NONE; + break; + + case 'p': + if (is_oacc) + { + if (strcmp ("present", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_PRESENT; + } + else + { + if (strcmp ("private", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_PRIVATE; + } + break; + + case 'f': + if (strcmp ("firstprivate", p) != 0 || is_oacc) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; + break; + + case 's': + if (strcmp ("shared", p) != 0 || is_oacc) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_SHARED; + break; + + default: + goto invalid_kind; + } + + c_parser_consume_token (parser); + } + else + { + invalid_kind: + if (is_oacc) + c_parser_error (parser, "expected % or %"); + else + c_parser_error (parser, "expected %, %, " + "% or %"); + } + parens.skip_until_found_close (parser); + + if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default"); + c = build_omp_clause (loc, OMP_CLAUSE_DEFAULT); + OMP_CLAUSE_CHAIN (c) = list; + OMP_CLAUSE_DEFAULT_KIND (c) = kind; + + return c; +} + +/* OpenMP 2.5: + firstprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_firstprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list); +} + +/* OpenMP 3.1: + final ( expression ) */ + +static tree +c_parser_omp_clause_final (c_parser *parser, tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + matching_parens parens; + tree t, c; + if (!parens.require_open (parser)) + t = error_mark_node; + else + { + location_t eloc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + t = convert_lvalue_to_rvalue (eloc, expr, true, true).value; + t = c_objc_common_truthvalue_conversion (eloc, t); + t = c_fully_fold (t, false, NULL); + parens.skip_until_found_close (parser); + } + + check_no_duplicate_clause (list, OMP_CLAUSE_FINAL, "final"); + + c = build_omp_clause (loc, OMP_CLAUSE_FINAL); + OMP_CLAUSE_FINAL_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + else + c_parser_error (parser, "expected %<(%>"); + + return list; +} + +/* OpenACC, OpenMP 2.5: + if ( expression ) + + OpenMP 4.5: + if ( directive-name-modifier : expression ) + + directive-name-modifier: + parallel | task | taskloop | target data | target | target update + | target enter data | target exit data + + OpenMP 5.0: + directive-name-modifier: + ... | simd | cancel */ + +static tree +c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) +{ + location_t location = c_parser_peek_token (parser)->location; + enum tree_code if_modifier = ERROR_MARK; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (is_omp && c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + int n = 2; + if (strcmp (p, "cancel") == 0) + if_modifier = VOID_CST; + else if (strcmp (p, "parallel") == 0) + if_modifier = OMP_PARALLEL; + else if (strcmp (p, "simd") == 0) + if_modifier = OMP_SIMD; + else if (strcmp (p, "task") == 0) + if_modifier = OMP_TASK; + else if (strcmp (p, "taskloop") == 0) + if_modifier = OMP_TASKLOOP; + else if (strcmp (p, "target") == 0) + { + if_modifier = OMP_TARGET; + if (c_parser_peek_2nd_token (parser)->type == CPP_NAME) + { + p = IDENTIFIER_POINTER (c_parser_peek_2nd_token (parser)->value); + if (strcmp ("data", p) == 0) + if_modifier = OMP_TARGET_DATA; + else if (strcmp ("update", p) == 0) + if_modifier = OMP_TARGET_UPDATE; + else if (strcmp ("enter", p) == 0) + if_modifier = OMP_TARGET_ENTER_DATA; + else if (strcmp ("exit", p) == 0) + if_modifier = OMP_TARGET_EXIT_DATA; + if (if_modifier != OMP_TARGET) + { + n = 3; + c_parser_consume_token (parser); + } + else + { + location_t loc = c_parser_peek_2nd_token (parser)->location; + error_at (loc, "expected %, %, % " + "or %"); + if_modifier = ERROR_MARK; + } + if (if_modifier == OMP_TARGET_ENTER_DATA + || if_modifier == OMP_TARGET_EXIT_DATA) + { + if (c_parser_peek_2nd_token (parser)->type == CPP_NAME) + { + p = IDENTIFIER_POINTER + (c_parser_peek_2nd_token (parser)->value); + if (strcmp ("data", p) == 0) + n = 4; + } + if (n == 4) + c_parser_consume_token (parser); + else + { + location_t loc + = c_parser_peek_2nd_token (parser)->location; + error_at (loc, "expected %"); + if_modifier = ERROR_MARK; + } + } + } + } + if (if_modifier != ERROR_MARK) + { + if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + else + { + if (n > 2) + { + location_t loc = c_parser_peek_2nd_token (parser)->location; + error_at (loc, "expected %<:%>"); + } + if_modifier = ERROR_MARK; + } + } + } + + location_t loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (loc, expr, true, true); + tree t = c_objc_common_truthvalue_conversion (loc, expr.value), c; + t = c_fully_fold (t, false, NULL); + parens.skip_until_found_close (parser); + + for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IF) + { + if (if_modifier != ERROR_MARK + && OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) + { + const char *p = NULL; + switch (if_modifier) + { + case VOID_CST: p = "cancel"; break; + case OMP_PARALLEL: p = "parallel"; break; + case OMP_SIMD: p = "simd"; break; + case OMP_TASK: p = "task"; break; + case OMP_TASKLOOP: p = "taskloop"; break; + case OMP_TARGET_DATA: p = "target data"; break; + case OMP_TARGET: p = "target"; break; + case OMP_TARGET_UPDATE: p = "target update"; break; + case OMP_TARGET_ENTER_DATA: p = "target enter data"; break; + case OMP_TARGET_EXIT_DATA: p = "target exit data"; break; + default: gcc_unreachable (); + } + error_at (location, "too many % clauses with %qs modifier", + p); + return list; + } + else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) + { + if (!is_omp) + error_at (location, "too many % clauses"); + else + error_at (location, "too many % clauses without modifier"); + return list; + } + else if (if_modifier == ERROR_MARK + || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK) + { + error_at (location, "if any % clause has modifier, then all " + "% clauses have to use modifier"); + return list; + } + } + + c = build_omp_clause (location, OMP_CLAUSE_IF); + OMP_CLAUSE_IF_MODIFIER (c) = if_modifier; + OMP_CLAUSE_IF_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + lastprivate ( variable-list ) + + OpenMP 5.0: + lastprivate ( [ lastprivate-modifier : ] variable-list ) */ + +static tree +c_parser_omp_clause_lastprivate (c_parser *parser, tree list) +{ + /* The clauses location. */ + location_t loc = c_parser_peek_token (parser)->location; + + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + bool conditional = false; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "conditional") == 0) + { + conditional = true; + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + } + tree nlist = c_parser_omp_variable_list (parser, loc, + OMP_CLAUSE_LASTPRIVATE, list); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (conditional) + for (tree c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 1; + return nlist; + } + return list; +} + +/* OpenMP 3.1: + mergeable */ + +static tree +c_parser_omp_clause_mergeable (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + /* FIXME: Should we allow duplicates? */ + check_no_duplicate_clause (list, OMP_CLAUSE_MERGEABLE, "mergeable"); + + c = build_omp_clause (c_parser_peek_token (parser)->location, + OMP_CLAUSE_MERGEABLE); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 2.5: + nowait */ + +static tree +c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + location_t loc = c_parser_peek_token (parser)->location; + + check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait"); + + c = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + num_threads ( expression ) */ + +static tree +c_parser_omp_clause_num_threads (c_parser *parser, tree list) +{ + location_t num_threads_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + + parens.skip_until_found_close (parser); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + protected_set_expr_location (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, + "% value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads"); + + c = build_omp_clause (num_threads_loc, OMP_CLAUSE_NUM_THREADS); + OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.5: + num_tasks ( expression ) + + OpenMP 5.1: + num_tasks ( strict : expression ) */ + +static tree +c_parser_omp_clause_num_tasks (c_parser *parser, tree list) +{ + location_t num_tasks_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + bool strict = false; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "strict") == 0) + { + strict = true; + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + + parens.skip_until_found_close (parser); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "% value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TASKS, "num_tasks"); + + c = build_omp_clause (num_tasks_loc, OMP_CLAUSE_NUM_TASKS); + OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; + OMP_CLAUSE_NUM_TASKS_STRICT (c) = strict; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.5: + grainsize ( expression ) + + OpenMP 5.1: + grainsize ( strict : expression ) */ + +static tree +c_parser_omp_clause_grainsize (c_parser *parser, tree list) +{ + location_t grainsize_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + bool strict = false; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "strict") == 0) + { + strict = true; + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + + parens.skip_until_found_close (parser); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "% value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_GRAINSIZE, "grainsize"); + + c = build_omp_clause (grainsize_loc, OMP_CLAUSE_GRAINSIZE); + OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; + OMP_CLAUSE_GRAINSIZE_STRICT (c) = strict; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.5: + priority ( expression ) */ + +static tree +c_parser_omp_clause_priority (c_parser *parser, tree list) +{ + location_t priority_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + + parens.skip_until_found_close (parser); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't + non-negative. */ + c = fold_build2_loc (expr_loc, LT_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "% value must be non-negative"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_PRIORITY, "priority"); + + c = build_omp_clause (priority_loc, OMP_CLAUSE_PRIORITY); + OMP_CLAUSE_PRIORITY_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.5: + hint ( expression ) */ + +static tree +c_parser_omp_clause_hint (c_parser *parser, tree list) +{ + location_t hint_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + || TREE_CODE (t) != INTEGER_CST + || tree_int_cst_sgn (t) == -1) + { + c_parser_error (parser, "expected constant integer expression " + "with valid sync-hint value"); + return list; + } + parens.skip_until_found_close (parser); + check_no_duplicate_clause (list, OMP_CLAUSE_HINT, "hint"); + + c = build_omp_clause (hint_loc, OMP_CLAUSE_HINT); + OMP_CLAUSE_HINT_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 5.1: + filter ( integer-expression ) */ + +static tree +c_parser_omp_clause_filter (c_parser *parser, tree list) +{ + location_t hint_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + parens.skip_until_found_close (parser); + check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter"); + + c = build_omp_clause (hint_loc, OMP_CLAUSE_FILTER); + OMP_CLAUSE_FILTER_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.5: + defaultmap ( tofrom : scalar ) + + OpenMP 5.0: + defaultmap ( implicit-behavior [ : variable-category ] ) */ + +static tree +c_parser_omp_clause_defaultmap (c_parser *parser, tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree c; + const char *p; + enum omp_clause_defaultmap_kind behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; + enum omp_clause_defaultmap_kind category + = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) + p = "default"; + else if (!c_parser_next_token_is (parser, CPP_NAME)) + { + invalid_behavior: + c_parser_error (parser, "expected %, %, %, " + "%, %, % " + "or %"); + goto out_err; + } + else + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + switch (p[0]) + { + case 'a': + if (strcmp ("alloc", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_ALLOC; + else + goto invalid_behavior; + break; + + case 'd': + if (strcmp ("default", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; + else + goto invalid_behavior; + break; + + case 'f': + if (strcmp ("firstprivate", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE; + else if (strcmp ("from", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_FROM; + else + goto invalid_behavior; + break; + + case 'n': + if (strcmp ("none", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_NONE; + else + goto invalid_behavior; + break; + + case 't': + if (strcmp ("tofrom", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM; + else if (strcmp ("to", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_TO; + else + goto invalid_behavior; + break; + + default: + goto invalid_behavior; + } + c_parser_consume_token (parser); + + if (!c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto out_err; + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + invalid_category: + c_parser_error (parser, "expected %, % or " + "%"); + goto out_err; + } + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + switch (p[0]) + { + case 'a': + if (strcmp ("aggregate", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE; + else + goto invalid_category; + break; + + case 'p': + if (strcmp ("pointer", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER; + else + goto invalid_category; + break; + + case 's': + if (strcmp ("scalar", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR; + else + goto invalid_category; + break; + + default: + goto invalid_category; + } + + c_parser_consume_token (parser); + } + parens.skip_until_found_close (parser); + + for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP + && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED + || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category + || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) + == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) + { + enum omp_clause_defaultmap_kind cat = category; + location_t loc = OMP_CLAUSE_LOCATION (c); + if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) + cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c); + p = NULL; + switch (cat) + { + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: + p = NULL; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: + p = "aggregate"; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER: + p = "pointer"; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: + p = "scalar"; + break; + default: + gcc_unreachable (); + } + if (p) + error_at (loc, "too many % clauses with %qs category", + p); + else + error_at (loc, "too many % clauses with unspecified " + "category"); + break; + } + + c = build_omp_clause (loc, OMP_CLAUSE_DEFAULTMAP); + OMP_CLAUSE_DEFAULTMAP_SET_KIND (c, behavior, category); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + out_err: + parens.skip_until_found_close (parser); + return list; +} + +/* OpenACC 2.0: + use_device ( variable-list ) + + OpenMP 4.5: + use_device_ptr ( variable-list ) */ + +static tree +c_parser_omp_clause_use_device_ptr (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_USE_DEVICE_PTR, + list); +} + +/* OpenMP 5.0: + use_device_addr ( variable-list ) */ + +static tree +c_parser_omp_clause_use_device_addr (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_USE_DEVICE_ADDR, + list); +} + +/* OpenMP 4.5: + is_device_ptr ( variable-list ) */ + +static tree +c_parser_omp_clause_is_device_ptr (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_IS_DEVICE_PTR, list); +} + +/* OpenACC: + num_gangs ( expression ) + num_workers ( expression ) + vector_length ( expression ) */ + +static tree +c_parser_oacc_single_int_clause (c_parser *parser, omp_clause_code code, + tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expression (parser); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + + parens.skip_until_found_close (parser); + + if (t == error_mark_node) + return list; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (expr_loc, "%qs expression must be integral", + omp_clause_code_name[code]); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + protected_set_expr_location (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, + "%qs value must be positive", + omp_clause_code_name[code]); + t = integer_one_node; + } + + check_no_duplicate_clause (list, code, omp_clause_code_name[code]); + + c = build_omp_clause (loc, code); + OMP_CLAUSE_OPERAND (c, 0) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenACC: + + gang [( gang-arg-list )] + worker [( [num:] int-expr )] + vector [( [length:] int-expr )] + + where gang-arg is one of: + + [num:] int-expr + static: size-expr + + and size-expr may be: + + * + int-expr +*/ + +static tree +c_parser_oacc_shape_clause (c_parser *parser, location_t loc, + omp_clause_code kind, + const char *str, tree list) +{ + const char *id = "num"; + tree ops[2] = { NULL_TREE, NULL_TREE }, c; + + if (kind == OMP_CLAUSE_VECTOR) + id = "length"; + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + + do + { + c_token *next = c_parser_peek_token (parser); + int idx = 0; + + /* Gang static argument. */ + if (kind == OMP_CLAUSE_GANG + && c_parser_next_token_is_keyword (parser, RID_STATIC)) + { + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto cleanup_error; + + idx = 1; + if (ops[idx] != NULL_TREE) + { + c_parser_error (parser, "too many % arguments"); + goto cleanup_error; + } + + /* Check for the '*' argument. */ + if (c_parser_next_token_is (parser, CPP_MULT) + && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA + || c_parser_peek_2nd_token (parser)->type + == CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + ops[idx] = integer_minus_one_node; + + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + continue; + } + else + break; + } + } + /* Worker num: argument and vector length: arguments. */ + else if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (id, IDENTIFIER_POINTER (next->value)) == 0 + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + c_parser_consume_token (parser); /* id */ + c_parser_consume_token (parser); /* ':' */ + } + + /* Now collect the actual argument. */ + if (ops[idx] != NULL_TREE) + { + c_parser_error (parser, "unexpected argument"); + goto cleanup_error; + } + + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr cexpr = c_parser_expr_no_commas (parser, NULL); + cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true); + tree expr = cexpr.value; + if (expr == error_mark_node) + goto cleanup_error; + + expr = c_fully_fold (expr, false, NULL); + + /* Attempt to statically determine when the number isn't a + positive integer. */ + + if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + tree c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, expr, + build_int_cst (TREE_TYPE (expr), 0)); + if (c == boolean_true_node) + { + warning_at (loc, 0, + "%qs value must be positive", str); + expr = integer_one_node; + } + + ops[idx] = expr; + + if (kind == OMP_CLAUSE_GANG + && c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + continue; + } + break; + } + while (1); + + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + goto cleanup_error; + } + + check_no_duplicate_clause (list, kind, str); + + c = build_omp_clause (loc, kind); + + if (ops[1]) + OMP_CLAUSE_OPERAND (c, 1) = ops[1]; + + OMP_CLAUSE_OPERAND (c, 0) = ops[0]; + OMP_CLAUSE_CHAIN (c) = list; + + return c; + + cleanup_error: + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); + return list; +} + +/* OpenACC 2.5: + auto + finalize + independent + nohost + seq */ + +static tree +c_parser_oacc_simple_clause (location_t loc, enum omp_clause_code code, + tree list) +{ + check_no_duplicate_clause (list, code, omp_clause_code_name[code]); + + tree c = build_omp_clause (loc, code); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenACC: + async [( int-expr )] */ + +static tree +c_parser_oacc_clause_async (c_parser *parser, tree list) +{ + tree c, t; + location_t loc = c_parser_peek_token (parser)->location; + + t = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL); + + if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) + { + c_parser_consume_token (parser); + + t = c_parser_expr_no_commas (parser, NULL).value; + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + c_parser_error (parser, "expected integer expression"); + else if (t == error_mark_node + || !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return list; + } + else + t = c_fully_fold (t, false, NULL); + + check_no_duplicate_clause (list, OMP_CLAUSE_ASYNC, "async"); + + c = build_omp_clause (loc, OMP_CLAUSE_ASYNC); + OMP_CLAUSE_ASYNC_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + + return list; +} + +/* OpenACC 2.0: + tile ( size-expr-list ) */ + +static tree +c_parser_oacc_clause_tile (c_parser *parser, tree list) +{ + tree c, expr = error_mark_node; + location_t loc; + tree tile = NULL_TREE; + + check_no_duplicate_clause (list, OMP_CLAUSE_TILE, "tile"); + check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse"); + + loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + do + { + if (tile && !c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + return list; + + if (c_parser_next_token_is (parser, CPP_MULT) + && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA + || c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + expr = integer_zero_node; + } + else + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr cexpr = c_parser_expr_no_commas (parser, NULL); + cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true); + expr = cexpr.value; + + if (expr == error_mark_node) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return list; + } + + expr = c_fully_fold (expr, false, NULL); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) + || !tree_fits_shwi_p (expr) + || tree_to_shwi (expr) <= 0) + { + error_at (expr_loc, "% argument needs positive" + " integral constant"); + expr = integer_zero_node; + } + } + + tile = tree_cons (NULL_TREE, expr, tile); + } + while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)); + + /* Consume the trailing ')'. */ + c_parser_consume_token (parser); + + c = build_omp_clause (loc, OMP_CLAUSE_TILE); + tile = nreverse (tile); + OMP_CLAUSE_TILE_LIST (c) = tile; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenACC: + wait [( int-expr-list )] */ + +static tree +c_parser_oacc_clause_wait (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + + if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) + list = c_parser_oacc_wait_list (parser, clause_loc, list); + else + { + tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT); + + OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL); + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + + +/* OpenMP 5.0: + order ( concurrent ) + + OpenMP 5.1: + order ( order-modifier : concurrent ) + + order-modifier: + reproducible + unconstrained */ + +static tree +c_parser_omp_clause_order (c_parser *parser, tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree c; + const char *p; + bool unconstrained = false; + bool reproducible = false; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "unconstrained") == 0) + unconstrained = true; + else if (strcmp (p, "reproducible") == 0) + reproducible = true; + else + { + c_parser_error (parser, "expected % or " + "%"); + goto out_err; + } + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %"); + goto out_err; + } + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "concurrent") != 0) + { + c_parser_error (parser, "expected %"); + goto out_err; + } + c_parser_consume_token (parser); + parens.skip_until_found_close (parser); + check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order"); + c = build_omp_clause (loc, OMP_CLAUSE_ORDER); + OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = unconstrained; + OMP_CLAUSE_ORDER_REPRODUCIBLE (c) = reproducible; + OMP_CLAUSE_CHAIN (c) = list; + return c; + + out_err: + parens.skip_until_found_close (parser); + return list; +} + + +/* OpenMP 5.0: + bind ( teams | parallel | thread ) */ + +static tree +c_parser_omp_clause_bind (c_parser *parser, tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree c; + const char *p; + enum omp_clause_bind_kind kind = OMP_CLAUSE_BIND_THREAD; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + invalid: + c_parser_error (parser, + "expected %, % or %"); + parens.skip_until_found_close (parser); + return list; + } + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "teams") == 0) + kind = OMP_CLAUSE_BIND_TEAMS; + else if (strcmp (p, "parallel") == 0) + kind = OMP_CLAUSE_BIND_PARALLEL; + else if (strcmp (p, "thread") != 0) + goto invalid; + c_parser_consume_token (parser); + parens.skip_until_found_close (parser); + /* check_no_duplicate_clause (list, OMP_CLAUSE_BIND, "bind"); */ + c = build_omp_clause (loc, OMP_CLAUSE_BIND); + OMP_CLAUSE_BIND_KIND (c) = kind; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + + +/* OpenMP 2.5: + ordered + + OpenMP 4.5: + ordered ( constant-expression ) */ + +static tree +c_parser_omp_clause_ordered (c_parser *parser, tree list) +{ + check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered"); + + tree c, num = NULL_TREE; + HOST_WIDE_INT n; + location_t loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + matching_parens parens; + parens.consume_open (parser); + num = c_parser_expr_no_commas (parser, NULL).value; + parens.skip_until_found_close (parser); + } + if (num == error_mark_node) + return list; + if (num) + { + mark_exp_read (num); + num = c_fully_fold (num, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) + || !tree_fits_shwi_p (num) + || (n = tree_to_shwi (num)) <= 0 + || (int) n != n) + { + error_at (loc, "ordered argument needs positive " + "constant integer expression"); + return list; + } + } + c = build_omp_clause (loc, OMP_CLAUSE_ORDERED); + OMP_CLAUSE_ORDERED_EXPR (c) = num; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + private ( variable-list ) */ + +static tree +c_parser_omp_clause_private (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list); +} + +/* OpenMP 2.5: + reduction ( reduction-operator : variable-list ) + + reduction-operator: + One of: + * - & ^ | && || + + OpenMP 3.1: + + reduction-operator: + One of: + * - & ^ | && || max min + + OpenMP 4.0: + + reduction-operator: + One of: + * - & ^ | && || + identifier + + OpenMP 5.0: + reduction ( reduction-modifier, reduction-operator : variable-list ) + in_reduction ( reduction-operator : variable-list ) + task_reduction ( reduction-operator : variable-list ) */ + +static tree +c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind, + bool is_omp, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + bool task = false; + bool inscan = false; + enum tree_code code = ERROR_MARK; + tree reduc_id = NULL_TREE; + + if (kind == OMP_CLAUSE_REDUCTION && is_omp) + { + if (c_parser_next_token_is_keyword (parser, RID_DEFAULT) + && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "task") == 0) + task = true; + else if (strcmp (p, "inscan") == 0) + inscan = true; + if (task || inscan) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + } + } + + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + code = PLUS_EXPR; + break; + case CPP_MULT: + code = MULT_EXPR; + break; + case CPP_MINUS: + code = MINUS_EXPR; + break; + case CPP_AND: + code = BIT_AND_EXPR; + break; + case CPP_XOR: + code = BIT_XOR_EXPR; + break; + case CPP_OR: + code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + code = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + code = TRUTH_ORIF_EXPR; + break; + case CPP_NAME: + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "min") == 0) + { + code = MIN_EXPR; + break; + } + if (strcmp (p, "max") == 0) + { + code = MAX_EXPR; + break; + } + reduc_id = c_parser_peek_token (parser)->value; + break; + } + default: + c_parser_error (parser, + "expected %<+%>, %<*%>, %<-%>, %<&%>, " + "%<^%>, %<|%>, %<&&%>, %<||%> or identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); + return list; + } + c_parser_consume_token (parser); + reduc_id = c_omp_reduction_id (code, reduc_id); + if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + tree nl, c; + + nl = c_parser_omp_variable_list (parser, clause_loc, kind, list); + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + { + tree d = OMP_CLAUSE_DECL (c), type; + if (TREE_CODE (d) != TREE_LIST) + type = TREE_TYPE (d); + else + { + int cnt = 0; + tree t; + for (t = d; TREE_CODE (t) == TREE_LIST; t = TREE_CHAIN (t)) + cnt++; + type = TREE_TYPE (t); + while (cnt > 0) + { + if (TREE_CODE (type) != POINTER_TYPE + && TREE_CODE (type) != ARRAY_TYPE) + break; + type = TREE_TYPE (type); + cnt--; + } + } + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + OMP_CLAUSE_REDUCTION_CODE (c) = code; + if (task) + OMP_CLAUSE_REDUCTION_TASK (c) = 1; + else if (inscan) + OMP_CLAUSE_REDUCTION_INSCAN (c) = 1; + if (code == ERROR_MARK + || !(INTEGRAL_TYPE_P (type) + || TREE_CODE (type) == REAL_TYPE + || TREE_CODE (type) == COMPLEX_TYPE)) + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) + = c_omp_reduction_lookup (reduc_id, + TYPE_MAIN_VARIANT (type)); + } + + list = nl; + } + parens.skip_until_found_close (parser); + } + return list; +} + +/* OpenMP 2.5: + schedule ( schedule-kind ) + schedule ( schedule-kind , expression ) + + schedule-kind: + static | dynamic | guided | runtime | auto + + OpenMP 4.5: + schedule ( schedule-modifier : schedule-kind ) + schedule ( schedule-modifier [ , schedule-modifier ] : schedule-kind , expression ) + + schedule-modifier: + simd + monotonic + nonmonotonic */ + +static tree +c_parser_omp_clause_schedule (c_parser *parser, tree list) +{ + tree c, t; + location_t loc = c_parser_peek_token (parser)->location; + int modifiers = 0, nmodifiers = 0; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE); + + location_t comma = UNKNOWN_LOCATION; + while (c_parser_next_token_is (parser, CPP_NAME)) + { + tree kind = c_parser_peek_token (parser)->value; + const char *p = IDENTIFIER_POINTER (kind); + if (strcmp ("simd", p) == 0) + OMP_CLAUSE_SCHEDULE_SIMD (c) = 1; + else if (strcmp ("monotonic", p) == 0) + modifiers |= OMP_CLAUSE_SCHEDULE_MONOTONIC; + else if (strcmp ("nonmonotonic", p) == 0) + modifiers |= OMP_CLAUSE_SCHEDULE_NONMONOTONIC; + else + break; + comma = UNKNOWN_LOCATION; + c_parser_consume_token (parser); + if (nmodifiers++ == 0 + && c_parser_next_token_is (parser, CPP_COMMA)) + { + comma = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + } + else + { + c_parser_require (parser, CPP_COLON, "expected %<:%>"); + break; + } + } + if (comma != UNKNOWN_LOCATION) + error_at (comma, "expected %<:%>"); + + if ((modifiers & (OMP_CLAUSE_SCHEDULE_MONOTONIC + | OMP_CLAUSE_SCHEDULE_NONMONOTONIC)) + == (OMP_CLAUSE_SCHEDULE_MONOTONIC + | OMP_CLAUSE_SCHEDULE_NONMONOTONIC)) + { + error_at (loc, "both % and % modifiers " + "specified"); + modifiers = 0; + } + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree kind = c_parser_peek_token (parser)->value; + const char *p = IDENTIFIER_POINTER (kind); + + switch (p[0]) + { + case 'd': + if (strcmp ("dynamic", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC; + break; + + case 'g': + if (strcmp ("guided", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED; + break; + + case 'r': + if (strcmp ("runtime", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME; + break; + + default: + goto invalid_kind; + } + } + else if (c_parser_next_token_is_keyword (parser, RID_STATIC)) + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; + else if (c_parser_next_token_is_keyword (parser, RID_AUTO)) + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO; + else + goto invalid_kind; + + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + location_t here; + c_parser_consume_token (parser); + + here = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (here, expr, false, true); + t = expr.value; + t = c_fully_fold (t, false, NULL); + + if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) + error_at (here, "schedule % does not take " + "a % parameter"); + else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO) + error_at (here, + "schedule % does not take " + "a % parameter"); + else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE) + { + /* Attempt to statically determine when the number isn't + positive. */ + tree s = fold_build2_loc (loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + protected_set_expr_location (s, loc); + if (s == boolean_true_node) + { + warning_at (loc, 0, + "chunk size value must be positive"); + t = integer_one_node; + } + OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; + } + else + c_parser_error (parser, "expected integer expression"); + + parens.skip_until_found_close (parser); + } + else + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<,%> or %<)%>"); + + OMP_CLAUSE_SCHEDULE_KIND (c) + = (enum omp_clause_schedule_kind) + (OMP_CLAUSE_SCHEDULE_KIND (c) | modifiers); + + check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule"); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + c_parser_error (parser, "invalid schedule kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); + return list; +} + +/* OpenMP 2.5: + shared ( variable-list ) */ + +static tree +c_parser_omp_clause_shared (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list); +} + +/* OpenMP 3.0: + untied */ + +static tree +c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + /* FIXME: Should we allow duplicates? */ + check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied"); + + c = build_omp_clause (c_parser_peek_token (parser)->location, + OMP_CLAUSE_UNTIED); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + inbranch + notinbranch */ + +static tree +c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED, + enum omp_clause_code code, tree list) +{ + check_no_duplicate_clause (list, code, omp_clause_code_name[code]); + + tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + parallel + for + sections + taskgroup */ + +static tree +c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED, + enum omp_clause_code code, tree list) +{ + tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.5: + nogroup */ + +static tree +c_parser_omp_clause_nogroup (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + check_no_duplicate_clause (list, OMP_CLAUSE_NOGROUP, "nogroup"); + tree c = build_omp_clause (c_parser_peek_token (parser)->location, + OMP_CLAUSE_NOGROUP); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.5: + simd + threads */ + +static tree +c_parser_omp_clause_orderedkind (c_parser *parser ATTRIBUTE_UNUSED, + enum omp_clause_code code, tree list) +{ + check_no_duplicate_clause (list, code, omp_clause_code_name[code]); + tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + num_teams ( expression ) + + OpenMP 5.1: + num_teams ( expression : expression ) */ + +static tree +c_parser_omp_clause_num_teams (c_parser *parser, tree list) +{ + location_t num_teams_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + location_t upper_loc = c_parser_peek_token (parser)->location; + location_t lower_loc = UNKNOWN_LOCATION; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (upper_loc, expr, false, true); + tree c, upper = expr.value, lower = NULL_TREE; + upper = c_fully_fold (upper, false, NULL); + + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + lower_loc = upper_loc; + lower = upper; + upper_loc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (upper_loc, expr, false, true); + upper = expr.value; + upper = c_fully_fold (upper, false, NULL); + } + + parens.skip_until_found_close (parser); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (upper)) + || (lower && !INTEGRAL_TYPE_P (TREE_TYPE (lower)))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (upper_loc, LE_EXPR, boolean_type_node, upper, + build_int_cst (TREE_TYPE (upper), 0)); + protected_set_expr_location (c, upper_loc); + if (c == boolean_true_node) + { + warning_at (upper_loc, 0, "% value must be positive"); + upper = integer_one_node; + } + if (lower) + { + c = fold_build2_loc (lower_loc, LE_EXPR, boolean_type_node, lower, + build_int_cst (TREE_TYPE (lower), 0)); + protected_set_expr_location (c, lower_loc); + if (c == boolean_true_node) + { + warning_at (lower_loc, 0, "% value must be positive"); + lower = NULL_TREE; + } + else if (TREE_CODE (lower) == INTEGER_CST + && TREE_CODE (upper) == INTEGER_CST + && tree_int_cst_lt (upper, lower)) + { + warning_at (lower_loc, 0, "% lower bound %qE bigger " + "than upper bound %qE", lower, upper); + lower = NULL_TREE; + } + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, "num_teams"); + + c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS); + OMP_CLAUSE_NUM_TEAMS_UPPER_EXPR (c) = upper; + OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c) = lower; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.0: + thread_limit ( expression ) */ + +static tree +c_parser_omp_clause_thread_limit (c_parser *parser, tree list) +{ + location_t num_thread_limit_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + + parens.skip_until_found_close (parser); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + protected_set_expr_location (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "% value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT, + "thread_limit"); + + c = build_omp_clause (num_thread_limit_loc, OMP_CLAUSE_THREAD_LIMIT); + OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.0: + aligned ( variable-list ) + aligned ( variable-list : constant-expression ) */ + +static tree +c_parser_omp_clause_aligned (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, c; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_ALIGNED, list); + + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree alignment = expr.value; + alignment = c_fully_fold (alignment, false, NULL); + if (TREE_CODE (alignment) != INTEGER_CST + || !INTEGRAL_TYPE_P (TREE_TYPE (alignment)) + || tree_int_cst_sgn (alignment) != 1) + { + error_at (clause_loc, "% clause alignment expression must " + "be positive constant integer expression"); + alignment = NULL_TREE; + } + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; + } + + parens.skip_until_found_close (parser); + return nl; +} + +/* OpenMP 5.0: + allocate ( variable-list ) + allocate ( expression : variable-list ) + + OpenMP 5.1: + allocate ( allocator-modifier : variable-list ) + allocate ( allocator-modifier , allocator-modifier : variable-list ) + + allocator-modifier: + allocator ( expression ) + align ( expression ) */ + +static tree +c_parser_omp_clause_allocate (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, c; + tree allocator = NULL_TREE; + tree align = NULL_TREE; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if ((c_parser_next_token_is_not (parser, CPP_NAME) + && c_parser_next_token_is_not (parser, CPP_KEYWORD)) + || (c_parser_peek_2nd_token (parser)->type != CPP_COMMA + && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN)) + { + bool has_modifiers = false; + tree orig_type = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) + { + unsigned int n = 3; + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if ((strcmp (p, "allocator") == 0 || strcmp (p, "align") == 0) + && c_parser_check_balanced_raw_token_sequence (parser, &n) + && (c_parser_peek_nth_token_raw (parser, n)->type + == CPP_CLOSE_PAREN)) + { + if (c_parser_peek_nth_token_raw (parser, n + 1)->type + == CPP_COLON) + has_modifiers = true; + else if (c_parser_peek_nth_token_raw (parser, n + 1)->type + == CPP_COMMA + && (c_parser_peek_nth_token_raw (parser, n + 2)->type + == CPP_NAME) + && (c_parser_peek_nth_token_raw (parser, n + 3)->type + == CPP_OPEN_PAREN)) + { + c_token *tok = c_parser_peek_nth_token_raw (parser, n + 2); + const char *q = IDENTIFIER_POINTER (tok->value); + n += 4; + if ((strcmp (q, "allocator") == 0 + || strcmp (q, "align") == 0) + && c_parser_check_balanced_raw_token_sequence (parser, + &n) + && (c_parser_peek_nth_token_raw (parser, n)->type + == CPP_CLOSE_PAREN) + && (c_parser_peek_nth_token_raw (parser, n + 1)->type + == CPP_COLON)) + has_modifiers = true; + } + } + if (has_modifiers) + { + c_parser_consume_token (parser); + matching_parens parens2;; + parens2.require_open (parser); + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + if (strcmp (p, "allocator") == 0) + { + allocator = expr.value; + allocator = c_fully_fold (allocator, false, NULL); + orig_type = expr.original_type + ? expr.original_type : TREE_TYPE (allocator); + orig_type = TYPE_MAIN_VARIANT (orig_type); + } + else + { + align = expr.value; + align = c_fully_fold (align, false, NULL); + } + parens2.skip_until_found_close (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + c_token *tok = c_parser_peek_token (parser); + const char *q = ""; + if (c_parser_next_token_is (parser, CPP_NAME)) + q = IDENTIFIER_POINTER (tok->value); + if (strcmp (q, "allocator") != 0 && strcmp (q, "align") != 0) + { + c_parser_error (parser, "expected % or " + "%"); + parens.skip_until_found_close (parser); + return list; + } + else if (strcmp (p, q) == 0) + { + error_at (tok->location, "duplicate %qs modifier", p); + parens.skip_until_found_close (parser); + return list; + } + c_parser_consume_token (parser); + if (!parens2.require_open (parser)) + { + parens.skip_until_found_close (parser); + return list; + } + expr_loc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, + true); + if (strcmp (q, "allocator") == 0) + { + allocator = expr.value; + allocator = c_fully_fold (allocator, false, NULL); + orig_type = expr.original_type + ? expr.original_type : TREE_TYPE (allocator); + orig_type = TYPE_MAIN_VARIANT (orig_type); + } + else + { + align = expr.value; + align = c_fully_fold (align, false, NULL); + } + parens2.skip_until_found_close (parser); + } + } + } + if (!has_modifiers) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + allocator = expr.value; + allocator = c_fully_fold (allocator, false, NULL); + orig_type = expr.original_type + ? expr.original_type : TREE_TYPE (allocator); + orig_type = TYPE_MAIN_VARIANT (orig_type); + } + if (allocator + && (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) + || TREE_CODE (orig_type) != ENUMERAL_TYPE + || (TYPE_NAME (orig_type) + != get_identifier ("omp_allocator_handle_t")))) + { + error_at (clause_loc, "% clause allocator expression " + "has type %qT rather than " + "%", + TREE_TYPE (allocator)); + allocator = NULL_TREE; + } + if (align + && (!INTEGRAL_TYPE_P (TREE_TYPE (align)) + || !tree_fits_uhwi_p (align) + || !integer_pow2p (align))) + { + error_at (clause_loc, "% clause % modifier " + "argument needs to be positive constant " + "power of two integer expression"); + align = NULL_TREE; + } + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + parens.skip_until_found_close (parser); + return list; + } + } + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_ALLOCATE, list); + + if (allocator || align) + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + { + OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; + OMP_CLAUSE_ALLOCATE_ALIGN (c) = align; + } + + parens.skip_until_found_close (parser); + return nl; +} + +/* OpenMP 4.0: + linear ( variable-list ) + linear ( variable-list : expression ) + + OpenMP 4.5: + linear ( modifier ( variable-list ) ) + linear ( modifier ( variable-list ) : expression ) */ + +static tree +c_parser_omp_clause_linear (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, c, step; + enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *tok = c_parser_peek_token (parser); + const char *p = IDENTIFIER_POINTER (tok->value); + if (strcmp ("val", p) == 0) + kind = OMP_CLAUSE_LINEAR_VAL; + if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN) + kind = OMP_CLAUSE_LINEAR_DEFAULT; + if (kind != OMP_CLAUSE_LINEAR_DEFAULT) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + } + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_LINEAR, list); + + if (kind != OMP_CLAUSE_LINEAR_DEFAULT) + parens.skip_until_found_close (parser); + + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + step = expr.value; + step = c_fully_fold (step, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) + { + error_at (clause_loc, "% clause step expression must " + "be integral"); + step = integer_one_node; + } + + } + else + step = integer_one_node; + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + { + OMP_CLAUSE_LINEAR_STEP (c) = step; + OMP_CLAUSE_LINEAR_KIND (c) = kind; + } + + parens.skip_until_found_close (parser); + return nl; +} + +/* OpenMP 5.0: + nontemporal ( variable-list ) */ + +static tree +c_parser_omp_clause_nontemporal (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_NONTEMPORAL, list); +} + +/* OpenMP 4.0: + safelen ( constant-expression ) */ + +static tree +c_parser_omp_clause_safelen (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree c, t; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + t = expr.value; + t = c_fully_fold (t, false, NULL); + if (TREE_CODE (t) != INTEGER_CST + || !INTEGRAL_TYPE_P (TREE_TYPE (t)) + || tree_int_cst_sgn (t) != 1) + { + error_at (clause_loc, "% clause expression must " + "be positive constant integer expression"); + t = NULL_TREE; + } + + parens.skip_until_found_close (parser); + if (t == NULL_TREE || t == error_mark_node) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_SAFELEN, "safelen"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + simdlen ( constant-expression ) */ + +static tree +c_parser_omp_clause_simdlen (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree c, t; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + t = expr.value; + t = c_fully_fold (t, false, NULL); + if (TREE_CODE (t) != INTEGER_CST + || !INTEGRAL_TYPE_P (TREE_TYPE (t)) + || tree_int_cst_sgn (t) != 1) + { + error_at (clause_loc, "% clause expression must " + "be positive constant integer expression"); + t = NULL_TREE; + } + + parens.skip_until_found_close (parser); + if (t == NULL_TREE || t == error_mark_node) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN); + OMP_CLAUSE_SIMDLEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.5: + vec: + identifier [+/- integer] + vec , identifier [+/- integer] +*/ + +static tree +c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc, + tree list) +{ + tree vec = NULL; + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + c_parser_error (parser, "expected identifier"); + return list; + } + + while (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + tree t = lookup_name (c_parser_peek_token (parser)->value); + tree addend = NULL; + + if (t == NULL_TREE) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + t = error_mark_node; + } + + c_parser_consume_token (parser); + + bool neg = false; + if (c_parser_next_token_is (parser, CPP_MINUS)) + neg = true; + else if (!c_parser_next_token_is (parser, CPP_PLUS)) + { + addend = integer_zero_node; + neg = false; + goto add_to_vector; + } + c_parser_consume_token (parser); + + if (c_parser_next_token_is_not (parser, CPP_NUMBER)) + { + c_parser_error (parser, "expected integer"); + return list; + } + + addend = c_parser_peek_token (parser)->value; + if (TREE_CODE (addend) != INTEGER_CST) + { + c_parser_error (parser, "expected integer"); + return list; + } + c_parser_consume_token (parser); + + add_to_vector: + if (t != error_mark_node) + { + vec = tree_cons (addend, t, vec); + if (neg) + OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1; + } + + if (c_parser_next_token_is_not (parser, CPP_COMMA) + || c_parser_peek_2nd_token (parser)->type != CPP_NAME + || c_parser_peek_2nd_token (parser)->id_kind != C_ID_ID) + break; + + c_parser_consume_token (parser); + } + + if (vec == NULL_TREE) + return list; + + tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); + OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK; + OMP_CLAUSE_DECL (u) = nreverse (vec); + OMP_CLAUSE_CHAIN (u) = list; + return u; +} + +/* OpenMP 5.0: + iterators ( iterators-definition ) + + iterators-definition: + iterator-specifier + iterator-specifier , iterators-definition + + iterator-specifier: + identifier = range-specification + iterator-type identifier = range-specification + + range-specification: + begin : end + begin : end : step */ + +static tree +c_parser_omp_iterators (c_parser *parser) +{ + tree ret = NULL_TREE, *last = &ret; + c_parser_consume_token (parser); + + push_scope (); + + matching_parens parens; + if (!parens.require_open (parser)) + return error_mark_node; + + do + { + tree iter_type = NULL_TREE, type_expr = NULL_TREE; + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + struct c_type_name *type = c_parser_type_name (parser); + if (type != NULL) + iter_type = groktypename (type, &type_expr, NULL); + } + if (iter_type == NULL_TREE) + iter_type = integer_type_node; + + location_t loc = c_parser_peek_token (parser)->location; + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + break; + + location_t eloc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (eloc, expr, true, false); + tree begin = expr.value; + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + break; + + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (eloc, expr, true, false); + tree end = expr.value; + + tree step = integer_one_node; + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (eloc, expr, true, false); + step = expr.value; + } + + tree iter_var = build_decl (loc, VAR_DECL, id, iter_type); + DECL_ARTIFICIAL (iter_var) = 1; + DECL_CONTEXT (iter_var) = current_function_decl; + pushdecl (iter_var); + + *last = make_tree_vec (6); + TREE_VEC_ELT (*last, 0) = iter_var; + TREE_VEC_ELT (*last, 1) = begin; + TREE_VEC_ELT (*last, 2) = end; + TREE_VEC_ELT (*last, 3) = step; + last = &TREE_CHAIN (*last); + + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + continue; + } + break; + } + while (1); + + parens.skip_until_found_close (parser); + return ret ? ret : error_mark_node; +} + +/* OpenMP 5.0: + affinity ( [aff-modifier :] variable-list ) + aff-modifier: + iterator ( iterators-definition ) */ + +static tree +c_parser_omp_clause_affinity (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, iterators = NULL_TREE; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + bool parse_iter = ((strcmp ("iterator", p) == 0) + && (c_parser_peek_2nd_token (parser)->type + == CPP_OPEN_PAREN)); + if (parse_iter) + { + unsigned n = 3; + parse_iter = (c_parser_check_balanced_raw_token_sequence (parser, &n) + && (c_parser_peek_nth_token_raw (parser, n)->type + == CPP_CLOSE_PAREN) + && (c_parser_peek_nth_token_raw (parser, n + 1)->type + == CPP_COLON)); + } + if (parse_iter) + { + iterators = c_parser_omp_iterators (parser); + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + if (iterators) + pop_scope (); + parens.skip_until_found_close (parser); + return list; + } + } + } + nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_AFFINITY, + list); + if (iterators) + { + tree block = pop_scope (); + if (iterators != error_mark_node) + { + TREE_VEC_ELT (iterators, 5) = block; + for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_DECL (c) = build_tree_list (iterators, + OMP_CLAUSE_DECL (c)); + } + } + + parens.skip_until_found_close (parser); + return nl; +} + + +/* OpenMP 4.0: + depend ( depend-kind: variable-list ) + + depend-kind: + in | out | inout + + OpenMP 4.5: + depend ( source ) + + depend ( sink : vec ) + + OpenMP 5.0: + depend ( depend-modifier , depend-kind: variable-list ) + + depend-kind: + in | out | inout | mutexinoutset | depobj + + depend-modifier: + iterator ( iterators-definition ) */ + +static tree +c_parser_omp_clause_depend (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST; + tree nl, c, iterators = NULL_TREE; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + do + { + if (c_parser_next_token_is_not (parser, CPP_NAME)) + goto invalid_kind; + + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("iterator", p) == 0 && iterators == NULL_TREE) + { + iterators = c_parser_omp_iterators (parser); + c_parser_require (parser, CPP_COMMA, "expected %<,%>"); + continue; + } + if (strcmp ("in", p) == 0) + kind = OMP_CLAUSE_DEPEND_IN; + else if (strcmp ("inout", p) == 0) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (strcmp ("mutexinoutset", p) == 0) + kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; + else if (strcmp ("out", p) == 0) + kind = OMP_CLAUSE_DEPEND_OUT; + else if (strcmp ("depobj", p) == 0) + kind = OMP_CLAUSE_DEPEND_DEPOBJ; + else if (strcmp ("sink", p) == 0) + kind = OMP_CLAUSE_DEPEND_SINK; + else if (strcmp ("source", p) == 0) + kind = OMP_CLAUSE_DEPEND_SOURCE; + else + goto invalid_kind; + break; + } + while (1); + + c_parser_consume_token (parser); + + if (iterators + && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK)) + { + pop_scope (); + error_at (clause_loc, "% modifier incompatible with %qs", + kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + iterators = NULL_TREE; + } + + if (kind == OMP_CLAUSE_DEPEND_SOURCE) + { + c = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); + OMP_CLAUSE_DEPEND_KIND (c) = kind; + OMP_CLAUSE_DECL (c) = NULL_TREE; + OMP_CLAUSE_CHAIN (c) = list; + parens.skip_until_found_close (parser); + return c; + } + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto resync_fail; + + if (kind == OMP_CLAUSE_DEPEND_SINK) + nl = c_parser_omp_clause_depend_sink (parser, clause_loc, list); + else + { + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_DEPEND, list); + + if (iterators) + { + tree block = pop_scope (); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + { + OMP_CLAUSE_DEPEND_KIND (c) = kind; + if (iterators) + OMP_CLAUSE_DECL (c) + = build_tree_list (iterators, OMP_CLAUSE_DECL (c)); + } + } + + parens.skip_until_found_close (parser); + return nl; + + invalid_kind: + c_parser_error (parser, "invalid depend kind"); + resync_fail: + parens.skip_until_found_close (parser); + if (iterators) + pop_scope (); + return list; +} + +/* OpenMP 4.0: + map ( map-kind: variable-list ) + map ( variable-list ) + + map-kind: + alloc | to | from | tofrom + + OpenMP 4.5: + map-kind: + alloc | to | from | tofrom | release | delete + + map ( always [,] map-kind: variable-list ) + + OpenMP 5.0: + map ( [map-type-modifier[,] ...] map-kind: variable-list ) + + map-type-modifier: + always | close */ + +static tree +c_parser_omp_clause_map (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum gomp_map_kind kind = GOMP_MAP_TOFROM; + tree nl, c; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + int pos = 1; + int map_kind_pos = 0; + while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME) + { + if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COLON) + { + map_kind_pos = pos; + break; + } + + if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA) + pos++; + pos++; + } + + int always_modifier = 0; + int close_modifier = 0; + for (int pos = 1; pos < map_kind_pos; ++pos) + { + c_token *tok = c_parser_peek_token (parser); + + if (tok->type == CPP_COMMA) + { + c_parser_consume_token (parser); + continue; + } + + const char *p = IDENTIFIER_POINTER (tok->value); + if (strcmp ("always", p) == 0) + { + if (always_modifier) + { + c_parser_error (parser, "too many % modifiers"); + parens.skip_until_found_close (parser); + return list; + } + always_modifier++; + } + else if (strcmp ("close", p) == 0) + { + if (close_modifier) + { + c_parser_error (parser, "too many % modifiers"); + parens.skip_until_found_close (parser); + return list; + } + close_modifier++; + } + else + { + c_parser_error (parser, "%<#pragma omp target%> with " + "modifier other than % or %" + "on % clause"); + parens.skip_until_found_close (parser); + return list; + } + + c_parser_consume_token (parser); + } + + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("alloc", p) == 0) + kind = GOMP_MAP_ALLOC; + else if (strcmp ("to", p) == 0) + kind = always_modifier ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO; + else if (strcmp ("from", p) == 0) + kind = always_modifier ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM; + else if (strcmp ("tofrom", p) == 0) + kind = always_modifier ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM; + else if (strcmp ("release", p) == 0) + kind = GOMP_MAP_RELEASE; + else if (strcmp ("delete", p) == 0) + kind = GOMP_MAP_DELETE; + else + { + c_parser_error (parser, "invalid map kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return list; + } + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + + nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list, + true); + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_SET_MAP_KIND (c, kind); + + parens.skip_until_found_close (parser); + return nl; +} + +/* OpenMP 4.0: + device ( expression ) + + OpenMP 5.0: + device ( [device-modifier :] integer-expression ) + + device-modifier: + ancestor | device_num */ + +static tree +c_parser_omp_clause_device (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + location_t expr_loc; + c_expr expr; + tree c, t; + bool ancestor = false; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + c_token *tok = c_parser_peek_token (parser); + const char *p = IDENTIFIER_POINTER (tok->value); + if (strcmp ("ancestor", p) == 0) + { + /* A requires directive with the reverse_offload clause must be + specified. */ + if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0) + { + error_at (tok->location, "% device modifier not " + "preceded by % directive " + "with % clause"); + parens.skip_until_found_close (parser); + return list; + } + ancestor = true; + } + else if (strcmp ("device_num", p) == 0) + ; + else + { + error_at (tok->location, "expected % or %"); + parens.skip_until_found_close (parser); + return list; + } + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + + expr_loc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + t = expr.value; + t = c_fully_fold (t, false, NULL); + + parens.skip_until_found_close (parser); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + if (ancestor && TREE_CODE (t) == INTEGER_CST && !integer_onep (t)) + { + error_at (expr_loc, "the % clause expression must evaluate to " + "%<1%>"); + return list; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, "device"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE); + + OMP_CLAUSE_DEVICE_ID (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + OMP_CLAUSE_DEVICE_ANCESTOR (c) = ancestor; + + list = c; + return list; +} + +/* OpenMP 4.0: + dist_schedule ( static ) + dist_schedule ( static , expression ) */ + +static tree +c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) +{ + tree c, t = NULL_TREE; + location_t loc = c_parser_peek_token (parser)->location; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (!c_parser_next_token_is_keyword (parser, RID_STATIC)) + { + c_parser_error (parser, "invalid dist_schedule kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return list; + } + + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + t = expr.value; + t = c_fully_fold (t, false, NULL); + parens.skip_until_found_close (parser); + } + else + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<,%> or %<)%>"); + + /* check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE, + "dist_schedule"); */ + if (omp_find_clause (list, OMP_CLAUSE_DIST_SCHEDULE)) + warning_at (loc, 0, "too many %qs clauses", "dist_schedule"); + if (t == error_mark_node) + return list; + + c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE); + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + proc_bind ( proc-bind-kind ) + + proc-bind-kind: + primary | master | close | spread + where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ + +static tree +c_parser_omp_clause_proc_bind (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_proc_bind_kind kind; + tree c; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("primary", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_PRIMARY; + else if (strcmp ("master", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_MASTER; + else if (strcmp ("close", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_CLOSE; + else if (strcmp ("spread", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_SPREAD; + else + goto invalid_kind; + } + else + goto invalid_kind; + + check_no_duplicate_clause (list, OMP_CLAUSE_PROC_BIND, "proc_bind"); + c_parser_consume_token (parser); + parens.skip_until_found_close (parser); + c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND); + OMP_CLAUSE_PROC_BIND_KIND (c) = kind; + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + c_parser_error (parser, "invalid proc_bind kind"); + parens.skip_until_found_close (parser); + return list; +} + +/* OpenMP 5.0: + device_type ( host | nohost | any ) */ + +static tree +c_parser_omp_clause_device_type (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_device_type_kind kind; + tree c; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("host", p) == 0) + kind = OMP_CLAUSE_DEVICE_TYPE_HOST; + else if (strcmp ("nohost", p) == 0) + kind = OMP_CLAUSE_DEVICE_TYPE_NOHOST; + else if (strcmp ("any", p) == 0) + kind = OMP_CLAUSE_DEVICE_TYPE_ANY; + else + goto invalid_kind; + } + else + goto invalid_kind; + + /* check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE, + "device_type"); */ + c_parser_consume_token (parser); + parens.skip_until_found_close (parser); + c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE_TYPE); + OMP_CLAUSE_DEVICE_TYPE_KIND (c) = kind; + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + c_parser_error (parser, "expected %, % or %"); + parens.skip_until_found_close (parser); + return list; +} + +/* OpenMP 4.0: + to ( variable-list ) */ + +static tree +c_parser_omp_clause_to (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true); +} + +/* OpenMP 4.0: + from ( variable-list ) */ + +static tree +c_parser_omp_clause_from (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list, true); +} + +/* OpenMP 4.0: + uniform ( variable-list ) */ + +static tree +c_parser_omp_clause_uniform (c_parser *parser, tree list) +{ + /* The clauses location. */ + location_t loc = c_parser_peek_token (parser)->location; + + matching_parens parens; + if (parens.require_open (parser)) + { + list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM, + list); + parens.skip_until_found_close (parser); + } + return list; +} + +/* OpenMP 5.0: + detach ( event-handle ) */ + +static tree +c_parser_omp_clause_detach (c_parser *parser, tree list) +{ + matching_parens parens; + location_t clause_loc = c_parser_peek_token (parser)->location; + + if (!parens.require_open (parser)) + return list; + + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + c_parser_error (parser, "expected identifier"); + parens.skip_until_found_close (parser); + return list; + } + + tree t = lookup_name (c_parser_peek_token (parser)->value); + if (t == NULL_TREE) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + parens.skip_until_found_close (parser); + return list; + } + c_parser_consume_token (parser); + + tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); + if (!INTEGRAL_TYPE_P (type) + || TREE_CODE (type) != ENUMERAL_TYPE + || TYPE_NAME (type) != get_identifier ("omp_event_handle_t")) + { + error_at (clause_loc, "% clause event handle " + "has type %qT rather than " + "%", + type); + parens.skip_until_found_close (parser); + return list; + } + + tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DETACH); + OMP_CLAUSE_DECL (u) = t; + OMP_CLAUSE_CHAIN (u) = list; + parens.skip_until_found_close (parser); + return u; +} + +/* Parse all OpenACC clauses. The set clauses allowed by the directive + is a bitmask in MASK. Return the list of clauses found. */ + +static tree +c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, + const char *where, bool finish_p = true) +{ + tree clauses = NULL; + bool first = true; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + location_t here; + pragma_omp_clause c_kind; + const char *c_name; + tree prev = clauses; + + if (!first && c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + + here = c_parser_peek_token (parser)->location; + c_kind = c_parser_omp_clause_name (parser); + + switch (c_kind) + { + case PRAGMA_OACC_CLAUSE_ASYNC: + clauses = c_parser_oacc_clause_async (parser, clauses); + c_name = "async"; + break; + case PRAGMA_OACC_CLAUSE_AUTO: + clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_AUTO, + clauses); + c_name = "auto"; + break; + case PRAGMA_OACC_CLAUSE_ATTACH: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "attach"; + break; + case PRAGMA_OACC_CLAUSE_COLLAPSE: + clauses = c_parser_omp_clause_collapse (parser, clauses); + c_name = "collapse"; + break; + case PRAGMA_OACC_CLAUSE_COPY: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "copy"; + break; + case PRAGMA_OACC_CLAUSE_COPYIN: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "copyin"; + break; + case PRAGMA_OACC_CLAUSE_COPYOUT: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "copyout"; + break; + case PRAGMA_OACC_CLAUSE_CREATE: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "create"; + break; + case PRAGMA_OACC_CLAUSE_DELETE: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "delete"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULT: + clauses = c_parser_omp_clause_default (parser, clauses, true); + c_name = "default"; + break; + case PRAGMA_OACC_CLAUSE_DETACH: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "detach"; + break; + case PRAGMA_OACC_CLAUSE_DEVICE: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "device"; + break; + case PRAGMA_OACC_CLAUSE_DEVICEPTR: + clauses = c_parser_oacc_data_clause_deviceptr (parser, clauses); + c_name = "deviceptr"; + break; + case PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "device_resident"; + break; + case PRAGMA_OACC_CLAUSE_FINALIZE: + clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_FINALIZE, + clauses); + c_name = "finalize"; + break; + case PRAGMA_OACC_CLAUSE_FIRSTPRIVATE: + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + c_name = "firstprivate"; + break; + case PRAGMA_OACC_CLAUSE_GANG: + c_name = "gang"; + clauses = c_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_GANG, + c_name, clauses); + break; + case PRAGMA_OACC_CLAUSE_HOST: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "host"; + break; + case PRAGMA_OACC_CLAUSE_IF: + clauses = c_parser_omp_clause_if (parser, clauses, false); + c_name = "if"; + break; + case PRAGMA_OACC_CLAUSE_IF_PRESENT: + clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_IF_PRESENT, + clauses); + c_name = "if_present"; + break; + case PRAGMA_OACC_CLAUSE_INDEPENDENT: + clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_INDEPENDENT, + clauses); + c_name = "independent"; + break; + case PRAGMA_OACC_CLAUSE_LINK: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "link"; + break; + case PRAGMA_OACC_CLAUSE_NO_CREATE: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "no_create"; + break; + case PRAGMA_OACC_CLAUSE_NOHOST: + clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_NOHOST, + clauses); + c_name = "nohost"; + break; + case PRAGMA_OACC_CLAUSE_NUM_GANGS: + clauses = c_parser_oacc_single_int_clause (parser, + OMP_CLAUSE_NUM_GANGS, + clauses); + c_name = "num_gangs"; + break; + case PRAGMA_OACC_CLAUSE_NUM_WORKERS: + clauses = c_parser_oacc_single_int_clause (parser, + OMP_CLAUSE_NUM_WORKERS, + clauses); + c_name = "num_workers"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present"; + break; + case PRAGMA_OACC_CLAUSE_PRIVATE: + clauses = c_parser_omp_clause_private (parser, clauses); + c_name = "private"; + break; + case PRAGMA_OACC_CLAUSE_REDUCTION: + clauses + = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION, + false, clauses); + c_name = "reduction"; + break; + case PRAGMA_OACC_CLAUSE_SEQ: + clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_SEQ, + clauses); + c_name = "seq"; + break; + case PRAGMA_OACC_CLAUSE_TILE: + clauses = c_parser_oacc_clause_tile (parser, clauses); + c_name = "tile"; + break; + case PRAGMA_OACC_CLAUSE_USE_DEVICE: + clauses = c_parser_omp_clause_use_device_ptr (parser, clauses); + c_name = "use_device"; + break; + case PRAGMA_OACC_CLAUSE_VECTOR: + c_name = "vector"; + clauses = c_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_VECTOR, + c_name, clauses); + break; + case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH: + clauses = c_parser_oacc_single_int_clause (parser, + OMP_CLAUSE_VECTOR_LENGTH, + clauses); + c_name = "vector_length"; + break; + case PRAGMA_OACC_CLAUSE_WAIT: + clauses = c_parser_oacc_clause_wait (parser, clauses); + c_name = "wait"; + break; + case PRAGMA_OACC_CLAUSE_WORKER: + c_name = "worker"; + clauses = c_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_WORKER, + c_name, clauses); + break; + default: + c_parser_error (parser, "expected %<#pragma acc%> clause"); + goto saw_error; + } + + first = false; + + if (((mask >> c_kind) & 1) == 0) + { + /* Remove the invalid clause(s) from the list to avoid + confusing the rest of the compiler. */ + clauses = prev; + error_at (here, "%qs is not valid for %qs", c_name, where); + } + } + + saw_error: + c_parser_skip_to_pragma_eol (parser); + + if (finish_p) + return c_finish_omp_clauses (clauses, C_ORT_ACC); + + return clauses; +} + +/* Parse all OpenMP clauses. The set clauses allowed by the directive + is a bitmask in MASK. Return the list of clauses found. + FINISH_P set if c_finish_omp_clauses should be called. + NESTED non-zero if clauses should be terminated by closing paren instead + of end of pragma. If it is 2, additionally commas are required in between + the clauses. */ + +static tree +c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, + const char *where, bool finish_p = true, + int nested = 0) +{ + tree clauses = NULL; + bool first = true; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + location_t here; + pragma_omp_clause c_kind; + const char *c_name; + tree prev = clauses; + + if (nested && c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + break; + + if (!first) + { + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else if (nested == 2) + error_at (c_parser_peek_token (parser)->location, + "clauses in % trait should be separated " + "by %<,%>"); + } + + here = c_parser_peek_token (parser)->location; + c_kind = c_parser_omp_clause_name (parser); + + switch (c_kind) + { + case PRAGMA_OMP_CLAUSE_BIND: + clauses = c_parser_omp_clause_bind (parser, clauses); + c_name = "bind"; + break; + case PRAGMA_OMP_CLAUSE_COLLAPSE: + clauses = c_parser_omp_clause_collapse (parser, clauses); + c_name = "collapse"; + break; + case PRAGMA_OMP_CLAUSE_COPYIN: + clauses = c_parser_omp_clause_copyin (parser, clauses); + c_name = "copyin"; + break; + case PRAGMA_OMP_CLAUSE_COPYPRIVATE: + clauses = c_parser_omp_clause_copyprivate (parser, clauses); + c_name = "copyprivate"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULT: + clauses = c_parser_omp_clause_default (parser, clauses, false); + c_name = "default"; + break; + case PRAGMA_OMP_CLAUSE_DETACH: + clauses = c_parser_omp_clause_detach (parser, clauses); + c_name = "detach"; + break; + case PRAGMA_OMP_CLAUSE_FILTER: + clauses = c_parser_omp_clause_filter (parser, clauses); + c_name = "filter"; + break; + case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + c_name = "firstprivate"; + break; + case PRAGMA_OMP_CLAUSE_FINAL: + clauses = c_parser_omp_clause_final (parser, clauses); + c_name = "final"; + break; + case PRAGMA_OMP_CLAUSE_GRAINSIZE: + clauses = c_parser_omp_clause_grainsize (parser, clauses); + c_name = "grainsize"; + break; + case PRAGMA_OMP_CLAUSE_HINT: + clauses = c_parser_omp_clause_hint (parser, clauses); + c_name = "hint"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULTMAP: + clauses = c_parser_omp_clause_defaultmap (parser, clauses); + c_name = "defaultmap"; + break; + case PRAGMA_OMP_CLAUSE_IF: + clauses = c_parser_omp_clause_if (parser, clauses, true); + c_name = "if"; + break; + case PRAGMA_OMP_CLAUSE_IN_REDUCTION: + clauses + = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_IN_REDUCTION, + true, clauses); + c_name = "in_reduction"; + break; + case PRAGMA_OMP_CLAUSE_LASTPRIVATE: + clauses = c_parser_omp_clause_lastprivate (parser, clauses); + c_name = "lastprivate"; + break; + case PRAGMA_OMP_CLAUSE_MERGEABLE: + clauses = c_parser_omp_clause_mergeable (parser, clauses); + c_name = "mergeable"; + break; + case PRAGMA_OMP_CLAUSE_NOWAIT: + clauses = c_parser_omp_clause_nowait (parser, clauses); + c_name = "nowait"; + break; + case PRAGMA_OMP_CLAUSE_NUM_TASKS: + clauses = c_parser_omp_clause_num_tasks (parser, clauses); + c_name = "num_tasks"; + break; + case PRAGMA_OMP_CLAUSE_NUM_THREADS: + clauses = c_parser_omp_clause_num_threads (parser, clauses); + c_name = "num_threads"; + break; + case PRAGMA_OMP_CLAUSE_ORDER: + clauses = c_parser_omp_clause_order (parser, clauses); + c_name = "order"; + break; + case PRAGMA_OMP_CLAUSE_ORDERED: + clauses = c_parser_omp_clause_ordered (parser, clauses); + c_name = "ordered"; + break; + case PRAGMA_OMP_CLAUSE_PRIORITY: + clauses = c_parser_omp_clause_priority (parser, clauses); + c_name = "priority"; + break; + case PRAGMA_OMP_CLAUSE_PRIVATE: + clauses = c_parser_omp_clause_private (parser, clauses); + c_name = "private"; + break; + case PRAGMA_OMP_CLAUSE_REDUCTION: + clauses + = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION, + true, clauses); + c_name = "reduction"; + break; + case PRAGMA_OMP_CLAUSE_SCHEDULE: + clauses = c_parser_omp_clause_schedule (parser, clauses); + c_name = "schedule"; + break; + case PRAGMA_OMP_CLAUSE_SHARED: + clauses = c_parser_omp_clause_shared (parser, clauses); + c_name = "shared"; + break; + case PRAGMA_OMP_CLAUSE_TASK_REDUCTION: + clauses + = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_TASK_REDUCTION, + true, clauses); + c_name = "task_reduction"; + break; + case PRAGMA_OMP_CLAUSE_UNTIED: + clauses = c_parser_omp_clause_untied (parser, clauses); + c_name = "untied"; + break; + case PRAGMA_OMP_CLAUSE_INBRANCH: + clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH, + clauses); + c_name = "inbranch"; + break; + case PRAGMA_OMP_CLAUSE_NONTEMPORAL: + clauses = c_parser_omp_clause_nontemporal (parser, clauses); + c_name = "nontemporal"; + break; + case PRAGMA_OMP_CLAUSE_NOTINBRANCH: + clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH, + clauses); + c_name = "notinbranch"; + break; + case PRAGMA_OMP_CLAUSE_PARALLEL: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL, + clauses); + c_name = "parallel"; + if (!first) + { + clause_not_first: + error_at (here, "%qs must be the first clause of %qs", + c_name, where); + clauses = prev; + } + break; + case PRAGMA_OMP_CLAUSE_FOR: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR, + clauses); + c_name = "for"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_SECTIONS: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS, + clauses); + c_name = "sections"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_TASKGROUP: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP, + clauses); + c_name = "taskgroup"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_LINK: + clauses + = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LINK, clauses); + c_name = "link"; + break; + case PRAGMA_OMP_CLAUSE_TO: + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0) + clauses + = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, + clauses); + else + clauses = c_parser_omp_clause_to (parser, clauses); + c_name = "to"; + break; + case PRAGMA_OMP_CLAUSE_FROM: + clauses = c_parser_omp_clause_from (parser, clauses); + c_name = "from"; + break; + case PRAGMA_OMP_CLAUSE_UNIFORM: + clauses = c_parser_omp_clause_uniform (parser, clauses); + c_name = "uniform"; + break; + case PRAGMA_OMP_CLAUSE_NUM_TEAMS: + clauses = c_parser_omp_clause_num_teams (parser, clauses); + c_name = "num_teams"; + break; + case PRAGMA_OMP_CLAUSE_THREAD_LIMIT: + clauses = c_parser_omp_clause_thread_limit (parser, clauses); + c_name = "thread_limit"; + break; + case PRAGMA_OMP_CLAUSE_ALIGNED: + clauses = c_parser_omp_clause_aligned (parser, clauses); + c_name = "aligned"; + break; + case PRAGMA_OMP_CLAUSE_ALLOCATE: + clauses = c_parser_omp_clause_allocate (parser, clauses); + c_name = "allocate"; + break; + case PRAGMA_OMP_CLAUSE_LINEAR: + clauses = c_parser_omp_clause_linear (parser, clauses); + c_name = "linear"; + break; + case PRAGMA_OMP_CLAUSE_AFFINITY: + clauses = c_parser_omp_clause_affinity (parser, clauses); + c_name = "affinity"; + break; + case PRAGMA_OMP_CLAUSE_DEPEND: + clauses = c_parser_omp_clause_depend (parser, clauses); + c_name = "depend"; + break; + case PRAGMA_OMP_CLAUSE_MAP: + clauses = c_parser_omp_clause_map (parser, clauses); + c_name = "map"; + break; + case PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR: + clauses = c_parser_omp_clause_use_device_ptr (parser, clauses); + c_name = "use_device_ptr"; + break; + case PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR: + clauses = c_parser_omp_clause_use_device_addr (parser, clauses); + c_name = "use_device_addr"; + break; + case PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR: + clauses = c_parser_omp_clause_is_device_ptr (parser, clauses); + c_name = "is_device_ptr"; + break; + case PRAGMA_OMP_CLAUSE_DEVICE: + clauses = c_parser_omp_clause_device (parser, clauses); + c_name = "device"; + break; + case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE: + clauses = c_parser_omp_clause_dist_schedule (parser, clauses); + c_name = "dist_schedule"; + break; + case PRAGMA_OMP_CLAUSE_PROC_BIND: + clauses = c_parser_omp_clause_proc_bind (parser, clauses); + c_name = "proc_bind"; + break; + case PRAGMA_OMP_CLAUSE_DEVICE_TYPE: + clauses = c_parser_omp_clause_device_type (parser, clauses); + c_name = "device_type"; + break; + case PRAGMA_OMP_CLAUSE_SAFELEN: + clauses = c_parser_omp_clause_safelen (parser, clauses); + c_name = "safelen"; + break; + case PRAGMA_OMP_CLAUSE_SIMDLEN: + clauses = c_parser_omp_clause_simdlen (parser, clauses); + c_name = "simdlen"; + break; + case PRAGMA_OMP_CLAUSE_NOGROUP: + clauses = c_parser_omp_clause_nogroup (parser, clauses); + c_name = "nogroup"; + break; + case PRAGMA_OMP_CLAUSE_THREADS: + clauses + = c_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_THREADS, + clauses); + c_name = "threads"; + break; + case PRAGMA_OMP_CLAUSE_SIMD: + clauses + = c_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_SIMD, + clauses); + c_name = "simd"; + break; + default: + c_parser_error (parser, "expected %<#pragma omp%> clause"); + goto saw_error; + } + + first = false; + + if (((mask >> c_kind) & 1) == 0) + { + /* Remove the invalid clause(s) from the list to avoid + confusing the rest of the compiler. */ + clauses = prev; + error_at (here, "%qs is not valid for %qs", c_name, where); + } + } + + saw_error: + if (!nested) + c_parser_skip_to_pragma_eol (parser); + + if (finish_p) + { + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0) + return c_finish_omp_clauses (clauses, C_ORT_OMP_DECLARE_SIMD); + return c_finish_omp_clauses (clauses, C_ORT_OMP); + } + + return clauses; +} + +/* OpenACC 2.0, OpenMP 2.5: + structured-block: + statement + + In practice, we're also interested in adding the statement to an + outer node. So it is convenient if we work around the fact that + c_parser_statement calls add_stmt. */ + +static tree +c_parser_omp_structured_block (c_parser *parser, bool *if_p) +{ + tree stmt = push_stmt_list (); + c_parser_statement (parser, if_p); + return pop_stmt_list (stmt); +} + +/* OpenACC 2.0: + # pragma acc cache (variable-list) new-line + + LOC is the location of the #pragma token. +*/ + +static tree +c_parser_oacc_cache (location_t loc, c_parser *parser) +{ + tree stmt, clauses; + + clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE__CACHE_, NULL); + clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); + + c_parser_skip_to_pragma_eol (parser); + + stmt = make_node (OACC_CACHE); + TREE_TYPE (stmt) = void_type_node; + OACC_CACHE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + + return stmt; +} + +/* OpenACC 2.0: + # pragma acc data oacc-data-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OACC_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT)) + +static tree +c_parser_oacc_data (location_t loc, c_parser *parser, bool *if_p) +{ + tree stmt, clauses, block; + + clauses = c_parser_oacc_all_clauses (parser, OACC_DATA_CLAUSE_MASK, + "#pragma acc data"); + + block = c_begin_omp_parallel (); + add_stmt (c_parser_omp_structured_block (parser, if_p)); + + stmt = c_finish_oacc_data (loc, clauses, block); + + return stmt; +} + +/* OpenACC 2.0: + # pragma acc declare oacc-data-clause[optseq] new-line +*/ + +#define OACC_DECLARE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_LINK) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT)) + +static void +c_parser_oacc_declare (c_parser *parser) +{ + location_t pragma_loc = c_parser_peek_token (parser)->location; + tree clauses, stmt, t, decl; + + bool error = false; + + c_parser_consume_pragma (parser); + + clauses = c_parser_oacc_all_clauses (parser, OACC_DECLARE_CLAUSE_MASK, + "#pragma acc declare"); + if (!clauses) + { + error_at (pragma_loc, + "no valid clauses specified in %<#pragma acc declare%>"); + return; + } + + for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t)) + { + location_t loc = OMP_CLAUSE_LOCATION (t); + decl = OMP_CLAUSE_DECL (t); + if (!DECL_P (decl)) + { + error_at (loc, "array section in %<#pragma acc declare%>"); + error = true; + continue; + } + + switch (OMP_CLAUSE_MAP_KIND (t)) + { + case GOMP_MAP_FIRSTPRIVATE_POINTER: + case GOMP_MAP_ALLOC: + case GOMP_MAP_TO: + case GOMP_MAP_FORCE_DEVICEPTR: + case GOMP_MAP_DEVICE_RESIDENT: + break; + + case GOMP_MAP_LINK: + if (!global_bindings_p () + && (TREE_STATIC (decl) + || !DECL_EXTERNAL (decl))) + { + error_at (loc, + "%qD must be a global variable in " + "%<#pragma acc declare link%>", + decl); + error = true; + continue; + } + break; + + default: + if (global_bindings_p ()) + { + error_at (loc, "invalid OpenACC clause at file scope"); + error = true; + continue; + } + if (DECL_EXTERNAL (decl)) + { + error_at (loc, + "invalid use of % variable %qD " + "in %<#pragma acc declare%>", decl); + error = true; + continue; + } + else if (TREE_PUBLIC (decl)) + { + error_at (loc, + "invalid use of % variable %qD " + "in %<#pragma acc declare%>", decl); + error = true; + continue; + } + break; + } + + if (!c_check_in_current_scope (decl)) + { + error_at (loc, + "%qD must be a variable declared in the same scope as " + "%<#pragma acc declare%>", decl); + error = true; + continue; + } + + if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl)) + || lookup_attribute ("omp declare target link", + DECL_ATTRIBUTES (decl))) + { + error_at (loc, "variable %qD used more than once with " + "%<#pragma acc declare%>", decl); + error = true; + continue; + } + + if (!error) + { + tree id; + + if (OMP_CLAUSE_MAP_KIND (t) == GOMP_MAP_LINK) + id = get_identifier ("omp declare target link"); + else + id = get_identifier ("omp declare target"); + + DECL_ATTRIBUTES (decl) + = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (decl)); + + if (global_bindings_p ()) + { + symtab_node *node = symtab_node::get (decl); + if (node != NULL) + { + node->offloadable = 1; + if (ENABLE_OFFLOADING) + { + g->have_offload = true; + if (is_a (node)) + vec_safe_push (offload_vars, decl); + } + } + } + } + } + + if (error || global_bindings_p ()) + return; + + stmt = make_node (OACC_DECLARE); + TREE_TYPE (stmt) = void_type_node; + OACC_DECLARE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, pragma_loc); + + add_stmt (stmt); + + return; +} + +/* OpenACC 2.0: + # pragma acc enter data oacc-enter-data-clause[optseq] new-line + + or + + # pragma acc exit data oacc-exit-data-clause[optseq] new-line + + + LOC is the location of the #pragma token. +*/ + +#define OACC_ENTER_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +#define OACC_EXIT_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DELETE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DETACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FINALIZE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +static void +c_parser_oacc_enter_exit_data (c_parser *parser, bool enter) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree clauses, stmt; + const char *p = ""; + + c_parser_consume_pragma (parser); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + } + + if (strcmp (p, "data") != 0) + { + error_at (loc, "expected % after %<#pragma acc %s%>", + enter ? "enter" : "exit"); + parser->error = true; + c_parser_skip_to_pragma_eol (parser); + return; + } + + if (enter) + clauses = c_parser_oacc_all_clauses (parser, OACC_ENTER_DATA_CLAUSE_MASK, + "#pragma acc enter data"); + else + clauses = c_parser_oacc_all_clauses (parser, OACC_EXIT_DATA_CLAUSE_MASK, + "#pragma acc exit data"); + + if (omp_find_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE) + { + error_at (loc, "%<#pragma acc %s data%> has no data movement clause", + enter ? "enter" : "exit"); + return; + } + + stmt = enter ? make_node (OACC_ENTER_DATA) : make_node (OACC_EXIT_DATA); + TREE_TYPE (stmt) = void_type_node; + OMP_STANDALONE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); +} + + +/* OpenACC 2.0: + # pragma acc host_data oacc-data-clause[optseq] new-line + structured-block +*/ + +#define OACC_HOST_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_USE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) ) + +static tree +c_parser_oacc_host_data (location_t loc, c_parser *parser, bool *if_p) +{ + tree stmt, clauses, block; + + clauses = c_parser_oacc_all_clauses (parser, OACC_HOST_DATA_CLAUSE_MASK, + "#pragma acc host_data"); + + block = c_begin_omp_parallel (); + add_stmt (c_parser_omp_structured_block (parser, if_p)); + stmt = c_finish_oacc_host_data (loc, clauses, block); + return stmt; +} + + +/* OpenACC 2.0: + + # pragma acc loop oacc-loop-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OACC_LOOP_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_AUTO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_INDEPENDENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_TILE) ) +static tree +c_parser_oacc_loop (location_t loc, c_parser *parser, char *p_name, + omp_clause_mask mask, tree *cclauses, bool *if_p) +{ + bool is_parallel = ((mask >> PRAGMA_OACC_CLAUSE_REDUCTION) & 1) == 1; + + strcat (p_name, " loop"); + mask |= OACC_LOOP_CLAUSE_MASK; + + tree clauses = c_parser_oacc_all_clauses (parser, mask, p_name, + cclauses == NULL); + if (cclauses) + { + clauses = c_oacc_split_loop_clauses (clauses, cclauses, is_parallel); + if (*cclauses) + *cclauses = c_finish_omp_clauses (*cclauses, C_ORT_ACC); + if (clauses) + clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); + } + + tree block = c_begin_compound_stmt (true); + tree stmt = c_parser_omp_for_loop (loc, parser, OACC_LOOP, clauses, NULL, + if_p); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return stmt; +} + +/* OpenACC 2.0: + # pragma acc kernels oacc-kernels-clause[optseq] new-line + structured-block + + or + + # pragma acc parallel oacc-parallel-clause[optseq] new-line + structured-block + + OpenACC 2.6: + + # pragma acc serial oacc-serial-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OACC_KERNELS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +#define OACC_PARALLEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +#define OACC_SERIAL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +static tree +c_parser_oacc_compute (location_t loc, c_parser *parser, + enum pragma_kind p_kind, char *p_name, bool *if_p) +{ + omp_clause_mask mask; + enum tree_code code; + switch (p_kind) + { + case PRAGMA_OACC_KERNELS: + strcat (p_name, " kernels"); + mask = OACC_KERNELS_CLAUSE_MASK; + code = OACC_KERNELS; + break; + case PRAGMA_OACC_PARALLEL: + strcat (p_name, " parallel"); + mask = OACC_PARALLEL_CLAUSE_MASK; + code = OACC_PARALLEL; + break; + case PRAGMA_OACC_SERIAL: + strcat (p_name, " serial"); + mask = OACC_SERIAL_CLAUSE_MASK; + code = OACC_SERIAL; + break; + default: + gcc_unreachable (); + } + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "loop") == 0) + { + c_parser_consume_token (parser); + tree block = c_begin_omp_parallel (); + tree clauses; + c_parser_oacc_loop (loc, parser, p_name, mask, &clauses, if_p); + return c_finish_omp_construct (loc, code, block, clauses); + } + } + + tree clauses = c_parser_oacc_all_clauses (parser, mask, p_name); + + tree block = c_begin_omp_parallel (); + add_stmt (c_parser_omp_structured_block (parser, if_p)); + + return c_finish_omp_construct (loc, code, block, clauses); +} + +/* OpenACC 2.0: + # pragma acc routine oacc-routine-clause[optseq] new-line + function-definition + + # pragma acc routine ( name ) oacc-routine-clause[optseq] new-line +*/ + +#define OACC_ROUTINE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NOHOST) ) + +/* Parse an OpenACC routine directive. For named directives, we apply + immediately to the named function. For unnamed ones we then parse + a declaration or definition, which must be for a function. */ + +static void +c_parser_oacc_routine (c_parser *parser, enum pragma_context context) +{ + gcc_checking_assert (context == pragma_external); + + oacc_routine_data data; + data.error_seen = false; + data.fndecl_seen = false; + data.loc = c_parser_peek_token (parser)->location; + + c_parser_consume_pragma (parser); + + /* Look for optional '( name )'. */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); /* '(' */ + + tree decl = NULL_TREE; + c_token *name_token = c_parser_peek_token (parser); + location_t name_loc = name_token->location; + if (name_token->type == CPP_NAME + && (name_token->id_kind == C_ID_ID + || name_token->id_kind == C_ID_TYPENAME)) + { + decl = lookup_name (name_token->value); + if (!decl) + error_at (name_loc, + "%qE has not been declared", name_token->value); + c_parser_consume_token (parser); + } + else + c_parser_error (parser, "expected function name"); + + if (!decl + || !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + { + c_parser_skip_to_pragma_eol (parser, false); + return; + } + + data.clauses + = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, + "#pragma acc routine"); + /* The clauses are in reverse order; fix that to make later diagnostic + emission easier. */ + data.clauses = nreverse (data.clauses); + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_at (name_loc, "%qD does not refer to a function", decl); + return; + } + + c_finish_oacc_routine (&data, decl, false); + } + else /* No optional '( name )'. */ + { + data.clauses + = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, + "#pragma acc routine"); + /* The clauses are in reverse order; fix that to make later diagnostic + emission easier. */ + data.clauses = nreverse (data.clauses); + + /* Emit a helpful diagnostic if there's another pragma following this + one. Also don't allow a static assertion declaration, as in the + following we'll just parse a *single* "declaration or function + definition", and the static assertion counts an one. */ + if (c_parser_next_token_is (parser, CPP_PRAGMA) + || c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) + { + error_at (data.loc, + "%<#pragma acc routine%> not immediately followed by" + " function declaration or definition"); + /* ..., and then just keep going. */ + return; + } + + /* We only have to consider the pragma_external case here. */ + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION) + { + int ext = disable_extension_diagnostics (); + do + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, NULL, false, NULL, &data); + restore_extension_diagnostics (ext); + } + else + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, NULL, false, NULL, &data); + } +} + +/* Finalize an OpenACC routine pragma, applying it to FNDECL. + IS_DEFN is true if we're applying it to the definition. */ + +static void +c_finish_oacc_routine (struct oacc_routine_data *data, tree fndecl, + bool is_defn) +{ + /* Keep going if we're in error reporting mode. */ + if (data->error_seen + || fndecl == error_mark_node) + return; + + if (data->fndecl_seen) + { + error_at (data->loc, + "%<#pragma acc routine%> not immediately followed by" + " a single function declaration or definition"); + data->error_seen = true; + return; + } + if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) + { + error_at (data->loc, + "%<#pragma acc routine%> not immediately followed by" + " function declaration or definition"); + data->error_seen = true; + return; + } + + int compatible + = oacc_verify_routine_clauses (fndecl, &data->clauses, data->loc, + "#pragma acc routine"); + if (compatible < 0) + { + data->error_seen = true; + return; + } + if (compatible > 0) + { + } + else + { + if (TREE_USED (fndecl) || (!is_defn && DECL_SAVED_TREE (fndecl))) + { + error_at (data->loc, + TREE_USED (fndecl) + ? G_("%<#pragma acc routine%> must be applied before use") + : G_("%<#pragma acc routine%> must be applied before" + " definition")); + data->error_seen = true; + return; + } + + /* Set the routine's level of parallelism. */ + tree dims = oacc_build_routine_dims (data->clauses); + oacc_replace_fn_attrib (fndecl, dims); + + /* Add an "omp declare target" attribute. */ + DECL_ATTRIBUTES (fndecl) + = tree_cons (get_identifier ("omp declare target"), + data->clauses, DECL_ATTRIBUTES (fndecl)); + } + + /* Remember that we've used this "#pragma acc routine". */ + data->fndecl_seen = true; +} + +/* OpenACC 2.0: + # pragma acc update oacc-update-clause[optseq] new-line +*/ + +#define OACC_UPDATE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_HOST) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +static void +c_parser_oacc_update (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + + c_parser_consume_pragma (parser); + + tree clauses = c_parser_oacc_all_clauses (parser, OACC_UPDATE_CLAUSE_MASK, + "#pragma acc update"); + if (omp_find_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE) + { + error_at (loc, + "%<#pragma acc update%> must contain at least one " + "% or % or % clause"); + return; + } + + if (parser->error) + return; + + tree stmt = make_node (OACC_UPDATE); + TREE_TYPE (stmt) = void_type_node; + OACC_UPDATE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); +} + +/* OpenACC 2.0: + # pragma acc wait [(intseq)] oacc-wait-clause[optseq] new-line + + LOC is the location of the #pragma token. +*/ + +#define OACC_WAIT_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) ) + +static tree +c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name) +{ + tree clauses, list = NULL_TREE, stmt = NULL_TREE; + + if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) + list = c_parser_oacc_wait_list (parser, loc, list); + + strcpy (p_name, " wait"); + clauses = c_parser_oacc_all_clauses (parser, OACC_WAIT_CLAUSE_MASK, p_name); + stmt = c_finish_oacc_wait (loc, list, clauses); + add_stmt (stmt); + + return stmt; +} + +/* OpenMP 5.0: + # pragma omp allocate (list) [allocator(allocator)] */ + +static void +c_parser_omp_allocate (location_t loc, c_parser *parser) +{ + tree allocator = NULL_TREE; + tree nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ALLOCATE, NULL_TREE); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + matching_parens parens; + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + if (strcmp ("allocator", p) != 0) + error_at (c_parser_peek_token (parser)->location, + "expected %"); + else if (parens.require_open (parser)) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + allocator = expr.value; + allocator = c_fully_fold (allocator, false, NULL); + tree orig_type + = expr.original_type ? expr.original_type : TREE_TYPE (allocator); + orig_type = TYPE_MAIN_VARIANT (orig_type); + if (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) + || TREE_CODE (orig_type) != ENUMERAL_TYPE + || TYPE_NAME (orig_type) + != get_identifier ("omp_allocator_handle_t")) + { + error_at (expr_loc, "% clause allocator expression " + "has type %qT rather than " + "%", + TREE_TYPE (allocator)); + allocator = NULL_TREE; + } + parens.skip_until_found_close (parser); + } + } + c_parser_skip_to_pragma_eol (parser); + + if (allocator) + for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; + + sorry_at (loc, "%<#pragma omp allocate%> not yet supported"); +} + +/* OpenMP 2.5: + # pragma omp atomic new-line + expression-stmt + + expression-stmt: + x binop= expr | x++ | ++x | x-- | --x + binop: + +, *, -, /, &, ^, |, <<, >> + + where x is an lvalue expression with scalar type. + + OpenMP 3.1: + # pragma omp atomic new-line + update-stmt + + # pragma omp atomic read new-line + read-stmt + + # pragma omp atomic write new-line + write-stmt + + # pragma omp atomic update new-line + update-stmt + + # pragma omp atomic capture new-line + capture-stmt + + # pragma omp atomic capture new-line + capture-block + + read-stmt: + v = x + write-stmt: + x = expr + update-stmt: + expression-stmt | x = x binop expr + capture-stmt: + v = expression-stmt + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } + + OpenMP 4.0: + update-stmt: + expression-stmt | x = x binop expr | x = expr binop x + capture-stmt: + v = update-stmt + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } + + OpenMP 5.1: + # pragma omp atomic compare new-line + conditional-update-atomic + + # pragma omp atomic compare capture new-line + conditional-update-capture-atomic + + conditional-update-atomic: + cond-expr-stmt | cond-update-stmt + cond-expr-stmt: + x = expr ordop x ? expr : x; + x = x ordop expr ? expr : x; + x = x == e ? d : x; + cond-update-stmt: + if (expr ordop x) { x = expr; } + if (x ordop expr) { x = expr; } + if (x == e) { x = d; } + ordop: + <, > + conditional-update-capture-atomic: + v = cond-expr-stmt + { v = x; cond-expr-stmt } + { cond-expr-stmt v = x; } + { v = x; cond-update-stmt } + { cond-update-stmt v = x; } + if (x == e) { x = d; } else { v = x; } + { r = x == e; if (r) { x = d; } } + { r = x == e; if (r) { x = d; } else { v = x; } } + + where x, r and v are lvalue expressions with scalar type, + expr, e and d are expressions with scalar type and e might be + the same as v. + + LOC is the location of the #pragma token. */ + +static void +c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) +{ + tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, r = NULL_TREE; + tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; + tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE; + enum tree_code code = ERROR_MARK, opcode = NOP_EXPR; + enum omp_memory_order memory_order = OMP_MEMORY_ORDER_UNSPECIFIED; + struct c_expr expr; + location_t eloc; + bool structured_block = false; + bool swapped = false; + bool non_lvalue_p; + bool first = true; + tree clauses = NULL_TREE; + bool capture = false; + bool compare = false; + bool weak = false; + enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED; + bool no_semicolon = false; + bool extra_scope = false; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + if (!first + && c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + + first = false; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + location_t cloc = c_parser_peek_token (parser)->location; + enum tree_code new_code = ERROR_MARK; + enum omp_memory_order new_memory_order + = OMP_MEMORY_ORDER_UNSPECIFIED; + bool new_capture = false; + bool new_compare = false; + bool new_weak = false; + enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED; + + if (!strcmp (p, "read")) + new_code = OMP_ATOMIC_READ; + else if (!strcmp (p, "write")) + new_code = NOP_EXPR; + else if (!strcmp (p, "update")) + new_code = OMP_ATOMIC; + else if (openacc && !strcmp (p, "capture")) + new_code = OMP_ATOMIC_CAPTURE_NEW; + else if (openacc) + { + p = NULL; + error_at (cloc, "expected %, %, %, " + "or % clause"); + } + else if (!strcmp (p, "capture")) + new_capture = true; + else if (!strcmp (p, "compare")) + new_compare = true; + else if (!strcmp (p, "weak")) + new_weak = true; + else if (!strcmp (p, "fail")) + { + matching_parens parens; + + c_parser_consume_token (parser); + if (!parens.require_open (parser)) + continue; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *q + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (!strcmp (q, "seq_cst")) + new_fail = OMP_MEMORY_ORDER_SEQ_CST; + else if (!strcmp (q, "acquire")) + new_fail = OMP_MEMORY_ORDER_ACQUIRE; + else if (!strcmp (q, "relaxed")) + new_fail = OMP_MEMORY_ORDER_RELAXED; + } + + if (new_fail != OMP_MEMORY_ORDER_UNSPECIFIED) + { + c_parser_consume_token (parser); + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) + error_at (cloc, "too many %qs clauses", "fail"); + else + fail = new_fail; + } + else + c_parser_error (parser, "expected %, % " + "or %"); + parens.skip_until_found_close (parser); + continue; + } + else if (!strcmp (p, "seq_cst")) + new_memory_order = OMP_MEMORY_ORDER_SEQ_CST; + else if (!strcmp (p, "acq_rel")) + new_memory_order = OMP_MEMORY_ORDER_ACQ_REL; + else if (!strcmp (p, "release")) + new_memory_order = OMP_MEMORY_ORDER_RELEASE; + else if (!strcmp (p, "acquire")) + new_memory_order = OMP_MEMORY_ORDER_ACQUIRE; + else if (!strcmp (p, "relaxed")) + new_memory_order = OMP_MEMORY_ORDER_RELAXED; + else if (!strcmp (p, "hint")) + { + c_parser_consume_token (parser); + clauses = c_parser_omp_clause_hint (parser, clauses); + continue; + } + else + { + p = NULL; + error_at (cloc, "expected %, %, %, " + "%, %, %, %, " + "%, %, %, " + "% or % clause"); + } + if (p) + { + if (new_code != ERROR_MARK) + { + /* OpenACC permits 'update capture'. */ + if (openacc + && code == OMP_ATOMIC + && new_code == OMP_ATOMIC_CAPTURE_NEW) + code = new_code; + else if (code != ERROR_MARK) + error_at (cloc, "too many atomic clauses"); + else + code = new_code; + } + else if (new_memory_order != OMP_MEMORY_ORDER_UNSPECIFIED) + { + if (memory_order != OMP_MEMORY_ORDER_UNSPECIFIED) + error_at (cloc, "too many memory order clauses"); + else + memory_order = new_memory_order; + } + else if (new_capture) + { + if (capture) + error_at (cloc, "too many %qs clauses", "capture"); + else + capture = true; + } + else if (new_compare) + { + if (compare) + error_at (cloc, "too many %qs clauses", "compare"); + else + compare = true; + } + else if (new_weak) + { + if (weak) + error_at (cloc, "too many %qs clauses", "weak"); + else + weak = true; + } + c_parser_consume_token (parser); + continue; + } + } + break; + } + c_parser_skip_to_pragma_eol (parser); + + if (code == ERROR_MARK) + code = OMP_ATOMIC; + if (capture) + { + if (code != OMP_ATOMIC) + error_at (loc, "%qs clause is incompatible with % or % " + "clauses", "capture"); + else + code = OMP_ATOMIC_CAPTURE_NEW; + } + if (compare && code != OMP_ATOMIC && code != OMP_ATOMIC_CAPTURE_NEW) + { + error_at (loc, "%qs clause is incompatible with % or % " + "clauses", "compare"); + compare = false; + } + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare) + { + error_at (loc, "%qs clause requires %qs clause", "fail", "compare"); + fail = OMP_MEMORY_ORDER_UNSPECIFIED; + } + if (weak && !compare) + { + error_at (loc, "%qs clause requires %qs clause", "weak", "compare"); + weak = false; + } + if (openacc) + memory_order = OMP_MEMORY_ORDER_RELAXED; + else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED) + { + omp_requires_mask + = (enum omp_requires) (omp_requires_mask + | OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED); + switch ((enum omp_memory_order) + (omp_requires_mask & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER)) + { + case OMP_MEMORY_ORDER_UNSPECIFIED: + case OMP_MEMORY_ORDER_RELAXED: + memory_order = OMP_MEMORY_ORDER_RELAXED; + break; + case OMP_MEMORY_ORDER_SEQ_CST: + memory_order = OMP_MEMORY_ORDER_SEQ_CST; + break; + case OMP_MEMORY_ORDER_ACQ_REL: + switch (code) + { + case OMP_ATOMIC_READ: + memory_order = OMP_MEMORY_ORDER_ACQUIRE; + break; + case NOP_EXPR: /* atomic write */ + memory_order = OMP_MEMORY_ORDER_RELEASE; + break; + default: + memory_order = OMP_MEMORY_ORDER_ACQ_REL; + break; + } + break; + default: + gcc_unreachable (); + } + } + else + switch (code) + { + case OMP_ATOMIC_READ: + if (memory_order == OMP_MEMORY_ORDER_RELEASE) + { + error_at (loc, "%<#pragma omp atomic read%> incompatible with " + "% clause"); + memory_order = OMP_MEMORY_ORDER_SEQ_CST; + } + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) + memory_order = OMP_MEMORY_ORDER_ACQUIRE; + break; + case NOP_EXPR: /* atomic write */ + if (memory_order == OMP_MEMORY_ORDER_ACQUIRE) + { + error_at (loc, "%<#pragma omp atomic write%> incompatible with " + "% clause"); + memory_order = OMP_MEMORY_ORDER_SEQ_CST; + } + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) + memory_order = OMP_MEMORY_ORDER_RELEASE; + break; + default: + break; + } + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) + memory_order + = (enum omp_memory_order) (memory_order + | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT)); + + switch (code) + { + case OMP_ATOMIC_READ: + case NOP_EXPR: /* atomic write */ + v = c_parser_cast_expression (parser, NULL).value; + non_lvalue_p = !lvalue_p (v); + v = c_fully_fold (v, false, NULL, true); + if (v == error_mark_node) + goto saw_error; + if (non_lvalue_p) + v = non_lvalue (v); + loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + if (code == NOP_EXPR) + { + lhs = c_parser_expression (parser).value; + lhs = c_fully_fold (lhs, false, NULL); + if (lhs == error_mark_node) + goto saw_error; + } + else + { + lhs = c_parser_cast_expression (parser, NULL).value; + non_lvalue_p = !lvalue_p (lhs); + lhs = c_fully_fold (lhs, false, NULL, true); + if (lhs == error_mark_node) + goto saw_error; + if (non_lvalue_p) + lhs = non_lvalue (lhs); + } + if (code == NOP_EXPR) + { + /* atomic write is represented by OMP_ATOMIC with NOP_EXPR + opcode. */ + code = OMP_ATOMIC; + rhs = lhs; + lhs = v; + v = NULL_TREE; + } + goto done; + case OMP_ATOMIC_CAPTURE_NEW: + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + c_parser_consume_token (parser); + structured_block = true; + } + else if (compare + && c_parser_next_token_is_keyword (parser, RID_IF)) + break; + else + { + v = c_parser_cast_expression (parser, NULL).value; + non_lvalue_p = !lvalue_p (v); + v = c_fully_fold (v, false, NULL, true); + if (v == error_mark_node) + goto saw_error; + if (non_lvalue_p) + v = non_lvalue (v); + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + if (compare && c_parser_next_token_is_keyword (parser, RID_IF)) + { + eloc = c_parser_peek_token (parser)->location; + error_at (eloc, "expected expression"); + goto saw_error; + } + } + break; + default: + break; + } + + /* For structured_block case we don't know yet whether + old or new x should be captured. */ +restart: + if (compare && c_parser_next_token_is_keyword (parser, RID_IF)) + { + c_parser_consume_token (parser); + + matching_parens parens; + if (!parens.require_open (parser)) + goto saw_error; + eloc = c_parser_peek_token (parser)->location; + c_expr cmp_expr; + if (r) + { + cmp_expr = c_parser_cast_expression (parser, NULL); + cmp_expr = default_function_array_conversion (eloc, cmp_expr); + } + else + cmp_expr = c_parser_binary_expression (parser, NULL, void_list_node); + parens.skip_until_found_close (parser); + if (cmp_expr.value == error_mark_node) + goto saw_error; + if (r) + { + if (!c_tree_equal (cmp_expr.value, unfolded_lhs)) + goto bad_if; + cmp_expr.value = rhs1; + rhs1 = NULL_TREE; + gcc_assert (TREE_CODE (cmp_expr.value) == EQ_EXPR); + } + if (TREE_CODE (cmp_expr.value) == EQ_EXPR) + ; + else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), + "expected %<==%> comparison in % condition"); + goto saw_error; + } + else if (TREE_CODE (cmp_expr.value) != GT_EXPR + && TREE_CODE (cmp_expr.value) != LT_EXPR) + { + error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), + "expected %<==%>, %<<%> or %<>%> comparison in % " + "condition"); + goto saw_error; + } + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + goto saw_error; + + extra_scope = true; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_cast_expression (parser, NULL); + lhs = expr.value; + expr = default_function_array_conversion (eloc, expr); + unfolded_lhs = expr.value; + lhs = c_fully_fold (lhs, false, NULL, true); + orig_lhs = lhs; + if (lhs == error_mark_node) + goto saw_error; + if (!lvalue_p (unfolded_lhs)) + lhs = non_lvalue (lhs); + if (!c_parser_next_token_is (parser, CPP_EQ)) + { + c_parser_error (parser, "expected %<=%>"); + goto saw_error; + } + c_parser_consume_token (parser); + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + rhs1 = expr.value; + + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + goto saw_error; + + if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>")) + goto saw_error; + + extra_scope = false; + no_semicolon = true; + + if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), unfolded_lhs)) + { + if (TREE_CODE (cmp_expr.value) == EQ_EXPR) + { + opcode = COND_EXPR; + rhs = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1), + false, NULL, true); + rhs1 = c_fully_fold (rhs1, false, NULL, true); + } + else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), rhs1)) + { + opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR + ? MIN_EXPR : MAX_EXPR); + rhs = c_fully_fold (rhs1, false, NULL, true); + rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 0), + false, NULL, true); + } + else + goto bad_if; + } + else if (TREE_CODE (cmp_expr.value) == EQ_EXPR) + goto bad_if; + else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), unfolded_lhs) + && c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), rhs1)) + { + opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR + ? MAX_EXPR : MIN_EXPR); + rhs = c_fully_fold (rhs1, false, NULL, true); + rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1), + false, NULL, true); + } + else + { + bad_if: + c_parser_error (parser, + "invalid form of %<#pragma omp atomic compare%>"); + goto saw_error; + } + + if (c_parser_next_token_is_keyword (parser, RID_ELSE)) + { + if (code != OMP_ATOMIC_CAPTURE_NEW + || (structured_block && r == NULL_TREE) + || TREE_CODE (cmp_expr.value) != EQ_EXPR) + { + eloc = c_parser_peek_token (parser)->location; + error_at (eloc, "unexpected %"); + goto saw_error; + } + + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + goto saw_error; + + extra_scope = true; + v = c_parser_cast_expression (parser, NULL).value; + non_lvalue_p = !lvalue_p (v); + v = c_fully_fold (v, false, NULL, true); + if (v == error_mark_node) + goto saw_error; + if (non_lvalue_p) + v = non_lvalue (v); + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + + expr = c_parser_expr_no_commas (parser, NULL); + + if (!c_tree_equal (expr.value, unfolded_lhs)) + goto bad_if; + + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + goto saw_error; + + if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>")) + goto saw_error; + + extra_scope = false; + code = OMP_ATOMIC_CAPTURE_OLD; + if (r == NULL_TREE) + /* Signal to c_finish_omp_atomic that in + if (x == e) { x = d; } else { v = x; } + case the store to v should be conditional. */ + r = void_list_node; + } + else if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) + { + c_parser_require_keyword (parser, RID_ELSE, "expected %"); + goto saw_error; + } + else if (code == OMP_ATOMIC_CAPTURE_NEW + && r != NULL_TREE + && v == NULL_TREE) + code = OMP_ATOMIC; + goto stmt_done; + } + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_cast_expression (parser, NULL); + lhs = expr.value; + expr = default_function_array_conversion (eloc, expr); + unfolded_lhs = expr.value; + lhs = c_fully_fold (lhs, false, NULL, true); + orig_lhs = lhs; + switch (TREE_CODE (lhs)) + { + invalid_compare: + error_at (eloc, "invalid form of %"); + /* FALLTHRU */ + case ERROR_MARK: + saw_error: + c_parser_skip_to_end_of_block_or_statement (parser); + if (extra_scope && c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + c_parser_consume_token (parser); + if (structured_block) + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + c_parser_consume_token (parser); + else if (code == OMP_ATOMIC_CAPTURE_NEW) + { + c_parser_skip_to_end_of_block_or_statement (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + c_parser_consume_token (parser); + } + } + return; + + case POSTINCREMENT_EXPR: + if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) + code = OMP_ATOMIC_CAPTURE_OLD; + /* FALLTHROUGH */ + case PREINCREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; + opcode = PLUS_EXPR; + rhs = integer_one_node; + if (compare) + goto invalid_compare; + break; + + case POSTDECREMENT_EXPR: + if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) + code = OMP_ATOMIC_CAPTURE_OLD; + /* FALLTHROUGH */ + case PREDECREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; + opcode = MINUS_EXPR; + rhs = integer_one_node; + if (compare) + goto invalid_compare; + break; + + case COMPOUND_EXPR: + if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR + && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR + && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND + (TREE_OPERAND (lhs, 1), 0), 0))) + == BOOLEAN_TYPE) + /* Undo effects of boolean_increment for post {in,de}crement. */ + lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0); + /* FALLTHRU */ + case MODIFY_EXPR: + if (TREE_CODE (lhs) == MODIFY_EXPR + && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE) + { + /* Undo effects of boolean_increment. */ + if (integer_onep (TREE_OPERAND (lhs, 1))) + { + /* This is pre or post increment. */ + rhs = TREE_OPERAND (lhs, 1); + lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; + opcode = NOP_EXPR; + if (code == OMP_ATOMIC_CAPTURE_NEW + && !structured_block + && TREE_CODE (orig_lhs) == COMPOUND_EXPR) + code = OMP_ATOMIC_CAPTURE_OLD; + if (compare) + goto invalid_compare; + break; + } + if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR + && TREE_OPERAND (lhs, 0) + == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) + { + /* This is pre or post decrement. */ + rhs = TREE_OPERAND (lhs, 1); + lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; + opcode = NOP_EXPR; + if (code == OMP_ATOMIC_CAPTURE_NEW + && !structured_block + && TREE_CODE (orig_lhs) == COMPOUND_EXPR) + code = OMP_ATOMIC_CAPTURE_OLD; + if (compare) + goto invalid_compare; + break; + } + } + /* FALLTHRU */ + default: + if (!lvalue_p (unfolded_lhs)) + lhs = non_lvalue (lhs); + if (compare && !c_parser_next_token_is (parser, CPP_EQ)) + { + c_parser_error (parser, "expected %<=%>"); + goto saw_error; + } + switch (c_parser_peek_token (parser)->type) + { + case CPP_MULT_EQ: + opcode = MULT_EXPR; + break; + case CPP_DIV_EQ: + opcode = TRUNC_DIV_EXPR; + break; + case CPP_PLUS_EQ: + opcode = PLUS_EXPR; + break; + case CPP_MINUS_EQ: + opcode = MINUS_EXPR; + break; + case CPP_LSHIFT_EQ: + opcode = LSHIFT_EXPR; + break; + case CPP_RSHIFT_EQ: + opcode = RSHIFT_EXPR; + break; + case CPP_AND_EQ: + opcode = BIT_AND_EXPR; + break; + case CPP_OR_EQ: + opcode = BIT_IOR_EXPR; + break; + case CPP_XOR_EQ: + opcode = BIT_XOR_EXPR; + break; + case CPP_EQ: + c_parser_consume_token (parser); + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL, unfolded_lhs); + rhs1 = expr.value; + switch (TREE_CODE (rhs1)) + { + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case RDIV_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (compare) + break; + if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs)) + { + opcode = TREE_CODE (rhs1); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, + true); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL, + true); + goto stmt_done; + } + if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs)) + { + opcode = TREE_CODE (rhs1); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL, + true); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, + true); + swapped = !commutative_tree_code (opcode); + goto stmt_done; + } + break; + case COND_EXPR: + if (!compare) + break; + if (TREE_CODE (TREE_OPERAND (rhs1, 0)) != GT_EXPR + && TREE_CODE (TREE_OPERAND (rhs1, 0)) != LT_EXPR + && TREE_CODE (TREE_OPERAND (rhs1, 0)) != EQ_EXPR) + break; + if (!TREE_OPERAND (rhs1, 1)) + break; + if (!c_tree_equal (TREE_OPERAND (rhs1, 2), unfolded_lhs)) + break; + if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0), + unfolded_lhs)) + { + if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR) + { + opcode = COND_EXPR; + rhs = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, + 0), 1), + false, NULL, true); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, + NULL, true); + goto stmt_done; + } + if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), + TREE_OPERAND (rhs1, 1))) + { + opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR + ? MIN_EXPR : MAX_EXPR); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, + true); + rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, + 0), 0), + false, NULL, true); + goto stmt_done; + } + } + else if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR) + break; + else if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), + unfolded_lhs)) + { + if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0), + TREE_OPERAND (rhs1, 1))) + { + opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR + ? MAX_EXPR : MIN_EXPR); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, + true); + rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, + 0), 1), + false, NULL, true); + goto stmt_done; + } + } + break; + case EQ_EXPR: + if (!compare + || code != OMP_ATOMIC_CAPTURE_NEW + || !structured_block + || v + || r) + break; + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + && c_parser_peek_2nd_token (parser)->keyword == RID_IF) + { + r = lhs; + lhs = NULL_TREE; + c_parser_consume_token (parser); + goto restart; + } + break; + case ERROR_MARK: + goto saw_error; + default: + break; + } + if (c_parser_peek_token (parser)->type == CPP_SEMICOLON) + { + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + code = OMP_ATOMIC_CAPTURE_OLD; + v = lhs; + lhs = NULL_TREE; + expr = default_function_array_read_conversion (eloc, expr); + unfolded_lhs1 = expr.value; + lhs1 = c_fully_fold (unfolded_lhs1, false, NULL, true); + rhs1 = NULL_TREE; + c_parser_consume_token (parser); + goto restart; + } + if (structured_block && !compare) + { + opcode = NOP_EXPR; + expr = default_function_array_read_conversion (eloc, expr); + rhs = c_fully_fold (expr.value, false, NULL, true); + rhs1 = NULL_TREE; + goto stmt_done; + } + } + c_parser_error (parser, "invalid form of %<#pragma omp atomic%>"); + goto saw_error; + default: + c_parser_error (parser, + "invalid operator for %<#pragma omp atomic%>"); + goto saw_error; + } + + /* Arrange to pass the location of the assignment operator to + c_finish_omp_atomic. */ + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expression (parser); + expr = default_function_array_read_conversion (eloc, expr); + rhs = expr.value; + rhs = c_fully_fold (rhs, false, NULL, true); + break; + } +stmt_done: + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW && r == NULL_TREE) + { + if (!no_semicolon + && !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + goto saw_error; + no_semicolon = false; + v = c_parser_cast_expression (parser, NULL).value; + non_lvalue_p = !lvalue_p (v); + v = c_fully_fold (v, false, NULL, true); + if (v == error_mark_node) + goto saw_error; + if (non_lvalue_p) + v = non_lvalue (v); + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_cast_expression (parser, NULL); + lhs1 = expr.value; + expr = default_function_array_read_conversion (eloc, expr); + unfolded_lhs1 = expr.value; + lhs1 = c_fully_fold (lhs1, false, NULL, true); + if (lhs1 == error_mark_node) + goto saw_error; + if (!lvalue_p (unfolded_lhs1)) + lhs1 = non_lvalue (lhs1); + } + if (structured_block) + { + if (!no_semicolon) + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); + } +done: + if (weak && opcode != COND_EXPR) + { + error_at (loc, "% clause requires atomic equality comparison"); + weak = false; + } + if (unfolded_lhs && unfolded_lhs1 + && !c_tree_equal (unfolded_lhs, unfolded_lhs1)) + { + error ("%<#pragma omp atomic capture%> uses two different " + "expressions for memory"); + stmt = error_mark_node; + } + else + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, r, + swapped, memory_order, weak); + if (stmt != error_mark_node) + add_stmt (stmt); + + if (!structured_block && !no_semicolon) + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); +} + + +/* OpenMP 2.5: + # pragma omp barrier new-line +*/ + +static void +c_parser_omp_barrier (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_barrier (loc); +} + +/* OpenMP 2.5: + # pragma omp critical [(name)] new-line + structured-block + + OpenMP 4.5: + # pragma omp critical [(name) [hint(expression)]] new-line + + LOC is the location of the #pragma itself. */ + +#define OMP_CRITICAL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HINT) ) + +static tree +c_parser_omp_critical (location_t loc, c_parser *parser, bool *if_p) +{ + tree stmt, name = NULL_TREE, clauses = NULL_TREE; + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + c_parser_error (parser, "expected identifier"); + + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + } + clauses = c_parser_omp_all_clauses (parser, OMP_CRITICAL_CLAUSE_MASK, + "#pragma omp critical"); + stmt = c_parser_omp_structured_block (parser, if_p); + return c_finish_omp_critical (loc, stmt, name, clauses); +} + +/* OpenMP 5.0: + # pragma omp depobj ( depobj ) depobj-clause new-line + + depobj-clause: + depend (dependence-type : locator) + destroy + update (dependence-type) + + dependence-type: + in + out + inout + mutexinout */ + +static void +c_parser_omp_depobj (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + c_parser_skip_to_pragma_eol (parser); + return; + } + + tree depobj = c_parser_expr_no_commas (parser, NULL).value; + if (depobj != error_mark_node) + { + if (!lvalue_p (depobj)) + { + error_at (EXPR_LOC_OR_LOC (depobj, loc), + "% expression is not lvalue expression"); + depobj = error_mark_node; + } + else + { + tree addr = build_unary_op (EXPR_LOC_OR_LOC (depobj, loc), ADDR_EXPR, + depobj, false); + if (addr == error_mark_node) + depobj = error_mark_node; + else + depobj = build_indirect_ref (EXPR_LOC_OR_LOC (depobj, loc), + addr, RO_UNARY_STAR); + } + } + + parens.skip_until_found_close (parser); + tree clause = NULL_TREE; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE; + location_t c_loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + c_parser_consume_token (parser); + if (!strcmp ("depend", p)) + { + clause = c_parser_omp_clause_depend (parser, NULL_TREE); + clause = c_finish_omp_clauses (clause, C_ORT_OMP); + if (!clause) + clause = error_mark_node; + } + else if (!strcmp ("destroy", p)) + kind = OMP_CLAUSE_DEPEND_LAST; + else if (!strcmp ("update", p)) + { + matching_parens c_parens; + if (c_parens.require_open (parser)) + { + location_t c2_loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p2 + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + c_parser_consume_token (parser); + if (!strcmp ("in", p2)) + kind = OMP_CLAUSE_DEPEND_IN; + else if (!strcmp ("out", p2)) + kind = OMP_CLAUSE_DEPEND_OUT; + else if (!strcmp ("inout", p2)) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (!strcmp ("mutexinoutset", p2)) + kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; + } + if (kind == OMP_CLAUSE_DEPEND_SOURCE) + { + clause = error_mark_node; + error_at (c2_loc, "expected %, %, % or " + "%"); + } + c_parens.skip_until_found_close (parser); + } + else + clause = error_mark_node; + } + } + if (!clause && kind == OMP_CLAUSE_DEPEND_SOURCE) + { + clause = error_mark_node; + error_at (c_loc, "expected %, % or % clause"); + } + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_depobj (loc, depobj, kind, clause); +} + + +/* OpenMP 2.5: + # pragma omp flush flush-vars[opt] new-line + + flush-vars: + ( variable-list ) + + OpenMP 5.0: + # pragma omp flush memory-order-clause new-line */ + +static void +c_parser_omp_flush (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + enum memmodel mo = MEMMODEL_LAST; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (!strcmp (p, "seq_cst")) + mo = MEMMODEL_SEQ_CST; + else if (!strcmp (p, "acq_rel")) + mo = MEMMODEL_ACQ_REL; + else if (!strcmp (p, "release")) + mo = MEMMODEL_RELEASE; + else if (!strcmp (p, "acquire")) + mo = MEMMODEL_ACQUIRE; + else + error_at (c_parser_peek_token (parser)->location, + "expected %, %, % or " + "%"); + c_parser_consume_token (parser); + } + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + if (mo != MEMMODEL_LAST) + error_at (c_parser_peek_token (parser)->location, + "% list specified together with memory order " + "clause"); + c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); + } + else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + c_parser_error (parser, "expected %<(%> or end of line"); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_flush (loc, mo); +} + +/* Parse an OpenMP structured block sequence. KIND is the corresponding + separating directive. */ + +static tree +c_parser_omp_structured_block_sequence (c_parser *parser, + enum pragma_kind kind) +{ + tree stmt = push_stmt_list (); + c_parser_statement (parser, NULL); + do + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + break; + if (c_parser_next_token_is (parser, CPP_EOF)) + break; + + if (kind != PRAGMA_NONE + && c_parser_peek_token (parser)->pragma_kind == kind) + break; + c_parser_statement (parser, NULL); + } + while (1); + return pop_stmt_list (stmt); +} + +/* OpenMP 5.0: + + scan-loop-body: + { structured-block scan-directive structured-block } */ + +static void +c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed) +{ + tree substmt; + location_t loc; + tree clauses = NULL_TREE; + + loc = c_parser_peek_token (parser)->location; + if (!open_brace_parsed + && !c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + { + /* Avoid skipping until the end of the block. */ + parser->error = false; + return; + } + + substmt = c_parser_omp_structured_block_sequence (parser, PRAGMA_OMP_SCAN); + substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE); + SET_EXPR_LOCATION (substmt, loc); + add_stmt (substmt); + + loc = c_parser_peek_token (parser)->location; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SCAN) + { + enum omp_clause_code clause = OMP_CLAUSE_ERROR; + + c_parser_consume_pragma (parser); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "inclusive") == 0) + clause = OMP_CLAUSE_INCLUSIVE; + else if (strcmp (p, "exclusive") == 0) + clause = OMP_CLAUSE_EXCLUSIVE; + } + if (clause != OMP_CLAUSE_ERROR) + { + c_parser_consume_token (parser); + clauses = c_parser_omp_var_list_parens (parser, clause, NULL_TREE); + } + else + c_parser_error (parser, "expected % or " + "% clause"); + c_parser_skip_to_pragma_eol (parser); + } + else + error ("expected %<#pragma omp scan%>"); + + clauses = c_finish_omp_clauses (clauses, C_ORT_OMP); + substmt = c_parser_omp_structured_block_sequence (parser, PRAGMA_NONE); + substmt = build2 (OMP_SCAN, void_type_node, substmt, clauses); + SET_EXPR_LOCATION (substmt, loc); + add_stmt (substmt); + + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, + "expected %<}%>"); +} + +/* Parse the restricted form of loop statements allowed by OpenACC and OpenMP. + The real trick here is to determine the loop control variable early + so that we can push a new decl if necessary to make it private. + LOC is the location of the "acc" or "omp" in "#pragma acc" or "#pragma omp", + respectively. */ + +static tree +c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, + tree clauses, tree *cclauses, bool *if_p) +{ + tree decl, cond, incr, body, init, stmt, cl; + unsigned char save_in_statement; + tree declv, condv, incrv, initv, ret = NULL_TREE; + tree pre_body = NULL_TREE, this_pre_body; + tree ordered_cl = NULL_TREE; + bool fail = false, open_brace_parsed = false; + int i, collapse = 1, ordered = 0, count, nbraces = 0; + location_t for_loc; + bool tiling = false; + bool inscan = false; + vec *for_block = make_tree_vector (); + + for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) + if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) + collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); + else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_TILE) + { + tiling = true; + collapse = list_length (OMP_CLAUSE_TILE_LIST (cl)); + } + else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED + && OMP_CLAUSE_ORDERED_EXPR (cl)) + { + ordered_cl = cl; + ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (cl)); + } + else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_REDUCTION + && OMP_CLAUSE_REDUCTION_INSCAN (cl) + && (code == OMP_SIMD || code == OMP_FOR)) + inscan = true; + + if (ordered && ordered < collapse) + { + error_at (OMP_CLAUSE_LOCATION (ordered_cl), + "% clause parameter is less than %"); + OMP_CLAUSE_ORDERED_EXPR (ordered_cl) + = build_int_cst (NULL_TREE, collapse); + ordered = collapse; + } + if (ordered) + { + for (tree *pc = &clauses; *pc; ) + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR) + { + error_at (OMP_CLAUSE_LOCATION (*pc), + "% clause may not be specified together " + "with % clause with a parameter"); + *pc = OMP_CLAUSE_CHAIN (*pc); + } + else + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + gcc_assert (tiling || (collapse >= 1 && ordered >= 0)); + count = ordered ? ordered : collapse; + + declv = make_tree_vec (count); + initv = make_tree_vec (count); + condv = make_tree_vec (count); + incrv = make_tree_vec (count); + + if (!c_parser_next_token_is_keyword (parser, RID_FOR)) + { + c_parser_error (parser, "for statement expected"); + return NULL; + } + for_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + /* Forbid break/continue in the loop initializer, condition, and + increment expressions. */ + save_in_statement = in_statement; + in_statement = IN_OMP_BLOCK; + + for (i = 0; i < count; i++) + { + int bracecount = 0; + + matching_parens parens; + if (!parens.require_open (parser)) + goto pop_scopes; + + /* Parse the initialization declaration or expression. */ + if (c_parser_next_tokens_start_declaration (parser)) + { + if (i > 0) + vec_safe_push (for_block, c_begin_compound_stmt (true)); + this_pre_body = push_stmt_list (); + c_in_omp_for = true; + c_parser_declaration_or_fndef (parser, true, true, true, true, true); + c_in_omp_for = false; + if (this_pre_body) + { + this_pre_body = pop_stmt_list (this_pre_body); + if (pre_body) + { + tree t = pre_body; + pre_body = push_stmt_list (); + add_stmt (t); + add_stmt (this_pre_body); + pre_body = pop_stmt_list (pre_body); + } + else + pre_body = this_pre_body; + } + decl = check_for_loop_decls (for_loc, flag_isoc99); + if (decl == NULL) + goto error_init; + if (DECL_INITIAL (decl) == error_mark_node) + decl = error_mark_node; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + struct c_expr decl_exp; + struct c_expr init_exp; + location_t init_loc; + + decl_exp = c_parser_postfix_expression (parser); + decl = decl_exp.value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init_loc = c_parser_peek_token (parser)->location; + init_exp = c_parser_expr_no_commas (parser, NULL); + init_exp = default_function_array_read_conversion (init_loc, + init_exp); + c_in_omp_for = true; + init = build_modify_expr (init_loc, decl, decl_exp.original_type, + NOP_EXPR, init_loc, init_exp.value, + init_exp.original_type); + c_in_omp_for = false; + init = c_process_expr_stmt (init_loc, init); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + error_init: + c_parser_error (parser, + "expected iteration declaration or initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + fail = true; + goto parse_next; + } + + /* Parse the loop condition. */ + cond = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + { + location_t cond_loc = c_parser_peek_token (parser)->location; + c_in_omp_for = true; + struct c_expr cond_expr + = c_parser_binary_expression (parser, NULL, NULL_TREE); + c_in_omp_for = false; + + cond = cond_expr.value; + cond = c_objc_common_truthvalue_conversion (cond_loc, cond); + switch (cond_expr.original_code) + { + case GT_EXPR: + case GE_EXPR: + case LT_EXPR: + case LE_EXPR: + break; + case NE_EXPR: + if (code != OACC_LOOP) + break; + /* FALLTHRU. */ + default: + /* Can't be cond = error_mark_node, because we want to preserve + the location until c_finish_omp_for. */ + cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node); + break; + } + protected_set_expr_location (cond, cond_loc); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + + /* Parse the increment expression. */ + incr = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + location_t incr_loc = c_parser_peek_token (parser)->location; + + incr = c_process_expr_stmt (incr_loc, + c_parser_expression (parser).value); + } + parens.skip_until_found_close (parser); + + if (decl == NULL || decl == error_mark_node || init == error_mark_node) + fail = true; + else + { + TREE_VEC_ELT (declv, i) = decl; + TREE_VEC_ELT (initv, i) = init; + TREE_VEC_ELT (condv, i) = cond; + TREE_VEC_ELT (incrv, i) = incr; + } + + parse_next: + if (i == count - 1) + break; + + /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed + in between the collapsed for loops to be still considered perfectly + nested. Hopefully the final version clarifies this. + For now handle (multiple) {'s and empty statements. */ + do + { + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + { + c_parser_consume_token (parser); + break; + } + else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + c_parser_consume_token (parser); + bracecount++; + } + else if (bracecount + && c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "not enough perfectly nested loops"); + if (bracecount) + { + open_brace_parsed = true; + bracecount--; + } + fail = true; + count = 0; + break; + } + } + while (1); + + nbraces += bracecount; + } + + if (nbraces) + if_p = NULL; + + in_statement = IN_OMP_FOR; + body = push_stmt_list (); + + if (inscan) + c_parser_omp_scan_loop_body (parser, open_brace_parsed); + else if (open_brace_parsed) + { + location_t here = c_parser_peek_token (parser)->location; + stmt = c_begin_compound_stmt (true); + c_parser_compound_statement_nostart (parser); + add_stmt (c_end_compound_stmt (here, stmt, true)); + } + else + add_stmt (c_parser_c99_block_statement (parser, if_p)); + + body = pop_stmt_list (body); + in_statement = save_in_statement; + + while (nbraces) + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + c_parser_consume_token (parser); + nbraces--; + } + else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "collapsed loops not perfectly nested"); + while (nbraces) + { + location_t here = c_parser_peek_token (parser)->location; + stmt = c_begin_compound_stmt (true); + add_stmt (body); + c_parser_compound_statement_nostart (parser); + body = c_end_compound_stmt (here, stmt, true); + nbraces--; + } + goto pop_scopes; + } + } + + /* Only bother calling c_finish_omp_for if we haven't already generated + an error from the initialization parsing. */ + if (!fail) + { + c_in_omp_for = true; + stmt = c_finish_omp_for (loc, code, declv, NULL, initv, condv, + incrv, body, pre_body, true); + c_in_omp_for = false; + + /* Check for iterators appearing in lb, b or incr expressions. */ + if (stmt && !c_omp_check_loop_iv (stmt, declv, NULL)) + stmt = NULL_TREE; + + if (stmt) + { + add_stmt (stmt); + + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++) + { + tree init = TREE_VEC_ELT (OMP_FOR_INIT (stmt), i); + gcc_assert (TREE_CODE (init) == MODIFY_EXPR); + tree decl = TREE_OPERAND (init, 0); + tree cond = TREE_VEC_ELT (OMP_FOR_COND (stmt), i); + gcc_assert (COMPARISON_CLASS_P (cond)); + gcc_assert (TREE_OPERAND (cond, 0) == decl); + + tree op0 = TREE_OPERAND (init, 1); + if (!OMP_FOR_NON_RECTANGULAR (stmt) + || TREE_CODE (op0) != TREE_VEC) + TREE_OPERAND (init, 1) = c_fully_fold (op0, false, NULL); + else + { + TREE_VEC_ELT (op0, 1) + = c_fully_fold (TREE_VEC_ELT (op0, 1), false, NULL); + TREE_VEC_ELT (op0, 2) + = c_fully_fold (TREE_VEC_ELT (op0, 2), false, NULL); + } + + tree op1 = TREE_OPERAND (cond, 1); + if (!OMP_FOR_NON_RECTANGULAR (stmt) + || TREE_CODE (op1) != TREE_VEC) + TREE_OPERAND (cond, 1) = c_fully_fold (op1, false, NULL); + else + { + TREE_VEC_ELT (op1, 1) + = c_fully_fold (TREE_VEC_ELT (op1, 1), false, NULL); + TREE_VEC_ELT (op1, 2) + = c_fully_fold (TREE_VEC_ELT (op1, 2), false, NULL); + } + } + + if (cclauses != NULL + && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL) + { + tree *c; + for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) + if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE) + c = &OMP_CLAUSE_CHAIN (*c); + else + { + for (i = 0; i < count; i++) + if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c)) + break; + if (i == count) + c = &OMP_CLAUSE_CHAIN (*c); + else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE) + { + error_at (loc, + "iteration variable %qD should not be firstprivate", + OMP_CLAUSE_DECL (*c)); + *c = OMP_CLAUSE_CHAIN (*c); + } + else + { + /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */ + tree l = *c; + *c = OMP_CLAUSE_CHAIN (*c); + if (code == OMP_SIMD) + { + OMP_CLAUSE_CHAIN (l) + = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + cclauses[C_OMP_CLAUSE_SPLIT_FOR] = l; + } + else + { + OMP_CLAUSE_CHAIN (l) = clauses; + clauses = l; + } + } + } + } + OMP_FOR_CLAUSES (stmt) = clauses; + } + ret = stmt; + } +pop_scopes: + while (!for_block->is_empty ()) + { + /* FIXME diagnostics: LOC below should be the actual location of + this particular for block. We need to build a list of + locations to go along with FOR_BLOCK. */ + stmt = c_end_compound_stmt (loc, for_block->pop (), true); + add_stmt (stmt); + } + release_tree_vector (for_block); + return ret; +} + +/* Helper function for OpenMP parsing, split clauses and call + finish_omp_clauses on each of the set of clauses afterwards. */ + +static void +omp_split_clauses (location_t loc, enum tree_code code, + omp_clause_mask mask, tree clauses, tree *cclauses) +{ + int i; + c_omp_split_clauses (loc, code, mask, clauses, cclauses); + for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) + if (cclauses[i]) + cclauses[i] = c_finish_omp_clauses (cclauses[i], + i == C_OMP_CLAUSE_SPLIT_TARGET + ? C_ORT_OMP_TARGET : C_ORT_OMP); +} + +/* OpenMP 5.0: + #pragma omp loop loop-clause[optseq] new-line + for-loop + + LOC is the location of the #pragma token. +*/ + +#define OMP_LOOP_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_BIND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) + +static tree +c_parser_omp_loop (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree block, clauses, ret; + + strcat (p_name, " loop"); + mask |= OMP_LOOP_CLAUSE_MASK; + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_LOOP, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_LOOP]; + } + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_LOOP, clauses, cclauses, if_p); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 4.0: + #pragma omp simd simd-clause[optseq] new-line + for-loop + + LOC is the location of the #pragma token. +*/ + +#define OMP_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONTEMPORAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) + +static tree +c_parser_omp_simd (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree block, clauses, ret; + + strcat (p_name, " simd"); + mask |= OMP_SIMD_CLAUSE_MASK; + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + tree c = omp_find_clause (cclauses[C_OMP_CLAUSE_SPLIT_FOR], + OMP_CLAUSE_ORDERED); + if (c && OMP_CLAUSE_ORDERED_EXPR (c)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause with parameter may not be specified " + "on %qs construct", p_name); + OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE; + } + } + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, cclauses, if_p); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 2.5: + #pragma omp for for-clause[optseq] new-line + for-loop + + OpenMP 4.0: + #pragma omp for simd for-simd-clause[optseq] new-line + for-loop + + LOC is the location of the #pragma token. +*/ + +#define OMP_FOR_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) + +static tree +c_parser_omp_for (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree block, clauses, ret; + + strcat (p_name, " for"); + mask |= OMP_FOR_CLAUSE_MASK; + /* parallel for{, simd} disallows nowait clause, but for + target {teams distribute ,}parallel for{, simd} it should be accepted. */ + if (cclauses && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) == 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + /* Composite distribute parallel for{, simd} disallows ordered clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "simd") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL_TREE) + return ret; + ret = make_node (OMP_FOR); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = block; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + /* Composite distribute parallel for disallows linear clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR); + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + } + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_FOR, clauses, cclauses, if_p); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + +static tree c_parser_omp_taskloop (location_t, c_parser *, char *, + omp_clause_mask, tree *, bool *); + +/* OpenMP 2.5: + # pragma omp master new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +static tree +c_parser_omp_master (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree block, clauses, ret; + + strcat (p_name, " master"); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "taskloop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL_TREE) + return ret; + ret = c_finish_omp_master (loc, block); + OMP_MASTER_COMBINED (ret) = 1; + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + if (cclauses) + { + clauses = c_parser_omp_all_clauses (parser, mask, p_name, false); + omp_split_clauses (loc, OMP_MASTER, mask, clauses, cclauses); + } + else + c_parser_skip_to_pragma_eol (parser); + + return c_finish_omp_master (loc, c_parser_omp_structured_block (parser, + if_p)); +} + +/* OpenMP 5.1: + # pragma omp masked masked-clauses new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OMP_MASKED_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) + +static tree +c_parser_omp_masked (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree block, clauses, ret; + + strcat (p_name, " masked"); + mask |= OMP_MASKED_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "taskloop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL_TREE) + return ret; + ret = c_finish_omp_masked (loc, block, + cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); + OMP_MASKED_COMBINED (ret) = 1; + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_MASKED, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; + } + + return c_finish_omp_masked (loc, c_parser_omp_structured_block (parser, + if_p), + clauses); +} + +/* OpenMP 2.5: + # pragma omp ordered new-line + structured-block + + OpenMP 4.5: + # pragma omp ordered ordered-clauses new-line + structured-block + + # pragma omp ordered depend-clauses new-line */ + +#define OMP_ORDERED_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD)) + +#define OMP_ORDERED_DEPEND_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + +static bool +c_parser_omp_ordered (c_parser *parser, enum pragma_context context, + bool *if_p) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + + if (context != pragma_stmt && context != pragma_compound) + { + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_to_pragma_eol (parser, false); + return false; + } + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (!strcmp ("depend", p)) + { + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return false; + } + if (context == pragma_stmt) + { + error_at (loc, + "%<#pragma omp ordered%> with % clause may " + "only be used in compound statements"); + c_parser_skip_to_pragma_eol (parser, false); + return true; + } + + tree clauses + = c_parser_omp_all_clauses (parser, + OMP_ORDERED_DEPEND_CLAUSE_MASK, + "#pragma omp ordered"); + c_finish_omp_ordered (loc, clauses, NULL_TREE); + return false; + } + } + + tree clauses = c_parser_omp_all_clauses (parser, OMP_ORDERED_CLAUSE_MASK, + "#pragma omp ordered"); + + if (!flag_openmp /* flag_openmp_simd */ + && omp_find_clause (clauses, OMP_CLAUSE_SIMD) == NULL_TREE) + return false; + + c_finish_omp_ordered (loc, clauses, + c_parser_omp_structured_block (parser, if_p)); + return true; +} + +/* OpenMP 2.5: + + section-scope: + { section-sequence } + + section-sequence: + section-directive[opt] structured-block + section-sequence section-directive structured-block + + OpenMP 5.1 allows structured-block-sequence instead of structured-block. + + SECTIONS_LOC is the location of the #pragma omp sections. */ + +static tree +c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) +{ + tree stmt, substmt; + bool error_suppress = false; + location_t loc; + + loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + { + /* Avoid skipping until the end of the block. */ + parser->error = false; + return NULL_TREE; + } + + stmt = push_stmt_list (); + + if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION) + { + substmt = c_parser_omp_structured_block_sequence (parser, + PRAGMA_OMP_SECTION); + substmt = build1 (OMP_SECTION, void_type_node, substmt); + SET_EXPR_LOCATION (substmt, loc); + add_stmt (substmt); + } + + while (1) + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + break; + if (c_parser_next_token_is (parser, CPP_EOF)) + break; + + loc = c_parser_peek_token (parser)->location; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) + { + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + error_suppress = false; + } + else if (!error_suppress) + { + error_at (loc, "expected %<#pragma omp section%> or %<}%>"); + error_suppress = true; + } + + substmt = c_parser_omp_structured_block_sequence (parser, + PRAGMA_OMP_SECTION); + substmt = build1 (OMP_SECTION, void_type_node, substmt); + SET_EXPR_LOCATION (substmt, loc); + add_stmt (substmt); + } + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, + "expected %<#pragma omp section%> or %<}%>"); + + substmt = pop_stmt_list (stmt); + + stmt = make_node (OMP_SECTIONS); + SET_EXPR_LOCATION (stmt, sections_loc); + TREE_TYPE (stmt) = void_type_node; + OMP_SECTIONS_BODY (stmt) = substmt; + + return add_stmt (stmt); +} + +/* OpenMP 2.5: + # pragma omp sections sections-clause[optseq] newline + sections-scope + + LOC is the location of the #pragma token. +*/ + +#define OMP_SECTIONS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_sections (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree block, clauses, ret; + + strcat (p_name, " sections"); + mask |= OMP_SECTIONS_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; + } + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_sections_scope (loc, parser); + if (ret) + OMP_SECTIONS_CLAUSES (ret) = clauses; + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 2.5: + # pragma omp parallel parallel-clause[optseq] new-line + structured-block + # pragma omp parallel for parallel-for-clause[optseq] new-line + structured-block + # pragma omp parallel sections parallel-sections-clause[optseq] new-line + structured-block + + OpenMP 4.0: + # pragma omp parallel for simd parallel-for-simd-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OMP_PARALLEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) + +static tree +c_parser_omp_parallel (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree stmt, clauses, block; + + strcat (p_name, " parallel"); + mask |= OMP_PARALLEL_CLAUSE_MASK; + /* #pragma omp target parallel{, for, for simd} disallow copyin clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) != 0 + && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN); + + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_for (loc, parser, p_name, mask, cclauses, if_p); + block = c_begin_omp_parallel (); + tree ret = c_parser_omp_for (loc, parser, p_name, mask, cclauses, if_p); + stmt + = c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL_TREE) + return ret; + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + /* When combined with distribute, parallel has to be followed by for. + #pragma omp target parallel is allowed though. */ + else if (cclauses + && (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) + { + error_at (loc, "expected % after %qs", p_name); + c_parser_skip_to_pragma_eol (parser); + return NULL_TREE; + } + else if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (cclauses == NULL && strcmp (p, "masked") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_masked (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_omp_parallel (); + tree ret = c_parser_omp_masked (loc, parser, p_name, mask, cclauses, + if_p); + stmt = c_finish_omp_parallel (loc, + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL) + return ret; + /* masked does have just filter clause, but during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel masked + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel masked taskloop simd lastprivate (x) */ + if (OMP_MASKED_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses == NULL && strcmp (p, "master") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_master (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_omp_parallel (); + tree ret = c_parser_omp_master (loc, parser, p_name, mask, cclauses, + if_p); + stmt = c_finish_omp_parallel (loc, + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL) + return ret; + /* master doesn't have any clauses and during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel master don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel master + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel master taskloop simd lastprivate (x) */ + if (OMP_MASTER_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (strcmp (p, "loop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_loop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_omp_parallel (); + tree ret = c_parser_omp_loop (loc, parser, p_name, mask, cclauses, + if_p); + stmt + = c_finish_omp_parallel (loc, + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL_TREE) + return ret; + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + else if (cclauses == NULL && strcmp (p, "sections") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + block = c_begin_omp_parallel (); + c_parser_omp_sections (loc, parser, p_name, mask, cclauses); + stmt = c_finish_omp_parallel (loc, + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + } + else if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_PARALLEL, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + } + + block = c_begin_omp_parallel (); + c_parser_statement (parser, if_p); + stmt = c_finish_omp_parallel (loc, clauses, block); + + return stmt; +} + +/* OpenMP 2.5: + # pragma omp single single-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma. +*/ + +#define OMP_SINGLE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) +{ + tree stmt = make_node (OMP_SINGLE); + SET_EXPR_LOCATION (stmt, loc); + TREE_TYPE (stmt) = void_type_node; + + OMP_SINGLE_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, + "#pragma omp single"); + OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); + + return add_stmt (stmt); +} + +/* OpenMP 5.1: + # pragma omp scope scope-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma. +*/ + +#define OMP_SCOPE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_scope (location_t loc, c_parser *parser, bool *if_p) +{ + tree stmt = make_node (OMP_SCOPE); + SET_EXPR_LOCATION (stmt, loc); + TREE_TYPE (stmt) = void_type_node; + + OMP_SCOPE_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, + "#pragma omp scope"); + OMP_SCOPE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); + + return add_stmt (stmt); +} + +/* OpenMP 3.0: + # pragma omp task task-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_TASK_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_AFFINITY)) + +static tree +c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p) +{ + tree clauses, block; + + clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, + "#pragma omp task"); + + block = c_begin_omp_task (); + c_parser_statement (parser, if_p); + return c_finish_omp_task (loc, clauses, block); +} + +/* OpenMP 3.0: + # pragma omp taskwait new-line + + OpenMP 5.0: + # pragma omp taskwait taskwait-clause[optseq] new-line +*/ + +#define OMP_TASKWAIT_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + +static void +c_parser_omp_taskwait (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + + tree clauses + = c_parser_omp_all_clauses (parser, OMP_TASKWAIT_CLAUSE_MASK, + "#pragma omp taskwait"); + + if (clauses) + { + tree stmt = make_node (OMP_TASK); + TREE_TYPE (stmt) = void_node; + OMP_TASK_CLAUSES (stmt) = clauses; + OMP_TASK_BODY (stmt) = NULL_TREE; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + } + else + c_finish_omp_taskwait (loc); +} + +/* OpenMP 3.1: + # pragma omp taskyield new-line +*/ + +static void +c_parser_omp_taskyield (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_taskyield (loc); +} + +/* OpenMP 4.0: + # pragma omp taskgroup new-line + + OpenMP 5.0: + # pragma omp taskgroup taskgroup-clause[optseq] new-line +*/ + +#define OMP_TASKGROUP_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASK_REDUCTION)) + +static tree +c_parser_omp_taskgroup (location_t loc, c_parser *parser, bool *if_p) +{ + tree clauses = c_parser_omp_all_clauses (parser, OMP_TASKGROUP_CLAUSE_MASK, + "#pragma omp taskgroup"); + + tree body = c_parser_omp_structured_block (parser, if_p); + return c_finish_omp_taskgroup (loc, body, clauses); +} + +/* OpenMP 4.0: + # pragma omp cancel cancel-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_CANCEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static void +c_parser_omp_cancel (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + + c_parser_consume_pragma (parser); + tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, + "#pragma omp cancel"); + + c_finish_omp_cancel (loc, clauses); +} + +/* OpenMP 4.0: + # pragma omp cancellation point cancelpt-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_CANCELLATION_POINT_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) + +static bool +c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree clauses; + bool point_seen = false; + + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "point") == 0) + { + c_parser_consume_token (parser); + point_seen = true; + } + } + if (!point_seen) + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return false; + } + + if (context != pragma_compound) + { + if (context == pragma_stmt) + error_at (loc, + "%<#pragma %s%> may only be used in compound statements", + "omp cancellation point"); + else + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_to_pragma_eol (parser, false); + return true; + } + + clauses + = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK, + "#pragma omp cancellation point"); + + c_finish_omp_cancellation_point (loc, clauses); + return true; +} + +/* OpenMP 4.0: + #pragma omp distribute distribute-clause[optseq] new-line + for-loop */ + +#define OMP_DISTRIBUTE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) + +static tree +c_parser_omp_distribute (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree clauses, block, ret; + + strcat (p_name, " distribute"); + mask |= OMP_DISTRIBUTE_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + bool simd = false; + bool parallel = false; + + if (strcmp (p, "simd") == 0) + simd = true; + else + parallel = strcmp (p, "parallel") == 0; + if (parallel || simd) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + { + if (simd) + return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, + if_p); + else + return c_parser_omp_parallel (loc, parser, p_name, mask, + cclauses, if_p); + } + block = c_begin_compound_stmt (true); + if (simd) + ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, + if_p); + else + ret = c_parser_omp_parallel (loc, parser, p_name, mask, cclauses, + if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + ret = make_node (OMP_DISTRIBUTE); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = block; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + } + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_DISTRIBUTE, clauses, NULL, + if_p); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 4.0: + # pragma omp teams teams-clause[optseq] new-line + structured-block */ + +#define OMP_TEAMS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) + +static tree +c_parser_omp_teams (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree clauses, block, ret; + + strcat (p_name, " teams"); + mask |= OMP_TEAMS_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "distribute") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_distribute (loc, parser, p_name, mask, + cclauses, if_p); + block = c_begin_omp_parallel (); + ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses, + if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + ret = make_node (OMP_TEAMS); + TREE_TYPE (ret) = void_type_node; + OMP_TEAMS_CLAUSES (ret) = clauses; + OMP_TEAMS_BODY (ret) = block; + OMP_TEAMS_COMBINED (ret) = 1; + SET_EXPR_LOCATION (ret, loc); + return add_stmt (ret); + } + else if (strcmp (p, "loop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_loop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_omp_parallel (); + ret = c_parser_omp_loop (loc, parser, p_name, mask, cclauses, if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + ret = make_node (OMP_TEAMS); + TREE_TYPE (ret) = void_type_node; + OMP_TEAMS_CLAUSES (ret) = clauses; + OMP_TEAMS_BODY (ret) = block; + OMP_TEAMS_COMBINED (ret) = 1; + SET_EXPR_LOCATION (ret, loc); + return add_stmt (ret); + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + } + + tree stmt = make_node (OMP_TEAMS); + TREE_TYPE (stmt) = void_type_node; + OMP_TEAMS_CLAUSES (stmt) = clauses; + block = c_begin_omp_parallel (); + add_stmt (c_parser_omp_structured_block (parser, if_p)); + OMP_TEAMS_BODY (stmt) = c_end_compound_stmt (loc, block, true); + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target data target-data-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR)) + +static tree +c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p) +{ + tree clauses + = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, + "#pragma omp target data"); + c_omp_adjust_map_clauses (clauses, false); + int map_seen = 0; + for (tree *pc = &clauses; *pc;) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_TO: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_ALLOC: + map_seen = 3; + break; + case GOMP_MAP_FIRSTPRIVATE_POINTER: + case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_ATTACH_DETACH: + break; + default: + map_seen |= 1; + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target data%> with map-type other " + "than %, %, % or % " + "on % clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_PTR + || OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_ADDR) + map_seen = 3; + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + if (map_seen != 3) + { + if (map_seen == 0) + error_at (loc, + "%<#pragma omp target data%> must contain at least " + "one %, % or % " + "clause"); + return NULL_TREE; + } + + tree stmt = make_node (OMP_TARGET_DATA); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_DATA_CLAUSES (stmt) = clauses; + keep_next_level (); + tree block = c_begin_compound_stmt (true); + add_stmt (c_parser_omp_structured_block (parser, if_p)); + OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true); + + SET_EXPR_LOCATION (stmt, loc); + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target update target-update-clause[optseq] new-line */ + +#define OMP_TARGET_UPDATE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static bool +c_parser_omp_target_update (location_t loc, c_parser *parser, + enum pragma_context context) +{ + if (context == pragma_stmt) + { + error_at (loc, "%<#pragma %s%> may only be used in compound statements", + "omp target update"); + c_parser_skip_to_pragma_eol (parser, false); + return true; + } + + tree clauses + = c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK, + "#pragma omp target update"); + if (omp_find_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE + && omp_find_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE) + { + error_at (loc, + "%<#pragma omp target update%> must contain at least one " + "% or % clauses"); + return false; + } + + tree stmt = make_node (OMP_TARGET_UPDATE); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + return false; +} + +/* OpenMP 4.5: + # pragma omp target enter data target-data-clause[optseq] new-line */ + +#define OMP_TARGET_ENTER_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static bool +c_parser_omp_target_enter_data (location_t loc, c_parser *parser, + enum pragma_context context) +{ + bool data_seen = false; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "data") == 0) + { + c_parser_consume_token (parser); + data_seen = true; + } + } + if (!data_seen) + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return false; + } + + if (context == pragma_stmt) + { + error_at (loc, "%<#pragma %s%> may only be used in compound statements", + "omp target enter data"); + c_parser_skip_to_pragma_eol (parser, false); + return true; + } + + tree clauses + = c_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK, + "#pragma omp target enter data"); + c_omp_adjust_map_clauses (clauses, false); + int map_seen = 0; + for (tree *pc = &clauses; *pc;) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_TO: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALLOC: + map_seen = 3; + break; + case GOMP_MAP_FIRSTPRIVATE_POINTER: + case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_ATTACH_DETACH: + break; + default: + map_seen |= 1; + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target enter data%> with map-type other " + "than % or % on % clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + if (map_seen != 3) + { + if (map_seen == 0) + error_at (loc, + "%<#pragma omp target enter data%> must contain at least " + "one % clause"); + return true; + } + + tree stmt = make_node (OMP_TARGET_ENTER_DATA); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + return true; +} + +/* OpenMP 4.5: + # pragma omp target exit data target-data-clause[optseq] new-line */ + +#define OMP_TARGET_EXIT_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static bool +c_parser_omp_target_exit_data (location_t loc, c_parser *parser, + enum pragma_context context) +{ + bool data_seen = false; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "data") == 0) + { + c_parser_consume_token (parser); + data_seen = true; + } + } + if (!data_seen) + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return false; + } + + if (context == pragma_stmt) + { + error_at (loc, "%<#pragma %s%> may only be used in compound statements", + "omp target exit data"); + c_parser_skip_to_pragma_eol (parser, false); + return true; + } + + tree clauses + = c_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK, + "#pragma omp target exit data"); + c_omp_adjust_map_clauses (clauses, false); + int map_seen = 0; + for (tree *pc = &clauses; *pc;) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_FROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + map_seen = 3; + break; + case GOMP_MAP_FIRSTPRIVATE_POINTER: + case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_ATTACH_DETACH: + break; + default: + map_seen |= 1; + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target exit data%> with map-type other " + "than %, % or % on %" + " clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } + + if (map_seen != 3) + { + if (map_seen == 0) + error_at (loc, + "%<#pragma omp target exit data%> must contain at least one " + "% clause"); + return true; + } + + tree stmt = make_node (OMP_TARGET_EXIT_DATA); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + return true; +} + +/* OpenMP 4.0: + # pragma omp target target-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)) + +static bool +c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + tree *pc = NULL, stmt, block; + + if (context != pragma_stmt && context != pragma_compound) + { + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_to_pragma_eol (parser); + return false; + } + + if (flag_openmp) + omp_requires_mask + = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + enum tree_code ccode = ERROR_MARK; + + if (strcmp (p, "teams") == 0) + ccode = OMP_TEAMS; + else if (strcmp (p, "parallel") == 0) + ccode = OMP_PARALLEL; + else if (strcmp (p, "simd") == 0) + ccode = OMP_SIMD; + if (ccode != ERROR_MARK) + { + tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; + char p_name[sizeof ("#pragma omp target teams distribute " + "parallel for simd")]; + + c_parser_consume_token (parser); + strcpy (p_name, "#pragma omp target"); + if (!flag_openmp) /* flag_openmp_simd */ + { + tree stmt; + switch (ccode) + { + case OMP_TEAMS: + stmt = c_parser_omp_teams (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, + cclauses, if_p); + break; + case OMP_PARALLEL: + stmt = c_parser_omp_parallel (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, + cclauses, if_p); + break; + case OMP_SIMD: + stmt = c_parser_omp_simd (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, + cclauses, if_p); + break; + default: + gcc_unreachable (); + } + return stmt != NULL_TREE; + } + keep_next_level (); + tree block = c_begin_compound_stmt (true), ret; + switch (ccode) + { + case OMP_TEAMS: + ret = c_parser_omp_teams (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses, + if_p); + break; + case OMP_PARALLEL: + ret = c_parser_omp_parallel (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses, + if_p); + break; + case OMP_SIMD: + ret = c_parser_omp_simd (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses, + if_p); + break; + default: + gcc_unreachable (); + } + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL_TREE) + return false; + if (ccode == OMP_TEAMS) + /* For combined target teams, ensure the num_teams and + thread_limit clause expressions are evaluated on the host, + before entering the target construct. */ + for (tree c = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREAD_LIMIT) + for (int i = 0; + i <= (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS); ++i) + if (OMP_CLAUSE_OPERAND (c, i) + && TREE_CODE (OMP_CLAUSE_OPERAND (c, i)) != INTEGER_CST) + { + tree expr = OMP_CLAUSE_OPERAND (c, i); + tree tmp = create_tmp_var_raw (TREE_TYPE (expr)); + expr = build4 (TARGET_EXPR, TREE_TYPE (expr), tmp, + expr, NULL_TREE, NULL_TREE); + add_stmt (expr); + OMP_CLAUSE_OPERAND (c, i) = expr; + tree tc = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (tc) = tmp; + OMP_CLAUSE_CHAIN (tc) + = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = tc; + } + tree stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); + OMP_TARGET_BODY (stmt) = block; + OMP_TARGET_COMBINED (stmt) = 1; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + pc = &OMP_TARGET_CLAUSES (stmt); + goto check_clauses; + } + else if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return false; + } + else if (strcmp (p, "data") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_target_data (loc, parser, if_p); + return true; + } + else if (strcmp (p, "enter") == 0) + { + c_parser_consume_token (parser); + return c_parser_omp_target_enter_data (loc, parser, context); + } + else if (strcmp (p, "exit") == 0) + { + c_parser_consume_token (parser); + return c_parser_omp_target_exit_data (loc, parser, context); + } + else if (strcmp (p, "update") == 0) + { + c_parser_consume_token (parser); + return c_parser_omp_target_update (loc, parser, context); + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return false; + } + + stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + + OMP_TARGET_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, + "#pragma omp target", false); + for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) + { + tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + OMP_CLAUSE_DECL (nc) = OMP_CLAUSE_DECL (c); + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_ALWAYS_TOFROM); + OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = nc; + } + OMP_TARGET_CLAUSES (stmt) + = c_finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET); + c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); + + pc = &OMP_TARGET_CLAUSES (stmt); + keep_next_level (); + block = c_begin_compound_stmt (true); + add_stmt (c_parser_omp_structured_block (parser, if_p)); + OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true); + + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + +check_clauses: + while (*pc) + { + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (*pc)) + { + case GOMP_MAP_TO: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_ALLOC: + case GOMP_MAP_FIRSTPRIVATE_POINTER: + case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_ATTACH_DETACH: + break; + default: + error_at (OMP_CLAUSE_LOCATION (*pc), + "%<#pragma omp target%> with map-type other " + "than %, %, % or % " + "on % clause"); + *pc = OMP_CLAUSE_CHAIN (*pc); + continue; + } + pc = &OMP_CLAUSE_CHAIN (*pc); + } + cfun->has_omp_target = true; + return true; +} + +/* OpenMP 4.0: + # pragma omp declare simd declare-simd-clauses[optseq] new-line + + OpenMP 5.0: + # pragma omp declare variant (identifier) match(context-selector) new-line + */ + +#define OMP_DECLARE_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) + +static void +c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) +{ + c_token *token = c_parser_peek_token (parser); + gcc_assert (token->type == CPP_NAME); + tree kind = token->value; + gcc_assert (strcmp (IDENTIFIER_POINTER (kind), "simd") == 0 + || strcmp (IDENTIFIER_POINTER (kind), "variant") == 0); + + auto_vec clauses; + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF) + { + c_parser_skip_to_pragma_eol (parser); + return; + } + clauses.safe_push (*token); + c_parser_consume_token (parser); + } + clauses.safe_push (*c_parser_peek_token (parser)); + c_parser_skip_to_pragma_eol (parser); + + while (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_DECLARE + || c_parser_peek_2nd_token (parser)->type != CPP_NAME + || c_parser_peek_2nd_token (parser)->value != kind) + { + error ("%<#pragma omp declare %s%> must be followed by " + "function declaration or definition or another " + "%<#pragma omp declare %s%>", + IDENTIFIER_POINTER (kind), IDENTIFIER_POINTER (kind)); + return; + } + c_parser_consume_pragma (parser); + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF) + { + c_parser_skip_to_pragma_eol (parser); + return; + } + clauses.safe_push (*token); + c_parser_consume_token (parser); + } + clauses.safe_push (*c_parser_peek_token (parser)); + c_parser_skip_to_pragma_eol (parser); + } + + /* Make sure nothing tries to read past the end of the tokens. */ + c_token eof_token; + memset (&eof_token, 0, sizeof (eof_token)); + eof_token.type = CPP_EOF; + clauses.safe_push (eof_token); + clauses.safe_push (eof_token); + + switch (context) + { + case pragma_external: + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION) + { + int ext = disable_extension_diagnostics (); + do + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, &clauses); + restore_extension_diagnostics (ext); + } + else + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, &clauses); + break; + case pragma_struct: + case pragma_param: + case pragma_stmt: + error ("%<#pragma omp declare %s%> must be followed by " + "function declaration or definition", + IDENTIFIER_POINTER (kind)); + break; + case pragma_compound: + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION) + { + int ext = disable_extension_diagnostics (); + do + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION); + if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, NULL, &clauses); + restore_extension_diagnostics (ext); + break; + } + restore_extension_diagnostics (ext); + } + else if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + NULL, &clauses); + break; + } + error ("%<#pragma omp declare %s%> must be followed by " + "function declaration or definition", + IDENTIFIER_POINTER (kind)); + break; + default: + gcc_unreachable (); + } +} + +static const char *const omp_construct_selectors[] = { + "simd", "target", "teams", "parallel", "for", NULL }; +static const char *const omp_device_selectors[] = { + "kind", "isa", "arch", NULL }; +static const char *const omp_implementation_selectors[] = { + "vendor", "extension", "atomic_default_mem_order", "unified_address", + "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL }; +static const char *const omp_user_selectors[] = { + "condition", NULL }; + +/* OpenMP 5.0: + + trait-selector: + trait-selector-name[([trait-score:]trait-property[,trait-property[,...]])] + + trait-score: + score(score-expression) */ + +static tree +c_parser_omp_context_selector (c_parser *parser, tree set, tree parms) +{ + tree ret = NULL_TREE; + do + { + tree selector; + if (c_parser_next_token_is (parser, CPP_KEYWORD) + || c_parser_next_token_is (parser, CPP_NAME)) + selector = c_parser_peek_token (parser)->value; + else + { + c_parser_error (parser, "expected trait selector name"); + return error_mark_node; + } + + tree properties = NULL_TREE; + const char *const *selectors = NULL; + bool allow_score = true; + bool allow_user = false; + int property_limit = 0; + enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST, + CTX_PROPERTY_ID, CTX_PROPERTY_EXPR, + CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE; + switch (IDENTIFIER_POINTER (set)[0]) + { + case 'c': /* construct */ + selectors = omp_construct_selectors; + allow_score = false; + property_limit = 1; + property_kind = CTX_PROPERTY_SIMD; + break; + case 'd': /* device */ + selectors = omp_device_selectors; + allow_score = false; + allow_user = true; + property_limit = 3; + property_kind = CTX_PROPERTY_NAME_LIST; + break; + case 'i': /* implementation */ + selectors = omp_implementation_selectors; + allow_user = true; + property_limit = 3; + property_kind = CTX_PROPERTY_NAME_LIST; + break; + case 'u': /* user */ + selectors = omp_user_selectors; + property_limit = 1; + property_kind = CTX_PROPERTY_EXPR; + break; + default: + gcc_unreachable (); + } + for (int i = 0; ; i++) + { + if (selectors[i] == NULL) + { + if (allow_user) + { + property_kind = CTX_PROPERTY_USER; + break; + } + else + { + error_at (c_parser_peek_token (parser)->location, + "selector %qs not allowed for context selector " + "set %qs", IDENTIFIER_POINTER (selector), + IDENTIFIER_POINTER (set)); + c_parser_consume_token (parser); + return error_mark_node; + } + } + if (i == property_limit) + property_kind = CTX_PROPERTY_NONE; + if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0) + break; + } + if (property_kind == CTX_PROPERTY_NAME_LIST + && IDENTIFIER_POINTER (set)[0] == 'i' + && strcmp (IDENTIFIER_POINTER (selector), + "atomic_default_mem_order") == 0) + property_kind = CTX_PROPERTY_ID; + + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + if (property_kind == CTX_PROPERTY_NONE) + { + error_at (c_parser_peek_token (parser)->location, + "selector %qs does not accept any properties", + IDENTIFIER_POINTER (selector)); + return error_mark_node; + } + + matching_parens parens; + parens.require_open (parser); + + c_token *token = c_parser_peek_token (parser); + if (allow_score + && c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER (token->value), "score") == 0 + && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) + { + c_parser_consume_token (parser); + + matching_parens parens2; + parens2.require_open (parser); + tree score = c_parser_expr_no_commas (parser, NULL).value; + parens2.skip_until_found_close (parser); + c_parser_require (parser, CPP_COLON, "expected %<:%>"); + if (score != error_mark_node) + { + mark_exp_read (score); + score = c_fully_fold (score, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (score)) + || TREE_CODE (score) != INTEGER_CST) + error_at (token->location, "score argument must be " + "constant integer expression"); + else if (tree_int_cst_sgn (score) < 0) + error_at (token->location, "score argument must be " + "non-negative"); + else + properties = tree_cons (get_identifier (" score"), + score, properties); + } + token = c_parser_peek_token (parser); + } + + switch (property_kind) + { + tree t; + case CTX_PROPERTY_USER: + do + { + t = c_parser_expr_no_commas (parser, NULL).value; + if (TREE_CODE (t) == STRING_CST) + properties = tree_cons (NULL_TREE, t, properties); + else if (t != error_mark_node) + { + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + || !tree_fits_shwi_p (t)) + error_at (token->location, "property must be " + "constant integer expression or string " + "literal"); + else + properties = tree_cons (NULL_TREE, t, properties); + } + else + return error_mark_node; + + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + while (1); + break; + case CTX_PROPERTY_ID: + if (c_parser_next_token_is (parser, CPP_KEYWORD) + || c_parser_next_token_is (parser, CPP_NAME)) + { + tree prop = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + properties = tree_cons (prop, NULL_TREE, properties); + } + else + { + c_parser_error (parser, "expected identifier"); + return error_mark_node; + } + break; + case CTX_PROPERTY_NAME_LIST: + do + { + tree prop = NULL_TREE, value = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_KEYWORD) + || c_parser_next_token_is (parser, CPP_NAME)) + { + prop = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is (parser, CPP_STRING)) + value = c_parser_string_literal (parser, false, + false).value; + else + { + c_parser_error (parser, "expected identifier or " + "string literal"); + return error_mark_node; + } + + properties = tree_cons (prop, value, properties); + + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + while (1); + break; + case CTX_PROPERTY_EXPR: + t = c_parser_expr_no_commas (parser, NULL).value; + if (t != error_mark_node) + { + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + || !tree_fits_shwi_p (t)) + error_at (token->location, "property must be " + "constant integer expression"); + else + properties = tree_cons (NULL_TREE, t, properties); + } + else + return error_mark_node; + break; + case CTX_PROPERTY_SIMD: + if (parms == NULL_TREE) + { + error_at (token->location, "properties for % " + "selector may not be specified in " + "%"); + return error_mark_node; + } + tree c; + c = c_parser_omp_all_clauses (parser, + OMP_DECLARE_SIMD_CLAUSE_MASK, + "simd", true, 2); + c = c_omp_declare_simd_clauses_to_numbers (parms + == error_mark_node + ? NULL_TREE : parms, + c); + properties = c; + break; + default: + gcc_unreachable (); + } + + parens.skip_until_found_close (parser); + properties = nreverse (properties); + } + else if (property_kind == CTX_PROPERTY_NAME_LIST + || property_kind == CTX_PROPERTY_ID + || property_kind == CTX_PROPERTY_EXPR) + { + c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"); + return error_mark_node; + } + + ret = tree_cons (selector, properties, ret); + + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + while (1); + + return nreverse (ret); +} + +/* OpenMP 5.0: + + trait-set-selector[,trait-set-selector[,...]] + + trait-set-selector: + trait-set-selector-name = { trait-selector[, trait-selector[, ...]] } + + trait-set-selector-name: + constructor + device + implementation + user */ + +static tree +c_parser_omp_context_selector_specification (c_parser *parser, tree parms) +{ + tree ret = NULL_TREE; + do + { + const char *setp = ""; + if (c_parser_next_token_is (parser, CPP_NAME)) + setp = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + switch (setp[0]) + { + case 'c': + if (strcmp (setp, "construct") == 0) + setp = NULL; + break; + case 'd': + if (strcmp (setp, "device") == 0) + setp = NULL; + break; + case 'i': + if (strcmp (setp, "implementation") == 0) + setp = NULL; + break; + case 'u': + if (strcmp (setp, "user") == 0) + setp = NULL; + break; + default: + break; + } + if (setp) + { + c_parser_error (parser, "expected %, %, " + "% or %"); + return error_mark_node; + } + + tree set = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + return error_mark_node; + + matching_braces braces; + if (!braces.require_open (parser)) + return error_mark_node; + + tree selectors = c_parser_omp_context_selector (parser, set, parms); + if (selectors == error_mark_node) + ret = error_mark_node; + else if (ret != error_mark_node) + ret = tree_cons (set, selectors, ret); + + braces.skip_until_found_close (parser); + + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + while (1); + + if (ret == error_mark_node) + return ret; + return nreverse (ret); +} + +/* Finalize #pragma omp declare variant after FNDECL has been parsed, and put + that into "omp declare variant base" attribute. */ + +static void +c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) +{ + matching_parens parens; + if (!parens.require_open (parser)) + { + fail: + c_parser_skip_to_pragma_eol (parser, false); + return; + } + + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + c_parser_error (parser, "expected identifier"); + goto fail; + } + + c_token *token = c_parser_peek_token (parser); + tree variant = lookup_name (token->value); + + if (variant == NULL_TREE) + { + undeclared_variable (token->location, token->value); + variant = error_mark_node; + } + + c_parser_consume_token (parser); + + parens.require_close (parser); + + const char *clause = ""; + location_t match_loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_NAME)) + clause = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (clause, "match")) + { + c_parser_error (parser, "expected %"); + goto fail; + } + + c_parser_consume_token (parser); + + if (!parens.require_open (parser)) + goto fail; + + if (parms == NULL_TREE) + parms = error_mark_node; + + tree ctx = c_parser_omp_context_selector_specification (parser, parms); + if (ctx == error_mark_node) + goto fail; + ctx = omp_check_context_selector (match_loc, ctx); + if (ctx != error_mark_node && variant != error_mark_node) + { + if (TREE_CODE (variant) != FUNCTION_DECL) + { + error_at (token->location, "variant %qD is not a function", variant); + variant = error_mark_node; + } + else if (omp_get_context_selector (ctx, "construct", "simd") == NULL_TREE + && !comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant))) + { + error_at (token->location, "variant %qD and base %qD have " + "incompatible types", variant, fndecl); + variant = error_mark_node; + } + else if (fndecl_built_in_p (variant) + && (strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), + "__builtin_", strlen ("__builtin_")) == 0 + || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), + "__sync_", strlen ("__sync_")) == 0 + || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), + "__atomic_", strlen ("__atomic_")) == 0)) + { + error_at (token->location, "variant %qD is a built-in", variant); + variant = error_mark_node; + } + if (variant != error_mark_node) + { + C_DECL_USED (variant) = 1; + tree construct = omp_get_context_selector (ctx, "construct", NULL); + omp_mark_declare_variant (match_loc, variant, construct); + if (omp_context_selector_matches (ctx)) + { + tree attr + = tree_cons (get_identifier ("omp declare variant base"), + build_tree_list (variant, ctx), + DECL_ATTRIBUTES (fndecl)); + DECL_ATTRIBUTES (fndecl) = attr; + } + } + } + + parens.require_close (parser); + c_parser_skip_to_pragma_eol (parser); +} + +/* Finalize #pragma omp declare simd or #pragma omp declare variant + clauses after FNDECL has been parsed, and put that into "omp declare simd" + or "omp declare variant base" attribute. */ + +static void +c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms, + vec *pclauses) +{ + vec &clauses = *pclauses; + + /* Normally first token is CPP_NAME "simd" or "variant". CPP_EOF there + indicates error has been reported and CPP_PRAGMA that + c_finish_omp_declare_simd has already processed the tokens. */ + if (clauses.exists () && clauses[0].type == CPP_EOF) + return; + const char *kind = "simd"; + if (clauses.exists () + && (clauses[0].type == CPP_NAME || clauses[0].type == CPP_PRAGMA)) + kind = IDENTIFIER_POINTER (clauses[0].value); + gcc_assert (strcmp (kind, "simd") == 0 || strcmp (kind, "variant") == 0); + if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) + { + error ("%<#pragma omp declare %s%> not immediately followed by " + "a function declaration or definition", kind); + clauses[0].type = CPP_EOF; + return; + } + if (clauses.exists () && clauses[0].type != CPP_NAME) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "%<#pragma omp declare %s%> not immediately followed by " + "a single function declaration or definition", kind); + clauses[0].type = CPP_EOF; + return; + } + + if (parms == NULL_TREE) + parms = DECL_ARGUMENTS (fndecl); + + unsigned int tokens_avail = parser->tokens_avail; + gcc_assert (parser->tokens == &parser->tokens_buf[0]); + + parser->tokens = clauses.address (); + parser->tokens_avail = clauses.length (); + + /* c_parser_omp_declare_simd pushed 2 extra CPP_EOF tokens at the end. */ + while (parser->tokens_avail > 3) + { + c_token *token = c_parser_peek_token (parser); + gcc_assert (token->type == CPP_NAME + && strcmp (IDENTIFIER_POINTER (token->value), kind) == 0); + c_parser_consume_token (parser); + parser->in_pragma = true; + + if (strcmp (kind, "simd") == 0) + { + tree c; + c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, + "#pragma omp declare simd"); + c = c_omp_declare_simd_clauses_to_numbers (parms, c); + if (c != NULL_TREE) + c = tree_cons (NULL_TREE, c, NULL_TREE); + c = build_tree_list (get_identifier ("omp declare simd"), c); + TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl); + DECL_ATTRIBUTES (fndecl) = c; + } + else + { + gcc_assert (strcmp (kind, "variant") == 0); + c_finish_omp_declare_variant (parser, fndecl, parms); + } + } + + parser->tokens = &parser->tokens_buf[0]; + parser->tokens_avail = tokens_avail; + if (clauses.exists ()) + clauses[0].type = CPP_PRAGMA; +} + + +/* OpenMP 4.0: + # pragma omp declare target new-line + declarations and definitions + # pragma omp end declare target new-line + + OpenMP 4.5: + # pragma omp declare target ( extended-list ) new-line + + # pragma omp declare target declare-target-clauses[seq] new-line */ + +#define OMP_DECLARE_TARGET_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE)) + +static void +c_parser_omp_declare_target (c_parser *parser) +{ + tree clauses = NULL_TREE; + int device_type = 0; + bool only_device_type = true; + if (c_parser_next_token_is (parser, CPP_NAME)) + clauses = c_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, + "#pragma omp declare target"); + else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, + clauses); + clauses = c_finish_omp_clauses (clauses, C_ORT_OMP); + c_parser_skip_to_pragma_eol (parser); + } + else + { + c_parser_skip_to_pragma_eol (parser); + current_omp_declare_target_attribute++; + return; + } + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE) + device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c); + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE) + continue; + tree t = OMP_CLAUSE_DECL (c), id; + tree at1 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (t)); + tree at2 = lookup_attribute ("omp declare target link", + DECL_ATTRIBUTES (t)); + only_device_type = false; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK) + { + id = get_identifier ("omp declare target link"); + std::swap (at1, at2); + } + else + id = get_identifier ("omp declare target"); + if (at2) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified both in declare target % and %" + " clauses", t); + continue; + } + if (!at1) + { + DECL_ATTRIBUTES (t) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); + if (TREE_CODE (t) != FUNCTION_DECL && !is_global_var (t)) + continue; + + symtab_node *node = symtab_node::get (t); + if (node != NULL) + { + node->offloadable = 1; + if (ENABLE_OFFLOADING) + { + g->have_offload = true; + if (is_a (node)) + vec_safe_push (offload_vars, t); + } + } + } + if (TREE_CODE (t) != FUNCTION_DECL) + continue; + if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0) + { + tree at3 = lookup_attribute ("omp declare target host", + DECL_ATTRIBUTES (t)); + if (at3 == NULL_TREE) + { + id = get_identifier ("omp declare target host"); + DECL_ATTRIBUTES (t) + = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); + } + } + if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0) + { + tree at3 = lookup_attribute ("omp declare target nohost", + DECL_ATTRIBUTES (t)); + if (at3 == NULL_TREE) + { + id = get_identifier ("omp declare target nohost"); + DECL_ATTRIBUTES (t) + = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); + } + } + } + if (device_type && only_device_type) + warning_at (OMP_CLAUSE_LOCATION (clauses), 0, + "directive with only % clauses ignored"); +} + +static void +c_parser_omp_end_declare_target (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "declare") == 0) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "target") == 0) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return; + } + } + else + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return; + } + c_parser_skip_to_pragma_eol (parser); + if (!current_omp_declare_target_attribute) + error_at (loc, "%<#pragma omp end declare target%> without corresponding " + "%<#pragma omp declare target%>"); + else + current_omp_declare_target_attribute--; +} + + +/* OpenMP 4.0 + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + initializer-clause[opt] new-line + + initializer-clause: + initializer (omp_priv = initializer) + initializer (function-name (argument-list)) */ + +static void +c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) +{ + unsigned int tokens_avail = 0, i; + vec types = vNULL; + vec clauses = vNULL; + enum tree_code reduc_code = ERROR_MARK; + tree reduc_id = NULL_TREE; + tree type; + location_t rloc = c_parser_peek_token (parser)->location; + + if (context == pragma_struct || context == pragma_param) + { + error ("%<#pragma omp declare reduction%> not at file or block scope"); + goto fail; + } + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + goto fail; + + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + reduc_code = PLUS_EXPR; + break; + case CPP_MULT: + reduc_code = MULT_EXPR; + break; + case CPP_MINUS: + reduc_code = MINUS_EXPR; + break; + case CPP_AND: + reduc_code = BIT_AND_EXPR; + break; + case CPP_XOR: + reduc_code = BIT_XOR_EXPR; + break; + case CPP_OR: + reduc_code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + reduc_code = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + reduc_code = TRUTH_ORIF_EXPR; + break; + case CPP_NAME: + const char *p; + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "min") == 0) + { + reduc_code = MIN_EXPR; + break; + } + if (strcmp (p, "max") == 0) + { + reduc_code = MAX_EXPR; + break; + } + reduc_id = c_parser_peek_token (parser)->value; + break; + default: + c_parser_error (parser, + "expected %<+%>, %<*%>, %<-%>, %<&%>, " + "%<^%>, %<|%>, %<&&%>, %<||%> or identifier"); + goto fail; + } + + tree orig_reduc_id, reduc_decl; + orig_reduc_id = reduc_id; + reduc_id = c_omp_reduction_id (reduc_code, reduc_id); + reduc_decl = c_omp_reduction_decl (reduc_id); + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto fail; + + while (true) + { + location_t loc = c_parser_peek_token (parser)->location; + struct c_type_name *ctype = c_parser_type_name (parser); + if (ctype != NULL) + { + type = groktypename (ctype, NULL, NULL); + if (type == error_mark_node) + ; + else if ((INTEGRAL_TYPE_P (type) + || TREE_CODE (type) == REAL_TYPE + || TREE_CODE (type) == COMPLEX_TYPE) + && orig_reduc_id == NULL_TREE) + error_at (loc, "predeclared arithmetic type in " + "%<#pragma omp declare reduction%>"); + else if (TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == ARRAY_TYPE) + error_at (loc, "function or array type in " + "%<#pragma omp declare reduction%>"); + else if (TYPE_ATOMIC (type)) + error_at (loc, "%<_Atomic%> qualified type in " + "%<#pragma omp declare reduction%>"); + else if (TYPE_QUALS_NO_ADDR_SPACE (type)) + error_at (loc, "const, volatile or restrict qualified type in " + "%<#pragma omp declare reduction%>"); + else + { + tree t; + for (t = DECL_INITIAL (reduc_decl); t; t = TREE_CHAIN (t)) + if (comptypes (TREE_PURPOSE (t), type)) + { + error_at (loc, "redeclaration of %qs " + "%<#pragma omp declare reduction%> for " + "type %qT", + IDENTIFIER_POINTER (reduc_id) + + sizeof ("omp declare reduction ") - 1, + type); + location_t ploc + = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t), + 0)); + error_at (ploc, "previous %<#pragma omp declare " + "reduction%>"); + break; + } + if (t == NULL_TREE) + types.safe_push (type); + } + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + else + break; + } + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>") + || types.is_empty ()) + { + fail: + clauses.release (); + types.release (); + while (true) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF || token->type == CPP_PRAGMA_EOL) + break; + c_parser_consume_token (parser); + } + c_parser_skip_to_pragma_eol (parser); + return; + } + + if (types.length () > 1) + { + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF) + goto fail; + clauses.safe_push (*token); + c_parser_consume_token (parser); + } + clauses.safe_push (*c_parser_peek_token (parser)); + c_parser_skip_to_pragma_eol (parser); + + /* Make sure nothing tries to read past the end of the tokens. */ + c_token eof_token; + memset (&eof_token, 0, sizeof (eof_token)); + eof_token.type = CPP_EOF; + clauses.safe_push (eof_token); + clauses.safe_push (eof_token); + } + + int errs = errorcount; + FOR_EACH_VEC_ELT (types, i, type) + { + tokens_avail = parser->tokens_avail; + gcc_assert (parser->tokens == &parser->tokens_buf[0]); + if (!clauses.is_empty ()) + { + parser->tokens = clauses.address (); + parser->tokens_avail = clauses.length (); + parser->in_pragma = true; + } + + bool nested = current_function_decl != NULL_TREE; + if (nested) + c_push_function_context (); + tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, + reduc_id, default_function_type); + current_function_decl = fndecl; + allocate_struct_function (fndecl, true); + push_scope (); + tree stmt = push_stmt_list (); + /* Intentionally BUILTINS_LOCATION, so that -Wshadow doesn't + warn about these. */ + tree omp_out = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_out"), type); + DECL_ARTIFICIAL (omp_out) = 1; + DECL_CONTEXT (omp_out) = fndecl; + pushdecl (omp_out); + tree omp_in = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_in"), type); + DECL_ARTIFICIAL (omp_in) = 1; + DECL_CONTEXT (omp_in) = fndecl; + pushdecl (omp_in); + struct c_expr combiner = c_parser_expression (parser); + struct c_expr initializer; + tree omp_priv = NULL_TREE, omp_orig = NULL_TREE; + bool bad = false; + initializer.set_error (); + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + bad = true; + else if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER + (c_parser_peek_token (parser)->value), + "initializer") == 0) + { + c_parser_consume_token (parser); + pop_scope (); + push_scope (); + omp_priv = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_priv"), type); + DECL_ARTIFICIAL (omp_priv) = 1; + DECL_INITIAL (omp_priv) = error_mark_node; + DECL_CONTEXT (omp_priv) = fndecl; + pushdecl (omp_priv); + omp_orig = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_orig"), type); + DECL_ARTIFICIAL (omp_orig) = 1; + DECL_CONTEXT (omp_orig) = fndecl; + pushdecl (omp_orig); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + bad = true; + else if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected % or " + "function-name"); + bad = true; + } + else if (strcmp (IDENTIFIER_POINTER + (c_parser_peek_token (parser)->value), + "omp_priv") != 0) + { + if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + c_parser_error (parser, "expected function-name %<(%>"); + bad = true; + } + else + initializer = c_parser_postfix_expression (parser); + if (initializer.value + && TREE_CODE (initializer.value) == CALL_EXPR) + { + int j; + tree c = initializer.value; + for (j = 0; j < call_expr_nargs (c); j++) + { + tree a = CALL_EXPR_ARG (c, j); + STRIP_NOPS (a); + if (TREE_CODE (a) == ADDR_EXPR + && TREE_OPERAND (a, 0) == omp_priv) + break; + } + if (j == call_expr_nargs (c)) + error ("one of the initializer call arguments should be " + "%<&omp_priv%>"); + } + } + else + { + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + bad = true; + else + { + tree st = push_stmt_list (); + location_t loc = c_parser_peek_token (parser)->location; + rich_location richloc (line_table, loc); + start_init (omp_priv, NULL_TREE, 0, &richloc); + struct c_expr init = c_parser_initializer (parser); + finish_init (); + finish_decl (omp_priv, loc, init.value, + init.original_type, NULL_TREE); + pop_stmt_list (st); + } + } + if (!bad + && !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + bad = true; + } + + if (!bad) + { + c_parser_skip_to_pragma_eol (parser); + + tree t = tree_cons (type, make_tree_vec (omp_priv ? 6 : 3), + DECL_INITIAL (reduc_decl)); + DECL_INITIAL (reduc_decl) = t; + DECL_SOURCE_LOCATION (omp_out) = rloc; + TREE_VEC_ELT (TREE_VALUE (t), 0) = omp_out; + TREE_VEC_ELT (TREE_VALUE (t), 1) = omp_in; + TREE_VEC_ELT (TREE_VALUE (t), 2) = combiner.value; + walk_tree (&combiner.value, c_check_omp_declare_reduction_r, + &TREE_VEC_ELT (TREE_VALUE (t), 0), NULL); + if (omp_priv) + { + DECL_SOURCE_LOCATION (omp_priv) = rloc; + TREE_VEC_ELT (TREE_VALUE (t), 3) = omp_priv; + TREE_VEC_ELT (TREE_VALUE (t), 4) = omp_orig; + TREE_VEC_ELT (TREE_VALUE (t), 5) = initializer.value; + walk_tree (&initializer.value, c_check_omp_declare_reduction_r, + &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); + walk_tree (&DECL_INITIAL (omp_priv), + c_check_omp_declare_reduction_r, + &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); + } + } + + pop_stmt_list (stmt); + pop_scope (); + if (cfun->language != NULL) + { + ggc_free (cfun->language); + cfun->language = NULL; + } + set_cfun (NULL); + current_function_decl = NULL_TREE; + if (nested) + c_pop_function_context (); + + if (!clauses.is_empty ()) + { + parser->tokens = &parser->tokens_buf[0]; + parser->tokens_avail = tokens_avail; + } + if (bad) + goto fail; + if (errs != errorcount) + break; + } + + clauses.release (); + types.release (); +} + + +/* OpenMP 4.0 + #pragma omp declare simd declare-simd-clauses[optseq] new-line + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + initializer-clause[opt] new-line + #pragma omp declare target new-line + + OpenMP 5.0 + #pragma omp declare variant (identifier) match (context-selector) */ + +static bool +c_parser_omp_declare (c_parser *parser, enum pragma_context context) +{ + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "simd") == 0) + { + /* c_parser_consume_token (parser); done in + c_parser_omp_declare_simd. */ + c_parser_omp_declare_simd (parser, context); + return true; + } + if (strcmp (p, "reduction") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_declare_reduction (parser, context); + return false; + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return false; + } + if (strcmp (p, "target") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_declare_target (parser); + return false; + } + if (strcmp (p, "variant") == 0) + { + /* c_parser_consume_token (parser); done in + c_parser_omp_declare_simd. */ + c_parser_omp_declare_simd (parser, context); + return true; + } + } + + c_parser_error (parser, "expected %, %, " + "% or %"); + c_parser_skip_to_pragma_eol (parser); + return false; +} + +/* OpenMP 5.0 + #pragma omp requires clauses[optseq] new-line */ + +static void +c_parser_omp_requires (c_parser *parser) +{ + bool first = true; + enum omp_requires new_req = (enum omp_requires) 0; + + c_parser_consume_pragma (parser); + + location_t loc = c_parser_peek_token (parser)->location; + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + if (!first + && c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + + first = false; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + location_t cloc = c_parser_peek_token (parser)->location; + enum omp_requires this_req = (enum omp_requires) 0; + + if (!strcmp (p, "unified_address")) + this_req = OMP_REQUIRES_UNIFIED_ADDRESS; + else if (!strcmp (p, "unified_shared_memory")) + this_req = OMP_REQUIRES_UNIFIED_SHARED_MEMORY; + else if (!strcmp (p, "dynamic_allocators")) + this_req = OMP_REQUIRES_DYNAMIC_ALLOCATORS; + else if (!strcmp (p, "reverse_offload")) + this_req = OMP_REQUIRES_REVERSE_OFFLOAD; + else if (!strcmp (p, "atomic_default_mem_order")) + { + c_parser_consume_token (parser); + + matching_parens parens; + if (parens.require_open (parser)) + { + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree v = c_parser_peek_token (parser)->value; + p = IDENTIFIER_POINTER (v); + + if (!strcmp (p, "seq_cst")) + this_req + = (enum omp_requires) OMP_MEMORY_ORDER_SEQ_CST; + else if (!strcmp (p, "relaxed")) + this_req + = (enum omp_requires) OMP_MEMORY_ORDER_RELAXED; + else if (!strcmp (p, "acq_rel")) + this_req + = (enum omp_requires) OMP_MEMORY_ORDER_ACQ_REL; + } + if (this_req == 0) + { + error_at (c_parser_peek_token (parser)->location, + "expected %, % or " + "%"); + switch (c_parser_peek_token (parser)->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + case CPP_CLOSE_PAREN: + break; + default: + if (c_parser_peek_2nd_token (parser)->type + == CPP_CLOSE_PAREN) + c_parser_consume_token (parser); + break; + } + } + else + c_parser_consume_token (parser); + + parens.skip_until_found_close (parser); + if (this_req == 0) + { + c_parser_skip_to_pragma_eol (parser, false); + return; + } + } + p = NULL; + } + else + { + error_at (cloc, "expected %, " + "%, " + "%, " + "% " + "or % clause"); + c_parser_skip_to_pragma_eol (parser, false); + return; + } + if (p && this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS) + sorry_at (cloc, "%qs clause on % directive not " + "supported yet", p); + if (p) + c_parser_consume_token (parser); + if (this_req) + { + if ((this_req & ~OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) + { + if ((this_req & new_req) != 0) + error_at (cloc, "too many %qs clauses", p); + if (this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS + && (omp_requires_mask & OMP_REQUIRES_TARGET_USED) != 0) + error_at (cloc, "%qs clause used lexically after first " + "target construct or offloading API", p); + } + else if ((new_req & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) + { + error_at (cloc, "too many %qs clauses", + "atomic_default_mem_order"); + this_req = (enum omp_requires) 0; + } + else if ((omp_requires_mask + & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) + { + error_at (cloc, "more than one %" + " clause in a single compilation unit"); + this_req + = (enum omp_requires) + (omp_requires_mask + & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER); + } + else if ((omp_requires_mask + & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED) != 0) + error_at (cloc, "% clause used " + "lexically after first % construct " + "without memory order clause"); + new_req = (enum omp_requires) (new_req | this_req); + omp_requires_mask + = (enum omp_requires) (omp_requires_mask | this_req); + continue; + } + } + break; + } + c_parser_skip_to_pragma_eol (parser); + + if (new_req == 0) + error_at (loc, "% requires at least one clause"); +} + +/* Helper function for c_parser_omp_taskloop. + Disallow zero sized or potentially zero sized task reductions. */ + +static tree +c_finish_taskloop_clauses (tree clauses) +{ + tree *pc = &clauses; + for (tree c = clauses; c; c = *pc) + { + bool remove = false; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + tree type = strip_array_types (TREE_TYPE (OMP_CLAUSE_DECL (c))); + if (integer_zerop (TYPE_SIZE_UNIT (type))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero sized type %qT in % clause", type); + remove = true; + } + else if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "variable sized type %qT in % clause", + type); + remove = true; + } + } + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + return clauses; +} + +/* OpenMP 4.5: + #pragma omp taskloop taskloop-clause[optseq] new-line + for-loop + + #pragma omp taskloop simd taskloop-simd-clause[optseq] new-line + for-loop */ + +#define OMP_TASKLOOP_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_GRAINSIZE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TASKS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)) + +static tree +c_parser_omp_taskloop (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree clauses, block, ret; + + strcat (p_name, " taskloop"); + mask |= OMP_TASKLOOP_CLAUSE_MASK; + /* #pragma omp parallel master taskloop{, simd} disallow in_reduction + clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "simd") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + ret = make_node (OMP_TASKLOOP); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = block; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; + OMP_FOR_CLAUSES (ret) + = c_finish_taskloop_clauses (OMP_FOR_CLAUSES (ret)); + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_TASKLOOP, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; + } + + clauses = c_finish_taskloop_clauses (clauses); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_TASKLOOP, clauses, NULL, if_p); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 5.1 + #pragma omp nothing new-line */ + +static void +c_parser_omp_nothing (c_parser *parser) +{ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); +} + +/* OpenMP 5.1 + #pragma omp error clauses[optseq] new-line */ + +static bool +c_parser_omp_error (c_parser *parser, enum pragma_context context) +{ + int at_compilation = -1; + int severity_fatal = -1; + tree message = NULL_TREE; + bool first = true; + bool bad = false; + location_t loc = c_parser_peek_token (parser)->location; + + c_parser_consume_pragma (parser); + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + if (!first + && c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + + first = false; + + if (!c_parser_next_token_is (parser, CPP_NAME)) + break; + + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + location_t cloc = c_parser_peek_token (parser)->location; + static const char *args[] = { + "execution", "compilation", "warning", "fatal" + }; + int *v = NULL; + int idx = 0, n = -1; + tree m = NULL_TREE; + + if (!strcmp (p, "at")) + v = &at_compilation; + else if (!strcmp (p, "severity")) + { + v = &severity_fatal; + idx += 2; + } + else if (strcmp (p, "message")) + { + error_at (cloc, + "expected %, % or % clause"); + c_parser_skip_to_pragma_eol (parser, false); + return false; + } + + c_parser_consume_token (parser); + + matching_parens parens; + if (parens.require_open (parser)) + { + if (v == NULL) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true); + m = convert (const_string_type_node, expr.value); + m = c_fully_fold (m, false, NULL); + } + else + { + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree val = c_parser_peek_token (parser)->value; + const char *q = IDENTIFIER_POINTER (val); + + if (!strcmp (q, args[idx])) + n = 0; + else if (!strcmp (q, args[idx + 1])) + n = 1; + } + if (n == -1) + { + error_at (c_parser_peek_token (parser)->location, + "expected %qs or %qs", args[idx], args[idx + 1]); + bad = true; + switch (c_parser_peek_token (parser)->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + case CPP_CLOSE_PAREN: + break; + default: + if (c_parser_peek_2nd_token (parser)->type + == CPP_CLOSE_PAREN) + c_parser_consume_token (parser); + break; + } + } + else + c_parser_consume_token (parser); + } + + parens.skip_until_found_close (parser); + + if (v == NULL) + { + if (message) + { + error_at (cloc, "too many %qs clauses", p); + bad = true; + } + else + message = m; + } + else if (n != -1) + { + if (*v != -1) + { + error_at (cloc, "too many %qs clauses", p); + bad = true; + } + else + *v = n; + } + } + else + bad = true; + } + c_parser_skip_to_pragma_eol (parser); + if (bad) + return true; + + if (at_compilation == -1) + at_compilation = 1; + if (severity_fatal == -1) + severity_fatal = 1; + if (!at_compilation) + { + if (context != pragma_compound) + { + error_at (loc, "%<#pragma omp error%> with % clause " + "may only be used in compound statements"); + return true; + } + tree fndecl + = builtin_decl_explicit (severity_fatal ? BUILT_IN_GOMP_ERROR + : BUILT_IN_GOMP_WARNING); + if (!message) + message = build_zero_cst (const_string_type_node); + tree stmt = build_call_expr_loc (loc, fndecl, 2, message, + build_all_ones_cst (size_type_node)); + add_stmt (stmt); + return true; + } + const char *msg = NULL; + if (message) + { + msg = c_getstr (message); + if (msg == NULL) + msg = _(""); + } + if (msg) + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "% encountered: %s", msg); + else + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "% encountered"); + return false; +} + +/* Main entry point to parsing most OpenMP pragmas. */ + +static void +c_parser_omp_construct (c_parser *parser, bool *if_p) +{ + enum pragma_kind p_kind; + location_t loc; + tree stmt; + char p_name[sizeof "#pragma omp teams distribute parallel for simd"]; + omp_clause_mask mask (0); + + loc = c_parser_peek_token (parser)->location; + p_kind = c_parser_peek_token (parser)->pragma_kind; + c_parser_consume_pragma (parser); + + switch (p_kind) + { + case PRAGMA_OACC_ATOMIC: + c_parser_omp_atomic (loc, parser, true); + return; + case PRAGMA_OACC_CACHE: + strcpy (p_name, "#pragma acc"); + stmt = c_parser_oacc_cache (loc, parser); + break; + case PRAGMA_OACC_DATA: + stmt = c_parser_oacc_data (loc, parser, if_p); + break; + case PRAGMA_OACC_HOST_DATA: + stmt = c_parser_oacc_host_data (loc, parser, if_p); + break; + case PRAGMA_OACC_KERNELS: + case PRAGMA_OACC_PARALLEL: + case PRAGMA_OACC_SERIAL: + strcpy (p_name, "#pragma acc"); + stmt = c_parser_oacc_compute (loc, parser, p_kind, p_name, if_p); + break; + case PRAGMA_OACC_LOOP: + strcpy (p_name, "#pragma acc"); + stmt = c_parser_oacc_loop (loc, parser, p_name, mask, NULL, if_p); + break; + case PRAGMA_OACC_WAIT: + strcpy (p_name, "#pragma wait"); + stmt = c_parser_oacc_wait (loc, parser, p_name); + break; + case PRAGMA_OMP_ALLOCATE: + c_parser_omp_allocate (loc, parser); + return; + case PRAGMA_OMP_ATOMIC: + c_parser_omp_atomic (loc, parser, false); + return; + case PRAGMA_OMP_CRITICAL: + stmt = c_parser_omp_critical (loc, parser, if_p); + break; + case PRAGMA_OMP_DISTRIBUTE: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_distribute (loc, parser, p_name, mask, NULL, if_p); + break; + case PRAGMA_OMP_FOR: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL, if_p); + break; + case PRAGMA_OMP_LOOP: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_loop (loc, parser, p_name, mask, NULL, if_p); + break; + case PRAGMA_OMP_MASKED: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_masked (loc, parser, p_name, mask, NULL, if_p); + break; + case PRAGMA_OMP_MASTER: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p); + break; + case PRAGMA_OMP_PARALLEL: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL, if_p); + break; + case PRAGMA_OMP_SCOPE: + stmt = c_parser_omp_scope (loc, parser, if_p); + break; + case PRAGMA_OMP_SECTIONS: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL); + break; + case PRAGMA_OMP_SIMD: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_simd (loc, parser, p_name, mask, NULL, if_p); + break; + case PRAGMA_OMP_SINGLE: + stmt = c_parser_omp_single (loc, parser, if_p); + break; + case PRAGMA_OMP_TASK: + stmt = c_parser_omp_task (loc, parser, if_p); + break; + case PRAGMA_OMP_TASKGROUP: + stmt = c_parser_omp_taskgroup (loc, parser, if_p); + break; + case PRAGMA_OMP_TASKLOOP: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_taskloop (loc, parser, p_name, mask, NULL, if_p); + break; + case PRAGMA_OMP_TEAMS: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL, if_p); + break; + default: + gcc_unreachable (); + } + + if (stmt && stmt != error_mark_node) + gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION); +} + + +/* OpenMP 2.5: + # pragma omp threadprivate (variable-list) */ + +static void +c_parser_omp_threadprivate (c_parser *parser) +{ + tree vars, t; + location_t loc; + + c_parser_consume_pragma (parser); + loc = c_parser_peek_token (parser)->location; + vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); + + /* Mark every variable in VARS to be assigned thread local storage. */ + for (t = vars; t; t = TREE_CHAIN (t)) + { + tree v = TREE_PURPOSE (t); + + /* FIXME diagnostics: Ideally we should keep individual + locations for all the variables in the var list to make the + following errors more precise. Perhaps + c_parser_omp_var_list_parens() should construct a list of + locations to go along with the var list. */ + + /* If V had already been marked threadprivate, it doesn't matter + whether it had been used prior to this point. */ + if (!VAR_P (v)) + error_at (loc, "%qD is not a variable", v); + else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v)) + error_at (loc, "%qE declared % after first use", v); + else if (! is_global_var (v)) + error_at (loc, "automatic variable %qE cannot be %", v); + else if (TREE_TYPE (v) == error_mark_node) + ; + else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) + error_at (loc, "% %qE has incomplete type", v); + else + { + if (! DECL_THREAD_LOCAL_P (v)) + { + set_decl_tls_model (v, decl_default_tls_model (v)); + /* If rtl has been already set for this var, call + make_decl_rtl once again, so that encode_section_info + has a chance to look at the new decl flags. */ + if (DECL_RTL_SET_P (v)) + make_decl_rtl (v); + } + C_DECL_THREADPRIVATE_P (v) = 1; + } + } + + c_parser_skip_to_pragma_eol (parser); +} + +/* Parse a transaction attribute (GCC Extension). + + transaction-attribute: + gnu-attributes + attribute-specifier +*/ + +static tree +c_parser_transaction_attributes (c_parser *parser) +{ + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + return c_parser_gnu_attributes (parser); + + if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + return NULL_TREE; + return c_parser_std_attribute_specifier (parser, true); +} + +/* Parse a __transaction_atomic or __transaction_relaxed statement + (GCC Extension). + + transaction-statement: + __transaction_atomic transaction-attribute[opt] compound-statement + __transaction_relaxed compound-statement + + Note that the only valid attribute is: "outer". +*/ + +static tree +c_parser_transaction (c_parser *parser, enum rid keyword) +{ + unsigned int old_in = parser->in_transaction; + unsigned int this_in = 1, new_in; + location_t loc = c_parser_peek_token (parser)->location; + tree stmt, attrs; + + gcc_assert ((keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED) + && c_parser_next_token_is_keyword (parser, keyword)); + c_parser_consume_token (parser); + + if (keyword == RID_TRANSACTION_RELAXED) + this_in |= TM_STMT_ATTR_RELAXED; + else + { + attrs = c_parser_transaction_attributes (parser); + if (attrs) + this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); + } + + /* Keep track if we're in the lexical scope of an outer transaction. */ + new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); + + parser->in_transaction = new_in; + stmt = c_parser_compound_statement (parser); + parser->in_transaction = old_in; + + if (flag_tm) + stmt = c_finish_transaction (loc, stmt, this_in); + else + error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? + "%<__transaction_atomic%> without transactional memory support enabled" + : "%<__transaction_relaxed %> " + "without transactional memory support enabled")); + + return stmt; +} + +/* Parse a __transaction_atomic or __transaction_relaxed expression + (GCC Extension). + + transaction-expression: + __transaction_atomic ( expression ) + __transaction_relaxed ( expression ) +*/ + +static struct c_expr +c_parser_transaction_expression (c_parser *parser, enum rid keyword) +{ + struct c_expr ret; + unsigned int old_in = parser->in_transaction; + unsigned int this_in = 1; + location_t loc = c_parser_peek_token (parser)->location; + tree attrs; + + gcc_assert ((keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED) + && c_parser_next_token_is_keyword (parser, keyword)); + c_parser_consume_token (parser); + + if (keyword == RID_TRANSACTION_RELAXED) + this_in |= TM_STMT_ATTR_RELAXED; + else + { + attrs = c_parser_transaction_attributes (parser); + if (attrs) + this_in |= parse_tm_stmt_attr (attrs, 0); + } + + parser->in_transaction = this_in; + matching_parens parens; + if (parens.require_open (parser)) + { + tree expr = c_parser_expression (parser).value; + ret.original_type = TREE_TYPE (expr); + ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr); + if (this_in & TM_STMT_ATTR_RELAXED) + TRANSACTION_EXPR_RELAXED (ret.value) = 1; + SET_EXPR_LOCATION (ret.value, loc); + ret.original_code = TRANSACTION_EXPR; + if (!parens.require_close (parser)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + goto error; + } + } + else + { + error: + ret.set_error (); + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + } + parser->in_transaction = old_in; + + if (!flag_tm) + error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? + "%<__transaction_atomic%> without transactional memory support enabled" + : "%<__transaction_relaxed %> " + "without transactional memory support enabled")); + + set_c_expr_source_range (&ret, loc, loc); + + return ret; +} + +/* Parse a __transaction_cancel statement (GCC Extension). + + transaction-cancel-statement: + __transaction_cancel transaction-attribute[opt] ; + + Note that the only valid attribute is "outer". +*/ + +static tree +c_parser_transaction_cancel (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree attrs; + bool is_outer = false; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRANSACTION_CANCEL)); + c_parser_consume_token (parser); + + attrs = c_parser_transaction_attributes (parser); + if (attrs) + is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0); + + if (!flag_tm) + { + error_at (loc, "%<__transaction_cancel%> without " + "transactional memory support enabled"); + goto ret_error; + } + else if (parser->in_transaction & TM_STMT_ATTR_RELAXED) + { + error_at (loc, "%<__transaction_cancel%> within a " + "%<__transaction_relaxed%>"); + goto ret_error; + } + else if (is_outer) + { + if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0 + && !is_tm_may_cancel_outer (current_function_decl)) + { + error_at (loc, "outer %<__transaction_cancel%> not " + "within outer %<__transaction_atomic%> or " + "a % function"); + goto ret_error; + } + } + else if (parser->in_transaction == 0) + { + error_at (loc, "%<__transaction_cancel%> not within " + "%<__transaction_atomic%>"); + goto ret_error; + } + + return add_stmt (build_tm_abort_call (loc, is_outer)); + + ret_error: + return build1 (NOP_EXPR, void_type_node, error_mark_node); +} + +/* Parse a single source file. */ + +void +c_parse_file (void) +{ + /* Use local storage to begin. If the first token is a pragma, parse it. + If it is #pragma GCC pch_preprocess, then this will load a PCH file + which will cause garbage collection. */ + c_parser tparser; + + memset (&tparser, 0, sizeof tparser); + tparser.translate_strings_p = true; + tparser.tokens = &tparser.tokens_buf[0]; + the_parser = &tparser; + + if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) + c_parser_pragma_pch_preprocess (&tparser); + else + c_common_no_more_pch (); + + the_parser = ggc_alloc (); + *the_parser = tparser; + if (tparser.tokens == &tparser.tokens_buf[0]) + the_parser->tokens = &the_parser->tokens_buf[0]; + + /* Initialize EH, if we've been told to do so. */ + if (flag_exceptions) + using_eh_for_cleanups (); + + c_parser_translation_unit (the_parser); + the_parser = NULL; +} + +/* Parse the body of a function declaration marked with "__RTL". + + The RTL parser works on the level of characters read from a + FILE *, whereas c_parser works at the level of tokens. + Square this circle by consuming all of the tokens up to and + including the closing brace, recording the start/end of the RTL + fragment, and reopening the file and re-reading the relevant + lines within the RTL parser. + + This requires the opening and closing braces of the C function + to be on separate lines from the RTL they wrap. + + Take ownership of START_WITH_PASS, if non-NULL. */ + +location_t +c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass) +{ + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + { + free (start_with_pass); + return c_parser_peek_token (parser)->location; + } + + location_t start_loc = c_parser_peek_token (parser)->location; + + /* Consume all tokens, up to the closing brace, handling + matching pairs of braces in the rtl dump. */ + int num_open_braces = 1; + while (1) + { + switch (c_parser_peek_token (parser)->type) + { + case CPP_OPEN_BRACE: + num_open_braces++; + break; + case CPP_CLOSE_BRACE: + if (--num_open_braces == 0) + goto found_closing_brace; + break; + case CPP_EOF: + error_at (start_loc, "no closing brace"); + free (start_with_pass); + return c_parser_peek_token (parser)->location; + default: + break; + } + c_parser_consume_token (parser); + } + + found_closing_brace: + /* At the closing brace; record its location. */ + location_t end_loc = c_parser_peek_token (parser)->location; + + /* Consume the closing brace. */ + c_parser_consume_token (parser); + + /* Invoke the RTL parser. */ + if (!read_rtl_function_body_from_file_range (start_loc, end_loc)) + { + free (start_with_pass); + return end_loc; + } + + /* Run the backend on the cfun created above, transferring ownership of + START_WITH_PASS. */ + run_rtl_passes (start_with_pass); + return end_loc; +} + +#include "gt-c-c-parser.h" diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c deleted file mode 100644 index ac6618e..0000000 --- a/gcc/c/c-typeck.c +++ /dev/null @@ -1,16079 +0,0 @@ -/* Build expressions with type checking for C compiler. - Copyright (C) 1987-2022 Free Software Foundation, Inc. - -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 -. */ - - -/* This file is part of the C front end. - It contains routines to build C expressions given their operands, - including computing the types of the result, C-specific error checks, - and some optimization. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "memmodel.h" -#include "target.h" -#include "function.h" -#include "bitmap.h" -#include "c-tree.h" -#include "gimple-expr.h" -#include "predict.h" -#include "stor-layout.h" -#include "trans-mem.h" -#include "varasm.h" -#include "stmt.h" -#include "langhooks.h" -#include "c-lang.h" -#include "intl.h" -#include "tree-iterator.h" -#include "gimplify.h" -#include "tree-inline.h" -#include "omp-general.h" -#include "c-family/c-objc.h" -#include "c-family/c-ubsan.h" -#include "gomp-constants.h" -#include "spellcheck-tree.h" -#include "gcc-rich-location.h" -#include "stringpool.h" -#include "attribs.h" -#include "asan.h" - -/* Possible cases of implicit conversions. Used to select diagnostic messages - and control folding initializers in convert_for_assignment. */ -enum impl_conv { - ic_argpass, - ic_assign, - ic_init, - ic_init_const, - ic_return -}; - -/* The level of nesting inside "__alignof__". */ -int in_alignof; - -/* The level of nesting inside "sizeof". */ -int in_sizeof; - -/* The level of nesting inside "typeof". */ -int in_typeof; - -/* True when parsing OpenMP loop expressions. */ -bool c_in_omp_for; - -/* The argument of last parsed sizeof expression, only to be tested - if expr.original_code == SIZEOF_EXPR. */ -tree c_last_sizeof_arg; -location_t c_last_sizeof_loc; - -/* Nonzero if we might need to print a "missing braces around - initializer" message within this initializer. */ -static int found_missing_braces; - -static int require_constant_value; -static int require_constant_elements; - -static bool null_pointer_constant_p (const_tree); -static tree qualify_type (tree, tree); -static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *, - bool *); -static int comp_target_types (location_t, tree, tree); -static int function_types_compatible_p (const_tree, const_tree, bool *, - bool *); -static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *); -static tree lookup_field (tree, tree); -static int convert_arguments (location_t, vec, tree, - vec *, vec *, tree, - tree); -static tree pointer_diff (location_t, tree, tree, tree *); -static tree convert_for_assignment (location_t, location_t, tree, tree, tree, - enum impl_conv, bool, tree, tree, int, - int = 0); -static tree valid_compound_expr_initializer (tree, tree); -static void push_string (const char *); -static void push_member_name (tree); -static int spelling_length (void); -static char *print_spelling (char *); -static void warning_init (location_t, int, const char *); -static tree digest_init (location_t, tree, tree, tree, bool, bool, int); -static void output_init_element (location_t, tree, tree, bool, tree, tree, bool, - bool, struct obstack *); -static void output_pending_init_elements (int, struct obstack *); -static bool set_designator (location_t, bool, struct obstack *); -static void push_range_stack (tree, struct obstack *); -static void add_pending_init (location_t, tree, tree, tree, bool, - struct obstack *); -static void set_nonincremental_init (struct obstack *); -static void set_nonincremental_init_from_string (tree, struct obstack *); -static tree find_init_member (tree, struct obstack *); -static void readonly_warning (tree, enum lvalue_use); -static int lvalue_or_else (location_t, const_tree, enum lvalue_use); -static void record_maybe_used_decl (tree); -static int comptypes_internal (const_tree, const_tree, bool *, bool *); - -/* Return true if EXP is a null pointer constant, false otherwise. */ - -static bool -null_pointer_constant_p (const_tree expr) -{ - /* This should really operate on c_expr structures, but they aren't - yet available everywhere required. */ - tree type = TREE_TYPE (expr); - return (TREE_CODE (expr) == INTEGER_CST - && !TREE_OVERFLOW (expr) - && integer_zerop (expr) - && (INTEGRAL_TYPE_P (type) - || (TREE_CODE (type) == POINTER_TYPE - && VOID_TYPE_P (TREE_TYPE (type)) - && TYPE_QUALS (TREE_TYPE (type)) == TYPE_UNQUALIFIED))); -} - -/* EXPR may appear in an unevaluated part of an integer constant - expression, but not in an evaluated part. Wrap it in a - C_MAYBE_CONST_EXPR, or mark it with TREE_OVERFLOW if it is just an - INTEGER_CST and we cannot create a C_MAYBE_CONST_EXPR. */ - -static tree -note_integer_operands (tree expr) -{ - tree ret; - if (TREE_CODE (expr) == INTEGER_CST && in_late_binary_op) - { - ret = copy_node (expr); - TREE_OVERFLOW (ret) = 1; - } - else - { - ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL_TREE, expr); - C_MAYBE_CONST_EXPR_INT_OPERANDS (ret) = 1; - } - return ret; -} - -/* Having checked whether EXPR may appear in an unevaluated part of an - integer constant expression and found that it may, remove any - C_MAYBE_CONST_EXPR noting this fact and return the resulting - expression. */ - -static inline tree -remove_c_maybe_const_expr (tree expr) -{ - if (TREE_CODE (expr) == C_MAYBE_CONST_EXPR) - return C_MAYBE_CONST_EXPR_EXPR (expr); - else - return expr; -} - - /* This is a cache to hold if two types are compatible or not. */ - -struct tagged_tu_seen_cache { - const struct tagged_tu_seen_cache * next; - const_tree t1; - const_tree t2; - /* The return value of tagged_types_tu_compatible_p if we had seen - these two types already. */ - int val; -}; - -static const struct tagged_tu_seen_cache * tagged_tu_seen_base; -static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *); - -/* Do `exp = require_complete_type (loc, exp);' to make sure exp - does not have an incomplete type. (That includes void types.) - LOC is the location of the use. */ - -tree -require_complete_type (location_t loc, tree value) -{ - tree type = TREE_TYPE (value); - - if (error_operand_p (value)) - return error_mark_node; - - /* First, detect a valid value with a complete type. */ - if (COMPLETE_TYPE_P (type)) - return value; - - c_incomplete_type_error (loc, value, type); - return error_mark_node; -} - -/* Print an error message for invalid use of an incomplete type. - VALUE is the expression that was used (or 0 if that isn't known) - and TYPE is the type that was invalid. LOC is the location for - the error. */ - -void -c_incomplete_type_error (location_t loc, const_tree value, const_tree type) -{ - /* Avoid duplicate error message. */ - if (TREE_CODE (type) == ERROR_MARK) - return; - - if (value != NULL_TREE && (VAR_P (value) || TREE_CODE (value) == PARM_DECL)) - error_at (loc, "%qD has an incomplete type %qT", value, type); - else - { - retry: - /* We must print an error message. Be clever about what it says. */ - - switch (TREE_CODE (type)) - { - case RECORD_TYPE: - case UNION_TYPE: - case ENUMERAL_TYPE: - break; - - case VOID_TYPE: - error_at (loc, "invalid use of void expression"); - return; - - case ARRAY_TYPE: - if (TYPE_DOMAIN (type)) - { - if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL) - { - error_at (loc, "invalid use of flexible array member"); - return; - } - type = TREE_TYPE (type); - goto retry; - } - error_at (loc, "invalid use of array with unspecified bounds"); - return; - - default: - gcc_unreachable (); - } - - if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) - error_at (loc, "invalid use of undefined type %qT", type); - else - /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */ - error_at (loc, "invalid use of incomplete typedef %qT", type); - } -} - -/* Given a type, apply default promotions wrt unnamed function - arguments and return the new type. */ - -tree -c_type_promotes_to (tree type) -{ - tree ret = NULL_TREE; - - if (TYPE_MAIN_VARIANT (type) == float_type_node) - ret = double_type_node; - else if (c_promoting_integer_type_p (type)) - { - /* Preserve unsignedness if not really getting any wider. */ - if (TYPE_UNSIGNED (type) - && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))) - ret = unsigned_type_node; - else - ret = integer_type_node; - } - - if (ret != NULL_TREE) - return (TYPE_ATOMIC (type) - ? c_build_qualified_type (ret, TYPE_QUAL_ATOMIC) - : ret); - - return type; -} - -/* Return true if between two named address spaces, whether there is a superset - named address space that encompasses both address spaces. If there is a - superset, return which address space is the superset. */ - -static bool -addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common) -{ - if (as1 == as2) - { - *common = as1; - return true; - } - else if (targetm.addr_space.subset_p (as1, as2)) - { - *common = as2; - return true; - } - else if (targetm.addr_space.subset_p (as2, as1)) - { - *common = as1; - return true; - } - else - return false; -} - -/* Return a variant of TYPE which has all the type qualifiers of LIKE - as well as those of TYPE. */ - -static tree -qualify_type (tree type, tree like) -{ - addr_space_t as_type = TYPE_ADDR_SPACE (type); - addr_space_t as_like = TYPE_ADDR_SPACE (like); - addr_space_t as_common; - - /* If the two named address spaces are different, determine the common - superset address space. If there isn't one, raise an error. */ - if (!addr_space_superset (as_type, as_like, &as_common)) - { - as_common = as_type; - error ("%qT and %qT are in disjoint named address spaces", - type, like); - } - - return c_build_qualified_type (type, - TYPE_QUALS_NO_ADDR_SPACE (type) - | TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (like) - | ENCODE_QUAL_ADDR_SPACE (as_common)); -} - -/* Return true iff the given tree T is a variable length array. */ - -bool -c_vla_type_p (const_tree t) -{ - if (TREE_CODE (t) == ARRAY_TYPE - && C_TYPE_VARIABLE_SIZE (t)) - return true; - return false; -} - -/* If NTYPE is a type of a non-variadic function with a prototype - and OTYPE is a type of a function without a prototype and ATTRS - contains attribute format, diagnosess and removes it from ATTRS. - Returns the result of build_type_attribute_variant of NTYPE and - the (possibly) modified ATTRS. */ - -static tree -build_functype_attribute_variant (tree ntype, tree otype, tree attrs) -{ - if (!prototype_p (otype) - && prototype_p (ntype) - && lookup_attribute ("format", attrs)) - { - warning_at (input_location, OPT_Wattributes, - "%qs attribute cannot be applied to a function that " - "does not take variable arguments", "format"); - attrs = remove_attribute ("format", attrs); - } - return build_type_attribute_variant (ntype, attrs); - -} -/* Return the composite type of two compatible types. - - We assume that comptypes has already been done and returned - nonzero; if that isn't so, this may crash. In particular, we - assume that qualifiers match. */ - -tree -composite_type (tree t1, tree t2) -{ - enum tree_code code1; - enum tree_code code2; - tree attributes; - - /* Save time if the two types are the same. */ - - if (t1 == t2) return t1; - - /* If one type is nonsense, use the other. */ - if (t1 == error_mark_node) - return t2; - if (t2 == error_mark_node) - return t1; - - code1 = TREE_CODE (t1); - code2 = TREE_CODE (t2); - - /* Merge the attributes. */ - attributes = targetm.merge_type_attributes (t1, t2); - - /* If one is an enumerated type and the other is the compatible - integer type, the composite type might be either of the two - (DR#013 question 3). For consistency, use the enumerated type as - the composite type. */ - - if (code1 == ENUMERAL_TYPE && code2 == INTEGER_TYPE) - return t1; - if (code2 == ENUMERAL_TYPE && code1 == INTEGER_TYPE) - return t2; - - gcc_assert (code1 == code2); - - switch (code1) - { - case POINTER_TYPE: - /* For two pointers, do this recursively on the target type. */ - { - tree pointed_to_1 = TREE_TYPE (t1); - tree pointed_to_2 = TREE_TYPE (t2); - tree target = composite_type (pointed_to_1, pointed_to_2); - t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false); - t1 = build_type_attribute_variant (t1, attributes); - return qualify_type (t1, t2); - } - - case ARRAY_TYPE: - { - tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2)); - int quals; - tree unqual_elt; - tree d1 = TYPE_DOMAIN (t1); - tree d2 = TYPE_DOMAIN (t2); - bool d1_variable, d2_variable; - bool d1_zero, d2_zero; - bool t1_complete, t2_complete; - - /* We should not have any type quals on arrays at all. */ - gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1) - && !TYPE_QUALS_NO_ADDR_SPACE (t2)); - - t1_complete = COMPLETE_TYPE_P (t1); - t2_complete = COMPLETE_TYPE_P (t2); - - d1_zero = d1 == NULL_TREE || !TYPE_MAX_VALUE (d1); - d2_zero = d2 == NULL_TREE || !TYPE_MAX_VALUE (d2); - - d1_variable = (!d1_zero - && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST - || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST)); - d2_variable = (!d2_zero - && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST - || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); - d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1)); - d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2)); - - /* Save space: see if the result is identical to one of the args. */ - if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1) - && (d2_variable || d2_zero || !d1_variable)) - return build_type_attribute_variant (t1, attributes); - if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2) - && (d1_variable || d1_zero || !d2_variable)) - return build_type_attribute_variant (t2, attributes); - - if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) - return build_type_attribute_variant (t1, attributes); - if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) - return build_type_attribute_variant (t2, attributes); - - /* Merge the element types, and have a size if either arg has - one. We may have qualifiers on the element types. To set - up TYPE_MAIN_VARIANT correctly, we need to form the - composite of the unqualified types and add the qualifiers - back at the end. */ - quals = TYPE_QUALS (strip_array_types (elt)); - unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); - t1 = build_array_type (unqual_elt, - TYPE_DOMAIN ((TYPE_DOMAIN (t1) - && (d2_variable - || d2_zero - || !d1_variable)) - ? t1 - : t2)); - /* Ensure a composite type involving a zero-length array type - is a zero-length type not an incomplete type. */ - if (d1_zero && d2_zero - && (t1_complete || t2_complete) - && !COMPLETE_TYPE_P (t1)) - { - TYPE_SIZE (t1) = bitsize_zero_node; - TYPE_SIZE_UNIT (t1) = size_zero_node; - } - t1 = c_build_qualified_type (t1, quals); - return build_type_attribute_variant (t1, attributes); - } - - case ENUMERAL_TYPE: - case RECORD_TYPE: - case UNION_TYPE: - if (attributes != NULL) - { - /* Try harder not to create a new aggregate type. */ - if (attribute_list_equal (TYPE_ATTRIBUTES (t1), attributes)) - return t1; - if (attribute_list_equal (TYPE_ATTRIBUTES (t2), attributes)) - return t2; - } - return build_type_attribute_variant (t1, attributes); - - case FUNCTION_TYPE: - /* Function types: prefer the one that specified arg types. - If both do, merge the arg types. Also merge the return types. */ - { - tree valtype = composite_type (TREE_TYPE (t1), TREE_TYPE (t2)); - tree p1 = TYPE_ARG_TYPES (t1); - tree p2 = TYPE_ARG_TYPES (t2); - int len; - tree newargs, n; - int i; - - /* Save space: see if the result is identical to one of the args. */ - if (valtype == TREE_TYPE (t1) && !TYPE_ARG_TYPES (t2)) - return build_functype_attribute_variant (t1, t2, attributes); - if (valtype == TREE_TYPE (t2) && !TYPE_ARG_TYPES (t1)) - return build_functype_attribute_variant (t2, t1, attributes); - - /* Simple way if one arg fails to specify argument types. */ - if (TYPE_ARG_TYPES (t1) == NULL_TREE) - { - t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2)); - t1 = build_type_attribute_variant (t1, attributes); - return qualify_type (t1, t2); - } - if (TYPE_ARG_TYPES (t2) == NULL_TREE) - { - t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1)); - t1 = build_type_attribute_variant (t1, attributes); - return qualify_type (t1, t2); - } - - /* If both args specify argument types, we must merge the two - lists, argument by argument. */ - - for (len = 0, newargs = p1; - newargs && newargs != void_list_node; - len++, newargs = TREE_CHAIN (newargs)) - ; - - for (i = 0; i < len; i++) - newargs = tree_cons (NULL_TREE, NULL_TREE, newargs); - - n = newargs; - - for (; p1 && p1 != void_list_node; - p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n)) - { - /* A null type means arg type is not specified. - Take whatever the other function type has. */ - if (TREE_VALUE (p1) == NULL_TREE) - { - TREE_VALUE (n) = TREE_VALUE (p2); - goto parm_done; - } - if (TREE_VALUE (p2) == NULL_TREE) - { - TREE_VALUE (n) = TREE_VALUE (p1); - goto parm_done; - } - - /* Given wait (union {union wait *u; int *i} *) - and wait (union wait *), - prefer union wait * as type of parm. */ - if (TREE_CODE (TREE_VALUE (p1)) == UNION_TYPE - && TREE_VALUE (p1) != TREE_VALUE (p2)) - { - tree memb; - tree mv2 = TREE_VALUE (p2); - if (mv2 && mv2 != error_mark_node - && TREE_CODE (mv2) != ARRAY_TYPE) - mv2 = TYPE_MAIN_VARIANT (mv2); - for (memb = TYPE_FIELDS (TREE_VALUE (p1)); - memb; memb = DECL_CHAIN (memb)) - { - tree mv3 = TREE_TYPE (memb); - if (mv3 && mv3 != error_mark_node - && TREE_CODE (mv3) != ARRAY_TYPE) - mv3 = TYPE_MAIN_VARIANT (mv3); - if (comptypes (mv3, mv2)) - { - TREE_VALUE (n) = composite_type (TREE_TYPE (memb), - TREE_VALUE (p2)); - pedwarn (input_location, OPT_Wpedantic, - "function types not truly compatible in ISO C"); - goto parm_done; - } - } - } - if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE - && TREE_VALUE (p2) != TREE_VALUE (p1)) - { - tree memb; - tree mv1 = TREE_VALUE (p1); - if (mv1 && mv1 != error_mark_node - && TREE_CODE (mv1) != ARRAY_TYPE) - mv1 = TYPE_MAIN_VARIANT (mv1); - for (memb = TYPE_FIELDS (TREE_VALUE (p2)); - memb; memb = DECL_CHAIN (memb)) - { - tree mv3 = TREE_TYPE (memb); - if (mv3 && mv3 != error_mark_node - && TREE_CODE (mv3) != ARRAY_TYPE) - mv3 = TYPE_MAIN_VARIANT (mv3); - if (comptypes (mv3, mv1)) - { - TREE_VALUE (n) = composite_type (TREE_TYPE (memb), - TREE_VALUE (p1)); - pedwarn (input_location, OPT_Wpedantic, - "function types not truly compatible in ISO C"); - goto parm_done; - } - } - } - TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2)); - parm_done: ; - } - - t1 = build_function_type (valtype, newargs); - t1 = qualify_type (t1, t2); - } - /* FALLTHRU */ - - default: - return build_type_attribute_variant (t1, attributes); - } - -} - -/* Return the type of a conditional expression between pointers to - possibly differently qualified versions of compatible types. - - We assume that comp_target_types has already been done and returned - nonzero; if that isn't so, this may crash. */ - -static tree -common_pointer_type (tree t1, tree t2) -{ - tree attributes; - tree pointed_to_1, mv1; - tree pointed_to_2, mv2; - tree target; - unsigned target_quals; - addr_space_t as1, as2, as_common; - int quals1, quals2; - - /* Save time if the two types are the same. */ - - if (t1 == t2) return t1; - - /* If one type is nonsense, use the other. */ - if (t1 == error_mark_node) - return t2; - if (t2 == error_mark_node) - return t1; - - gcc_assert (TREE_CODE (t1) == POINTER_TYPE - && TREE_CODE (t2) == POINTER_TYPE); - - /* Merge the attributes. */ - attributes = targetm.merge_type_attributes (t1, t2); - - /* Find the composite type of the target types, and combine the - qualifiers of the two types' targets. Do not lose qualifiers on - array element types by taking the TYPE_MAIN_VARIANT. */ - mv1 = pointed_to_1 = TREE_TYPE (t1); - mv2 = pointed_to_2 = TREE_TYPE (t2); - if (TREE_CODE (mv1) != ARRAY_TYPE) - mv1 = TYPE_MAIN_VARIANT (pointed_to_1); - if (TREE_CODE (mv2) != ARRAY_TYPE) - mv2 = TYPE_MAIN_VARIANT (pointed_to_2); - target = composite_type (mv1, mv2); - - /* Strip array types to get correct qualifier for pointers to arrays */ - quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1)); - quals2 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_2)); - - /* For function types do not merge const qualifiers, but drop them - if used inconsistently. The middle-end uses these to mark const - and noreturn functions. */ - if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE) - target_quals = (quals1 & quals2); - else - target_quals = (quals1 | quals2); - - /* If the two named address spaces are different, determine the common - superset address space. This is guaranteed to exist due to the - assumption that comp_target_type returned non-zero. */ - as1 = TYPE_ADDR_SPACE (pointed_to_1); - as2 = TYPE_ADDR_SPACE (pointed_to_2); - if (!addr_space_superset (as1, as2, &as_common)) - gcc_unreachable (); - - target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common); - - t1 = build_pointer_type (c_build_qualified_type (target, target_quals)); - return build_type_attribute_variant (t1, attributes); -} - -/* Return the common type for two arithmetic types under the usual - arithmetic conversions. The default conversions have already been - applied, and enumerated types converted to their compatible integer - types. The resulting type is unqualified and has no attributes. - - This is the type for the result of most arithmetic operations - if the operands have the given two types. */ - -static tree -c_common_type (tree t1, tree t2) -{ - enum tree_code code1; - enum tree_code code2; - - /* If one type is nonsense, use the other. */ - if (t1 == error_mark_node) - return t2; - if (t2 == error_mark_node) - return t1; - - if (TYPE_QUALS (t1) != TYPE_UNQUALIFIED) - t1 = TYPE_MAIN_VARIANT (t1); - - if (TYPE_QUALS (t2) != TYPE_UNQUALIFIED) - t2 = TYPE_MAIN_VARIANT (t2); - - if (TYPE_ATTRIBUTES (t1) != NULL_TREE) - { - tree attrs = affects_type_identity_attributes (TYPE_ATTRIBUTES (t1)); - t1 = build_type_attribute_variant (t1, attrs); - } - - if (TYPE_ATTRIBUTES (t2) != NULL_TREE) - { - tree attrs = affects_type_identity_attributes (TYPE_ATTRIBUTES (t2)); - t2 = build_type_attribute_variant (t2, attrs); - } - - /* Save time if the two types are the same. */ - - if (t1 == t2) return t1; - - code1 = TREE_CODE (t1); - code2 = TREE_CODE (t2); - - gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE - || code1 == FIXED_POINT_TYPE || code1 == REAL_TYPE - || code1 == INTEGER_TYPE); - gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE - || code2 == FIXED_POINT_TYPE || code2 == REAL_TYPE - || code2 == INTEGER_TYPE); - - /* When one operand is a decimal float type, the other operand cannot be - a generic float type or a complex type. We also disallow vector types - here. */ - if ((DECIMAL_FLOAT_TYPE_P (t1) || DECIMAL_FLOAT_TYPE_P (t2)) - && !(DECIMAL_FLOAT_TYPE_P (t1) && DECIMAL_FLOAT_TYPE_P (t2))) - { - if (code1 == VECTOR_TYPE || code2 == VECTOR_TYPE) - { - error ("cannot mix operands of decimal floating and vector types"); - return error_mark_node; - } - if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE) - { - error ("cannot mix operands of decimal floating and complex types"); - return error_mark_node; - } - if (code1 == REAL_TYPE && code2 == REAL_TYPE) - { - error ("cannot mix operands of decimal floating " - "and other floating types"); - return error_mark_node; - } - } - - /* If one type is a vector type, return that type. (How the usual - arithmetic conversions apply to the vector types extension is not - precisely specified.) */ - if (code1 == VECTOR_TYPE) - return t1; - - if (code2 == VECTOR_TYPE) - return t2; - - /* If one type is complex, form the common type of the non-complex - components, then make that complex. Use T1 or T2 if it is the - required type. */ - if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE) - { - tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1; - tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2; - tree subtype = c_common_type (subtype1, subtype2); - - if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype) - return t1; - else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype) - return t2; - else - return build_complex_type (subtype); - } - - /* If only one is real, use it as the result. */ - - if (code1 == REAL_TYPE && code2 != REAL_TYPE) - return t1; - - if (code2 == REAL_TYPE && code1 != REAL_TYPE) - return t2; - - /* If both are real and either are decimal floating point types, use - the decimal floating point type with the greater precision. */ - - if (code1 == REAL_TYPE && code2 == REAL_TYPE) - { - if (TYPE_MAIN_VARIANT (t1) == dfloat128_type_node - || TYPE_MAIN_VARIANT (t2) == dfloat128_type_node) - return dfloat128_type_node; - else if (TYPE_MAIN_VARIANT (t1) == dfloat64_type_node - || TYPE_MAIN_VARIANT (t2) == dfloat64_type_node) - return dfloat64_type_node; - else if (TYPE_MAIN_VARIANT (t1) == dfloat32_type_node - || TYPE_MAIN_VARIANT (t2) == dfloat32_type_node) - return dfloat32_type_node; - } - - /* Deal with fixed-point types. */ - if (code1 == FIXED_POINT_TYPE || code2 == FIXED_POINT_TYPE) - { - unsigned int unsignedp = 0, satp = 0; - scalar_mode m1, m2; - unsigned int fbit1, ibit1, fbit2, ibit2, max_fbit, max_ibit; - - m1 = SCALAR_TYPE_MODE (t1); - m2 = SCALAR_TYPE_MODE (t2); - - /* If one input type is saturating, the result type is saturating. */ - if (TYPE_SATURATING (t1) || TYPE_SATURATING (t2)) - satp = 1; - - /* If both fixed-point types are unsigned, the result type is unsigned. - When mixing fixed-point and integer types, follow the sign of the - fixed-point type. - Otherwise, the result type is signed. */ - if ((TYPE_UNSIGNED (t1) && TYPE_UNSIGNED (t2) - && code1 == FIXED_POINT_TYPE && code2 == FIXED_POINT_TYPE) - || (code1 == FIXED_POINT_TYPE && code2 != FIXED_POINT_TYPE - && TYPE_UNSIGNED (t1)) - || (code1 != FIXED_POINT_TYPE && code2 == FIXED_POINT_TYPE - && TYPE_UNSIGNED (t2))) - unsignedp = 1; - - /* The result type is signed. */ - if (unsignedp == 0) - { - /* If the input type is unsigned, we need to convert to the - signed type. */ - if (code1 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t1)) - { - enum mode_class mclass = (enum mode_class) 0; - if (GET_MODE_CLASS (m1) == MODE_UFRACT) - mclass = MODE_FRACT; - else if (GET_MODE_CLASS (m1) == MODE_UACCUM) - mclass = MODE_ACCUM; - else - gcc_unreachable (); - m1 = as_a - (mode_for_size (GET_MODE_PRECISION (m1), mclass, 0)); - } - if (code2 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t2)) - { - enum mode_class mclass = (enum mode_class) 0; - if (GET_MODE_CLASS (m2) == MODE_UFRACT) - mclass = MODE_FRACT; - else if (GET_MODE_CLASS (m2) == MODE_UACCUM) - mclass = MODE_ACCUM; - else - gcc_unreachable (); - m2 = as_a - (mode_for_size (GET_MODE_PRECISION (m2), mclass, 0)); - } - } - - if (code1 == FIXED_POINT_TYPE) - { - fbit1 = GET_MODE_FBIT (m1); - ibit1 = GET_MODE_IBIT (m1); - } - else - { - fbit1 = 0; - /* Signed integers need to subtract one sign bit. */ - ibit1 = TYPE_PRECISION (t1) - (!TYPE_UNSIGNED (t1)); - } - - if (code2 == FIXED_POINT_TYPE) - { - fbit2 = GET_MODE_FBIT (m2); - ibit2 = GET_MODE_IBIT (m2); - } - else - { - fbit2 = 0; - /* Signed integers need to subtract one sign bit. */ - ibit2 = TYPE_PRECISION (t2) - (!TYPE_UNSIGNED (t2)); - } - - max_ibit = ibit1 >= ibit2 ? ibit1 : ibit2; - max_fbit = fbit1 >= fbit2 ? fbit1 : fbit2; - return c_common_fixed_point_type_for_size (max_ibit, max_fbit, unsignedp, - satp); - } - - /* Both real or both integers; use the one with greater precision. */ - - if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) - return t1; - else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1)) - return t2; - - /* Same precision. Prefer long longs to longs to ints when the - same precision, following the C99 rules on integer type rank - (which are equivalent to the C90 rules for C90 types). */ - - if (TYPE_MAIN_VARIANT (t1) == long_long_unsigned_type_node - || TYPE_MAIN_VARIANT (t2) == long_long_unsigned_type_node) - return long_long_unsigned_type_node; - - if (TYPE_MAIN_VARIANT (t1) == long_long_integer_type_node - || TYPE_MAIN_VARIANT (t2) == long_long_integer_type_node) - { - if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2)) - return long_long_unsigned_type_node; - else - return long_long_integer_type_node; - } - - if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node - || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node) - return long_unsigned_type_node; - - if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node - || TYPE_MAIN_VARIANT (t2) == long_integer_type_node) - { - /* But preserve unsignedness from the other type, - since long cannot hold all the values of an unsigned int. */ - if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2)) - return long_unsigned_type_node; - else - return long_integer_type_node; - } - - /* For floating types of the same TYPE_PRECISION (which we here - assume means either the same set of values, or sets of values - neither a subset of the other, with behavior being undefined in - the latter case), follow the rules from TS 18661-3: prefer - interchange types _FloatN, then standard types long double, - double, float, then extended types _FloatNx. For extended types, - check them starting with _Float128x as that seems most consistent - in spirit with preferring long double to double; for interchange - types, also check in that order for consistency although it's not - possible for more than one of them to have the same - precision. */ - tree mv1 = TYPE_MAIN_VARIANT (t1); - tree mv2 = TYPE_MAIN_VARIANT (t2); - - for (int i = NUM_FLOATN_TYPES - 1; i >= 0; i--) - if (mv1 == FLOATN_TYPE_NODE (i) || mv2 == FLOATN_TYPE_NODE (i)) - return FLOATN_TYPE_NODE (i); - - /* Likewise, prefer long double to double even if same size. */ - if (mv1 == long_double_type_node || mv2 == long_double_type_node) - return long_double_type_node; - - /* Likewise, prefer double to float even if same size. - We got a couple of embedded targets with 32 bit doubles, and the - pdp11 might have 64 bit floats. */ - if (mv1 == double_type_node || mv2 == double_type_node) - return double_type_node; - - if (mv1 == float_type_node || mv2 == float_type_node) - return float_type_node; - - for (int i = NUM_FLOATNX_TYPES - 1; i >= 0; i--) - if (mv1 == FLOATNX_TYPE_NODE (i) || mv2 == FLOATNX_TYPE_NODE (i)) - return FLOATNX_TYPE_NODE (i); - - /* Otherwise prefer the unsigned one. */ - - if (TYPE_UNSIGNED (t1)) - return t1; - else - return t2; -} - -/* Wrapper around c_common_type that is used by c-common.c and other - front end optimizations that remove promotions. ENUMERAL_TYPEs - are allowed here and are converted to their compatible integer types. - BOOLEAN_TYPEs are allowed here and return either boolean_type_node or - preferably a non-Boolean type as the common type. */ -tree -common_type (tree t1, tree t2) -{ - if (TREE_CODE (t1) == ENUMERAL_TYPE) - t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1); - if (TREE_CODE (t2) == ENUMERAL_TYPE) - t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1); - - /* If both types are BOOLEAN_TYPE, then return boolean_type_node. */ - if (TREE_CODE (t1) == BOOLEAN_TYPE - && TREE_CODE (t2) == BOOLEAN_TYPE) - return boolean_type_node; - - /* If either type is BOOLEAN_TYPE, then return the other. */ - if (TREE_CODE (t1) == BOOLEAN_TYPE) - return t2; - if (TREE_CODE (t2) == BOOLEAN_TYPE) - return t1; - - return c_common_type (t1, t2); -} - -/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment - or various other operations. Return 2 if they are compatible - but a warning may be needed if you use them together. */ - -int -comptypes (tree type1, tree type2) -{ - const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; - int val; - - val = comptypes_internal (type1, type2, NULL, NULL); - free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); - - return val; -} - -/* Like comptypes, but if it returns non-zero because enum and int are - compatible, it sets *ENUM_AND_INT_P to true. */ - -static int -comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) -{ - const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; - int val; - - val = comptypes_internal (type1, type2, enum_and_int_p, NULL); - free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); - - return val; -} - -/* Like comptypes, but if it returns nonzero for different types, it - sets *DIFFERENT_TYPES_P to true. */ - -int -comptypes_check_different_types (tree type1, tree type2, - bool *different_types_p) -{ - const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; - int val; - - val = comptypes_internal (type1, type2, NULL, different_types_p); - free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); - - return val; -} - -/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment - or various other operations. Return 2 if they are compatible - but a warning may be needed if you use them together. If - ENUM_AND_INT_P is not NULL, and one type is an enum and the other a - compatible integer type, then this sets *ENUM_AND_INT_P to true; - *ENUM_AND_INT_P is never set to false. If DIFFERENT_TYPES_P is not - NULL, and the types are compatible but different enough not to be - permitted in C11 typedef redeclarations, then this sets - *DIFFERENT_TYPES_P to true; *DIFFERENT_TYPES_P is never set to - false, but may or may not be set if the types are incompatible. - This differs from comptypes, in that we don't free the seen - types. */ - -static int -comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, - bool *different_types_p) -{ - const_tree t1 = type1; - const_tree t2 = type2; - int attrval, val; - - /* Suppress errors caused by previously reported errors. */ - - if (t1 == t2 || !t1 || !t2 - || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK) - return 1; - - /* Enumerated types are compatible with integer types, but this is - not transitive: two enumerated types in the same translation unit - are compatible with each other only if they are the same type. */ - - if (TREE_CODE (t1) == ENUMERAL_TYPE - && COMPLETE_TYPE_P (t1) - && TREE_CODE (t2) != ENUMERAL_TYPE) - { - t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1)); - if (TREE_CODE (t2) != VOID_TYPE) - { - if (enum_and_int_p != NULL) - *enum_and_int_p = true; - if (different_types_p != NULL) - *different_types_p = true; - } - } - else if (TREE_CODE (t2) == ENUMERAL_TYPE - && COMPLETE_TYPE_P (t2) - && TREE_CODE (t1) != ENUMERAL_TYPE) - { - t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2)); - if (TREE_CODE (t1) != VOID_TYPE) - { - if (enum_and_int_p != NULL) - *enum_and_int_p = true; - if (different_types_p != NULL) - *different_types_p = true; - } - } - - if (t1 == t2) - return 1; - - /* Different classes of types can't be compatible. */ - - if (TREE_CODE (t1) != TREE_CODE (t2)) - return 0; - - /* Qualifiers must match. C99 6.7.3p9 */ - - if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) - return 0; - - /* Allow for two different type nodes which have essentially the same - definition. Note that we already checked for equality of the type - qualifiers (just above). */ - - if (TREE_CODE (t1) != ARRAY_TYPE - && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) - return 1; - - /* 1 if no need for warning yet, 2 if warning cause has been seen. */ - if (!(attrval = comp_type_attributes (t1, t2))) - return 0; - - /* 1 if no need for warning yet, 2 if warning cause has been seen. */ - val = 0; - - switch (TREE_CODE (t1)) - { - case INTEGER_TYPE: - case FIXED_POINT_TYPE: - case REAL_TYPE: - /* With these nodes, we can't determine type equivalence by - looking at what is stored in the nodes themselves, because - two nodes might have different TYPE_MAIN_VARIANTs but still - represent the same type. For example, wchar_t and int could - have the same properties (TYPE_PRECISION, TYPE_MIN_VALUE, - TYPE_MAX_VALUE, etc.), but have different TYPE_MAIN_VARIANTs - and are distinct types. On the other hand, int and the - following typedef - - typedef int INT __attribute((may_alias)); - - have identical properties, different TYPE_MAIN_VARIANTs, but - represent the same type. The canonical type system keeps - track of equivalence in this case, so we fall back on it. */ - return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2); - - case POINTER_TYPE: - /* Do not remove mode information. */ - if (TYPE_MODE (t1) != TYPE_MODE (t2)) - break; - val = (TREE_TYPE (t1) == TREE_TYPE (t2) - ? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), - enum_and_int_p, different_types_p)); - break; - - case FUNCTION_TYPE: - val = function_types_compatible_p (t1, t2, enum_and_int_p, - different_types_p); - break; - - case ARRAY_TYPE: - { - tree d1 = TYPE_DOMAIN (t1); - tree d2 = TYPE_DOMAIN (t2); - bool d1_variable, d2_variable; - bool d1_zero, d2_zero; - val = 1; - - /* Target types must match incl. qualifiers. */ - if (TREE_TYPE (t1) != TREE_TYPE (t2) - && (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), - enum_and_int_p, - different_types_p)) == 0) - return 0; - - if (different_types_p != NULL - && (d1 == NULL_TREE) != (d2 == NULL_TREE)) - *different_types_p = true; - /* Sizes must match unless one is missing or variable. */ - if (d1 == NULL_TREE || d2 == NULL_TREE || d1 == d2) - break; - - d1_zero = !TYPE_MAX_VALUE (d1); - d2_zero = !TYPE_MAX_VALUE (d2); - - d1_variable = (!d1_zero - && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST - || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST)); - d2_variable = (!d2_zero - && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST - || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); - d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1)); - d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2)); - - if (different_types_p != NULL - && d1_variable != d2_variable) - *different_types_p = true; - if (d1_variable || d2_variable) - break; - if (d1_zero && d2_zero) - break; - if (d1_zero || d2_zero - || !tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2)) - || !tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2))) - val = 0; - - break; - } - - case ENUMERAL_TYPE: - case RECORD_TYPE: - case UNION_TYPE: - if (val != 1 && !same_translation_unit_p (t1, t2)) - { - tree a1 = TYPE_ATTRIBUTES (t1); - tree a2 = TYPE_ATTRIBUTES (t2); - - if (! attribute_list_contained (a1, a2) - && ! attribute_list_contained (a2, a1)) - break; - - if (attrval != 2) - return tagged_types_tu_compatible_p (t1, t2, enum_and_int_p, - different_types_p); - val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p, - different_types_p); - } - break; - - case VECTOR_TYPE: - val = (known_eq (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2)) - && comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), - enum_and_int_p, different_types_p)); - break; - - default: - break; - } - return attrval == 2 && val == 1 ? 2 : val; -} - -/* Return 1 if TTL and TTR are pointers to types that are equivalent, ignoring - their qualifiers, except for named address spaces. If the pointers point to - different named addresses, then we must determine if one address space is a - subset of the other. */ - -static int -comp_target_types (location_t location, tree ttl, tree ttr) -{ - int val; - int val_ped; - tree mvl = TREE_TYPE (ttl); - tree mvr = TREE_TYPE (ttr); - addr_space_t asl = TYPE_ADDR_SPACE (mvl); - addr_space_t asr = TYPE_ADDR_SPACE (mvr); - addr_space_t as_common; - bool enum_and_int_p; - - /* Fail if pointers point to incompatible address spaces. */ - if (!addr_space_superset (asl, asr, &as_common)) - return 0; - - /* For pedantic record result of comptypes on arrays before losing - qualifiers on the element type below. */ - val_ped = 1; - - if (TREE_CODE (mvl) == ARRAY_TYPE - && TREE_CODE (mvr) == ARRAY_TYPE) - val_ped = comptypes (mvl, mvr); - - /* Qualifiers on element types of array types that are - pointer targets are lost by taking their TYPE_MAIN_VARIANT. */ - - mvl = (TYPE_ATOMIC (strip_array_types (mvl)) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mvl)); - - mvr = (TYPE_ATOMIC (strip_array_types (mvr)) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mvr)); - - enum_and_int_p = false; - val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p); - - if (val == 1 && val_ped != 1) - pedwarn_c11 (location, OPT_Wpedantic, "invalid use of pointers to arrays with different qualifiers " - "in ISO C before C2X"); - - if (val == 2) - pedwarn (location, OPT_Wpedantic, "types are not quite compatible"); - - if (val == 1 && enum_and_int_p && warn_cxx_compat) - warning_at (location, OPT_Wc___compat, - "pointer target types incompatible in C++"); - - return val; -} - -/* Subroutines of `comptypes'. */ - -/* Determine whether two trees derive from the same translation unit. - If the CONTEXT chain ends in a null, that tree's context is still - being parsed, so if two trees have context chains ending in null, - they're in the same translation unit. */ - -bool -same_translation_unit_p (const_tree t1, const_tree t2) -{ - while (t1 && TREE_CODE (t1) != TRANSLATION_UNIT_DECL) - switch (TREE_CODE_CLASS (TREE_CODE (t1))) - { - case tcc_declaration: - t1 = DECL_CONTEXT (t1); break; - case tcc_type: - t1 = TYPE_CONTEXT (t1); break; - case tcc_exceptional: - t1 = BLOCK_SUPERCONTEXT (t1); break; /* assume block */ - default: gcc_unreachable (); - } - - while (t2 && TREE_CODE (t2) != TRANSLATION_UNIT_DECL) - switch (TREE_CODE_CLASS (TREE_CODE (t2))) - { - case tcc_declaration: - t2 = DECL_CONTEXT (t2); break; - case tcc_type: - t2 = TYPE_CONTEXT (t2); break; - case tcc_exceptional: - t2 = BLOCK_SUPERCONTEXT (t2); break; /* assume block */ - default: gcc_unreachable (); - } - - return t1 == t2; -} - -/* Allocate the seen two types, assuming that they are compatible. */ - -static struct tagged_tu_seen_cache * -alloc_tagged_tu_seen_cache (const_tree t1, const_tree t2) -{ - struct tagged_tu_seen_cache *tu = XNEW (struct tagged_tu_seen_cache); - tu->next = tagged_tu_seen_base; - tu->t1 = t1; - tu->t2 = t2; - - tagged_tu_seen_base = tu; - - /* The C standard says that two structures in different translation - units are compatible with each other only if the types of their - fields are compatible (among other things). We assume that they - are compatible until proven otherwise when building the cache. - An example where this can occur is: - struct a - { - struct a *next; - }; - If we are comparing this against a similar struct in another TU, - and did not assume they were compatible, we end up with an infinite - loop. */ - tu->val = 1; - return tu; -} - -/* Free the seen types until we get to TU_TIL. */ - -static void -free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til) -{ - const struct tagged_tu_seen_cache *tu = tagged_tu_seen_base; - while (tu != tu_til) - { - const struct tagged_tu_seen_cache *const tu1 - = (const struct tagged_tu_seen_cache *) tu; - tu = tu1->next; - XDELETE (CONST_CAST (struct tagged_tu_seen_cache *, tu1)); - } - tagged_tu_seen_base = tu_til; -} - -/* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are - compatible. If the two types are not the same (which has been - checked earlier), this can only happen when multiple translation - units are being compiled. See C99 6.2.7 paragraph 1 for the exact - rules. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in - comptypes_internal. */ - -static int -tagged_types_tu_compatible_p (const_tree t1, const_tree t2, - bool *enum_and_int_p, bool *different_types_p) -{ - tree s1, s2; - bool needs_warning = false; - - /* We have to verify that the tags of the types are the same. This - is harder than it looks because this may be a typedef, so we have - to go look at the original type. It may even be a typedef of a - typedef... - In the case of compiler-created builtin structs the TYPE_DECL - may be a dummy, with no DECL_ORIGINAL_TYPE. Don't fault. */ - while (TYPE_NAME (t1) - && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL - && DECL_ORIGINAL_TYPE (TYPE_NAME (t1))) - t1 = DECL_ORIGINAL_TYPE (TYPE_NAME (t1)); - - while (TYPE_NAME (t2) - && TREE_CODE (TYPE_NAME (t2)) == TYPE_DECL - && DECL_ORIGINAL_TYPE (TYPE_NAME (t2))) - t2 = DECL_ORIGINAL_TYPE (TYPE_NAME (t2)); - - /* C90 didn't have the requirement that the two tags be the same. */ - if (flag_isoc99 && TYPE_NAME (t1) != TYPE_NAME (t2)) - return 0; - - /* C90 didn't say what happened if one or both of the types were - incomplete; we choose to follow C99 rules here, which is that they - are compatible. */ - if (TYPE_SIZE (t1) == NULL - || TYPE_SIZE (t2) == NULL) - return 1; - - { - const struct tagged_tu_seen_cache * tts_i; - for (tts_i = tagged_tu_seen_base; tts_i != NULL; tts_i = tts_i->next) - if (tts_i->t1 == t1 && tts_i->t2 == t2) - return tts_i->val; - } - - switch (TREE_CODE (t1)) - { - case ENUMERAL_TYPE: - { - struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); - /* Speed up the case where the type values are in the same order. */ - tree tv1 = TYPE_VALUES (t1); - tree tv2 = TYPE_VALUES (t2); - - if (tv1 == tv2) - { - return 1; - } - - for (;tv1 && tv2; tv1 = TREE_CHAIN (tv1), tv2 = TREE_CHAIN (tv2)) - { - if (TREE_PURPOSE (tv1) != TREE_PURPOSE (tv2)) - break; - if (simple_cst_equal (TREE_VALUE (tv1), TREE_VALUE (tv2)) != 1) - { - tu->val = 0; - return 0; - } - } - - if (tv1 == NULL_TREE && tv2 == NULL_TREE) - { - return 1; - } - if (tv1 == NULL_TREE || tv2 == NULL_TREE) - { - tu->val = 0; - return 0; - } - - if (list_length (TYPE_VALUES (t1)) != list_length (TYPE_VALUES (t2))) - { - tu->val = 0; - return 0; - } - - for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1)) - { - s2 = purpose_member (TREE_PURPOSE (s1), TYPE_VALUES (t2)); - if (s2 == NULL - || simple_cst_equal (TREE_VALUE (s1), TREE_VALUE (s2)) != 1) - { - tu->val = 0; - return 0; - } - } - return 1; - } - - case UNION_TYPE: - { - struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); - if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2))) - { - tu->val = 0; - return 0; - } - - /* Speed up the common case where the fields are in the same order. */ - for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2; - s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2)) - { - int result; - - if (DECL_NAME (s1) != DECL_NAME (s2)) - break; - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), - enum_and_int_p, different_types_p); - - if (result != 1 && !DECL_NAME (s1)) - break; - if (result == 0) - { - tu->val = 0; - return 0; - } - if (result == 2) - needs_warning = true; - - if (TREE_CODE (s1) == FIELD_DECL - && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), - DECL_FIELD_BIT_OFFSET (s2)) != 1) - { - tu->val = 0; - return 0; - } - } - if (!s1 && !s2) - { - tu->val = needs_warning ? 2 : 1; - return tu->val; - } - - for (s1 = TYPE_FIELDS (t1); s1; s1 = DECL_CHAIN (s1)) - { - bool ok = false; - - for (s2 = TYPE_FIELDS (t2); s2; s2 = DECL_CHAIN (s2)) - if (DECL_NAME (s1) == DECL_NAME (s2)) - { - int result; - - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), - enum_and_int_p, - different_types_p); - - if (result != 1 && !DECL_NAME (s1)) - continue; - if (result == 0) - { - tu->val = 0; - return 0; - } - if (result == 2) - needs_warning = true; - - if (TREE_CODE (s1) == FIELD_DECL - && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), - DECL_FIELD_BIT_OFFSET (s2)) != 1) - break; - - ok = true; - break; - } - if (!ok) - { - tu->val = 0; - return 0; - } - } - tu->val = needs_warning ? 2 : 10; - return tu->val; - } - - case RECORD_TYPE: - { - struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); - - for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); - s1 && s2; - s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2)) - { - int result; - if (TREE_CODE (s1) != TREE_CODE (s2) - || DECL_NAME (s1) != DECL_NAME (s2)) - break; - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), - enum_and_int_p, different_types_p); - if (result == 0) - break; - if (result == 2) - needs_warning = true; - - if (TREE_CODE (s1) == FIELD_DECL - && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), - DECL_FIELD_BIT_OFFSET (s2)) != 1) - break; - } - if (s1 && s2) - tu->val = 0; - else - tu->val = needs_warning ? 2 : 1; - return tu->val; - } - - default: - gcc_unreachable (); - } -} - -/* Return 1 if two function types F1 and F2 are compatible. - If either type specifies no argument types, - the other must specify a fixed number of self-promoting arg types. - Otherwise, if one type specifies only the number of arguments, - the other must specify that number of self-promoting arg types. - Otherwise, the argument types must match. - ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in comptypes_internal. */ - -static int -function_types_compatible_p (const_tree f1, const_tree f2, - bool *enum_and_int_p, bool *different_types_p) -{ - tree args1, args2; - /* 1 if no need for warning yet, 2 if warning cause has been seen. */ - int val = 1; - int val1; - tree ret1, ret2; - - ret1 = TREE_TYPE (f1); - ret2 = TREE_TYPE (f2); - - /* 'volatile' qualifiers on a function's return type used to mean - the function is noreturn. */ - if (TYPE_VOLATILE (ret1) != TYPE_VOLATILE (ret2)) - pedwarn (input_location, 0, "function return types not compatible due to %"); - if (TYPE_VOLATILE (ret1)) - ret1 = build_qualified_type (TYPE_MAIN_VARIANT (ret1), - TYPE_QUALS (ret1) & ~TYPE_QUAL_VOLATILE); - if (TYPE_VOLATILE (ret2)) - ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2), - TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE); - val = comptypes_internal (ret1, ret2, enum_and_int_p, different_types_p); - if (val == 0) - return 0; - - args1 = TYPE_ARG_TYPES (f1); - args2 = TYPE_ARG_TYPES (f2); - - if (different_types_p != NULL - && (args1 == NULL_TREE) != (args2 == NULL_TREE)) - *different_types_p = true; - - /* An unspecified parmlist matches any specified parmlist - whose argument types don't need default promotions. */ - - if (args1 == NULL_TREE) - { - if (flag_isoc2x ? stdarg_p (f2) : !self_promoting_args_p (args2)) - return 0; - /* If one of these types comes from a non-prototype fn definition, - compare that with the other type's arglist. - If they don't match, ask for a warning (but no error). */ - if (TYPE_ACTUAL_ARG_TYPES (f1) - && type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1), - enum_and_int_p, different_types_p) != 1) - val = 2; - return val; - } - if (args2 == NULL_TREE) - { - if (flag_isoc2x ? stdarg_p (f1) : !self_promoting_args_p (args1)) - return 0; - if (TYPE_ACTUAL_ARG_TYPES (f2) - && type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2), - enum_and_int_p, different_types_p) != 1) - val = 2; - return val; - } - - /* Both types have argument lists: compare them and propagate results. */ - val1 = type_lists_compatible_p (args1, args2, enum_and_int_p, - different_types_p); - return val1 != 1 ? val1 : val; -} - -/* Check two lists of types for compatibility, returning 0 for - incompatible, 1 for compatible, or 2 for compatible with - warning. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in - comptypes_internal. */ - -static int -type_lists_compatible_p (const_tree args1, const_tree args2, - bool *enum_and_int_p, bool *different_types_p) -{ - /* 1 if no need for warning yet, 2 if warning cause has been seen. */ - int val = 1; - int newval = 0; - - while (1) - { - tree a1, mv1, a2, mv2; - if (args1 == NULL_TREE && args2 == NULL_TREE) - return val; - /* If one list is shorter than the other, - they fail to match. */ - if (args1 == NULL_TREE || args2 == NULL_TREE) - return 0; - mv1 = a1 = TREE_VALUE (args1); - mv2 = a2 = TREE_VALUE (args2); - if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE) - mv1 = (TYPE_ATOMIC (mv1) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv1), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mv1)); - if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE) - mv2 = (TYPE_ATOMIC (mv2) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv2), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mv2)); - /* A null pointer instead of a type - means there is supposed to be an argument - but nothing is specified about what type it has. - So match anything that self-promotes. */ - if (different_types_p != NULL - && (a1 == NULL_TREE) != (a2 == NULL_TREE)) - *different_types_p = true; - if (a1 == NULL_TREE) - { - if (c_type_promotes_to (a2) != a2) - return 0; - } - else if (a2 == NULL_TREE) - { - if (c_type_promotes_to (a1) != a1) - return 0; - } - /* If one of the lists has an error marker, ignore this arg. */ - else if (TREE_CODE (a1) == ERROR_MARK - || TREE_CODE (a2) == ERROR_MARK) - ; - else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p, - different_types_p))) - { - if (different_types_p != NULL) - *different_types_p = true; - /* Allow wait (union {union wait *u; int *i} *) - and wait (union wait *) to be compatible. */ - if (TREE_CODE (a1) == UNION_TYPE - && (TYPE_NAME (a1) == NULL_TREE - || TYPE_TRANSPARENT_AGGR (a1)) - && TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST - && tree_int_cst_equal (TYPE_SIZE (a1), - TYPE_SIZE (a2))) - { - tree memb; - for (memb = TYPE_FIELDS (a1); - memb; memb = DECL_CHAIN (memb)) - { - tree mv3 = TREE_TYPE (memb); - if (mv3 && mv3 != error_mark_node - && TREE_CODE (mv3) != ARRAY_TYPE) - mv3 = (TYPE_ATOMIC (mv3) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mv3)); - if (comptypes_internal (mv3, mv2, enum_and_int_p, - different_types_p)) - break; - } - if (memb == NULL_TREE) - return 0; - } - else if (TREE_CODE (a2) == UNION_TYPE - && (TYPE_NAME (a2) == NULL_TREE - || TYPE_TRANSPARENT_AGGR (a2)) - && TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST - && tree_int_cst_equal (TYPE_SIZE (a2), - TYPE_SIZE (a1))) - { - tree memb; - for (memb = TYPE_FIELDS (a2); - memb; memb = DECL_CHAIN (memb)) - { - tree mv3 = TREE_TYPE (memb); - if (mv3 && mv3 != error_mark_node - && TREE_CODE (mv3) != ARRAY_TYPE) - mv3 = (TYPE_ATOMIC (mv3) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mv3)); - if (comptypes_internal (mv3, mv1, enum_and_int_p, - different_types_p)) - break; - } - if (memb == NULL_TREE) - return 0; - } - else - return 0; - } - - /* comptypes said ok, but record if it said to warn. */ - if (newval > val) - val = newval; - - args1 = TREE_CHAIN (args1); - args2 = TREE_CHAIN (args2); - } -} - -/* Compute the size to increment a pointer by. When a function type or void - type or incomplete type is passed, size_one_node is returned. - This function does not emit any diagnostics; the caller is responsible - for that. */ - -static tree -c_size_in_bytes (const_tree type) -{ - enum tree_code code = TREE_CODE (type); - - if (code == FUNCTION_TYPE || code == VOID_TYPE || code == ERROR_MARK - || !COMPLETE_TYPE_P (type)) - return size_one_node; - - /* Convert in case a char is more than one unit. */ - return size_binop_loc (input_location, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type), - size_int (TYPE_PRECISION (char_type_node) - / BITS_PER_UNIT)); -} - -/* Return either DECL or its known constant value (if it has one). */ - -tree -decl_constant_value_1 (tree decl, bool in_init) -{ - if (/* Note that DECL_INITIAL isn't valid for a PARM_DECL. */ - TREE_CODE (decl) != PARM_DECL - && !TREE_THIS_VOLATILE (decl) - && TREE_READONLY (decl) - && DECL_INITIAL (decl) != NULL_TREE - && !error_operand_p (DECL_INITIAL (decl)) - /* This is invalid if initial value is not constant. - If it has either a function call, a memory reference, - or a variable, then re-evaluating it could give different results. */ - && TREE_CONSTANT (DECL_INITIAL (decl)) - /* Check for cases where this is sub-optimal, even though valid. */ - && (in_init || TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR)) - return DECL_INITIAL (decl); - return decl; -} - -/* Return either DECL or its known constant value (if it has one). - Like the above, but always return decl outside of functions. */ - -tree -decl_constant_value (tree decl) -{ - /* Don't change a variable array bound or initial value to a constant - in a place where a variable is invalid. */ - return current_function_decl ? decl_constant_value_1 (decl, false) : decl; -} - -/* Convert the array expression EXP to a pointer. */ -static tree -array_to_pointer_conversion (location_t loc, tree exp) -{ - tree orig_exp = exp; - tree type = TREE_TYPE (exp); - tree adr; - tree restype = TREE_TYPE (type); - tree ptrtype; - - gcc_assert (TREE_CODE (type) == ARRAY_TYPE); - - STRIP_TYPE_NOPS (exp); - - copy_warning (exp, orig_exp); - - ptrtype = build_pointer_type (restype); - - if (INDIRECT_REF_P (exp)) - return convert (ptrtype, TREE_OPERAND (exp, 0)); - - /* In C++ array compound literals are temporary objects unless they are - const or appear in namespace scope, so they are destroyed too soon - to use them for much of anything (c++/53220). */ - if (warn_cxx_compat && TREE_CODE (exp) == COMPOUND_LITERAL_EXPR) - { - tree decl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); - if (!TREE_READONLY (decl) && !TREE_STATIC (decl)) - warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, - "converting an array compound literal to a pointer " - "is ill-formed in C++"); - } - - adr = build_unary_op (loc, ADDR_EXPR, exp, true); - return convert (ptrtype, adr); -} - -/* Convert the function expression EXP to a pointer. */ -static tree -function_to_pointer_conversion (location_t loc, tree exp) -{ - tree orig_exp = exp; - - gcc_assert (TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE); - - STRIP_TYPE_NOPS (exp); - - copy_warning (exp, orig_exp); - - return build_unary_op (loc, ADDR_EXPR, exp, false); -} - -/* Mark EXP as read, not just set, for set but not used -Wunused - warning purposes. */ - -void -mark_exp_read (tree exp) -{ - switch (TREE_CODE (exp)) - { - case VAR_DECL: - case PARM_DECL: - DECL_READ_P (exp) = 1; - break; - case ARRAY_REF: - case COMPONENT_REF: - case MODIFY_EXPR: - case REALPART_EXPR: - case IMAGPART_EXPR: - CASE_CONVERT: - case ADDR_EXPR: - case VIEW_CONVERT_EXPR: - mark_exp_read (TREE_OPERAND (exp, 0)); - break; - case COMPOUND_EXPR: - /* Pattern match what build_atomic_assign produces with modifycode - NOP_EXPR. */ - if (VAR_P (TREE_OPERAND (exp, 1)) - && DECL_ARTIFICIAL (TREE_OPERAND (exp, 1)) - && TREE_CODE (TREE_OPERAND (exp, 0)) == COMPOUND_EXPR) - { - tree t1 = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); - tree t2 = TREE_OPERAND (TREE_OPERAND (exp, 0), 1); - if (TREE_CODE (t1) == TARGET_EXPR - && TARGET_EXPR_SLOT (t1) == TREE_OPERAND (exp, 1) - && TREE_CODE (t2) == CALL_EXPR) - { - tree fndecl = get_callee_fndecl (t2); - tree arg = NULL_TREE; - if (fndecl - && TREE_CODE (fndecl) == FUNCTION_DECL - && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL) - && call_expr_nargs (t2) >= 2) - switch (DECL_FUNCTION_CODE (fndecl)) - { - case BUILT_IN_ATOMIC_STORE: - arg = CALL_EXPR_ARG (t2, 1); - break; - case BUILT_IN_ATOMIC_STORE_1: - case BUILT_IN_ATOMIC_STORE_2: - case BUILT_IN_ATOMIC_STORE_4: - case BUILT_IN_ATOMIC_STORE_8: - case BUILT_IN_ATOMIC_STORE_16: - arg = CALL_EXPR_ARG (t2, 0); - break; - default: - break; - } - if (arg) - { - STRIP_NOPS (arg); - if (TREE_CODE (arg) == ADDR_EXPR - && DECL_P (TREE_OPERAND (arg, 0)) - && TYPE_ATOMIC (TREE_TYPE (TREE_OPERAND (arg, 0)))) - mark_exp_read (TREE_OPERAND (arg, 0)); - } - } - } - /* FALLTHRU */ - case C_MAYBE_CONST_EXPR: - mark_exp_read (TREE_OPERAND (exp, 1)); - break; - default: - break; - } -} - -/* Perform the default conversion of arrays and functions to pointers. - Return the result of converting EXP. For any other expression, just - return EXP. - - LOC is the location of the expression. */ - -struct c_expr -default_function_array_conversion (location_t loc, struct c_expr exp) -{ - tree orig_exp = exp.value; - tree type = TREE_TYPE (exp.value); - enum tree_code code = TREE_CODE (type); - - switch (code) - { - case ARRAY_TYPE: - { - bool not_lvalue = false; - bool lvalue_array_p; - - while ((TREE_CODE (exp.value) == NON_LVALUE_EXPR - || CONVERT_EXPR_P (exp.value)) - && TREE_TYPE (TREE_OPERAND (exp.value, 0)) == type) - { - if (TREE_CODE (exp.value) == NON_LVALUE_EXPR) - not_lvalue = true; - exp.value = TREE_OPERAND (exp.value, 0); - } - - copy_warning (exp.value, orig_exp); - - lvalue_array_p = !not_lvalue && lvalue_p (exp.value); - if (!flag_isoc99 && !lvalue_array_p) - { - /* Before C99, non-lvalue arrays do not decay to pointers. - Normally, using such an array would be invalid; but it can - be used correctly inside sizeof or as a statement expression. - Thus, do not give an error here; an error will result later. */ - return exp; - } - - exp.value = array_to_pointer_conversion (loc, exp.value); - } - break; - case FUNCTION_TYPE: - exp.value = function_to_pointer_conversion (loc, exp.value); - break; - default: - break; - } - - return exp; -} - -struct c_expr -default_function_array_read_conversion (location_t loc, struct c_expr exp) -{ - mark_exp_read (exp.value); - return default_function_array_conversion (loc, exp); -} - -/* Return whether EXPR should be treated as an atomic lvalue for the - purposes of load and store handling. */ - -static bool -really_atomic_lvalue (tree expr) -{ - if (error_operand_p (expr)) - return false; - if (!TYPE_ATOMIC (TREE_TYPE (expr))) - return false; - if (!lvalue_p (expr)) - return false; - - /* Ignore _Atomic on register variables, since their addresses can't - be taken so (a) atomicity is irrelevant and (b) the normal atomic - sequences wouldn't work. Ignore _Atomic on structures containing - bit-fields, since accessing elements of atomic structures or - unions is undefined behavior (C11 6.5.2.3#5), but it's unclear if - it's undefined at translation time or execution time, and the - normal atomic sequences again wouldn't work. */ - while (handled_component_p (expr)) - { - if (TREE_CODE (expr) == COMPONENT_REF - && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1))) - return false; - expr = TREE_OPERAND (expr, 0); - } - if (DECL_P (expr) && C_DECL_REGISTER (expr)) - return false; - return true; -} - -/* Convert expression EXP (location LOC) from lvalue to rvalue, - including converting functions and arrays to pointers if CONVERT_P. - If READ_P, also mark the expression as having been read. */ - -struct c_expr -convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, - bool convert_p, bool read_p) -{ - if (read_p) - mark_exp_read (exp.value); - if (convert_p) - exp = default_function_array_conversion (loc, exp); - if (!VOID_TYPE_P (TREE_TYPE (exp.value))) - exp.value = require_complete_type (loc, exp.value); - if (really_atomic_lvalue (exp.value)) - { - vec *params; - tree nonatomic_type, tmp, tmp_addr, fndecl, func_call; - tree expr_type = TREE_TYPE (exp.value); - tree expr_addr = build_unary_op (loc, ADDR_EXPR, exp.value, false); - tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); - - gcc_assert (TYPE_ATOMIC (expr_type)); - - /* Expansion of a generic atomic load may require an addition - element, so allocate enough to prevent a resize. */ - vec_alloc (params, 4); - - /* Remove the qualifiers for the rest of the expressions and - create the VAL temp variable to hold the RHS. */ - nonatomic_type = build_qualified_type (expr_type, TYPE_UNQUALIFIED); - tmp = create_tmp_var_raw (nonatomic_type); - tmp_addr = build_unary_op (loc, ADDR_EXPR, tmp, false); - TREE_ADDRESSABLE (tmp) = 1; - /* Do not disable warnings for TMP even though it's artificial. - -Winvalid-memory-model depends on it. */ - - /* Issue __atomic_load (&expr, &tmp, SEQ_CST); */ - fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD); - params->quick_push (expr_addr); - params->quick_push (tmp_addr); - params->quick_push (seq_cst); - func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); - - /* EXPR is always read. */ - mark_exp_read (exp.value); - - /* Return tmp which contains the value loaded. */ - exp.value = build4 (TARGET_EXPR, nonatomic_type, tmp, func_call, - NULL_TREE, NULL_TREE); - } - if (convert_p && !error_operand_p (exp.value) - && (TREE_CODE (TREE_TYPE (exp.value)) != ARRAY_TYPE)) - exp.value = convert (build_qualified_type (TREE_TYPE (exp.value), TYPE_UNQUALIFIED), exp.value); - return exp; -} - -/* EXP is an expression of integer type. Apply the integer promotions - to it and return the promoted value. */ - -tree -perform_integral_promotions (tree exp) -{ - tree type = TREE_TYPE (exp); - enum tree_code code = TREE_CODE (type); - - gcc_assert (INTEGRAL_TYPE_P (type)); - - /* Normally convert enums to int, - but convert wide enums to something wider. */ - if (code == ENUMERAL_TYPE) - { - type = c_common_type_for_size (MAX (TYPE_PRECISION (type), - TYPE_PRECISION (integer_type_node)), - ((TYPE_PRECISION (type) - >= TYPE_PRECISION (integer_type_node)) - && TYPE_UNSIGNED (type))); - - return convert (type, exp); - } - - /* ??? This should no longer be needed now bit-fields have their - proper types. */ - if (TREE_CODE (exp) == COMPONENT_REF - && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1)) - /* If it's thinner than an int, promote it like a - c_promoting_integer_type_p, otherwise leave it alone. */ - && compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)), - TYPE_PRECISION (integer_type_node)) < 0) - return convert (integer_type_node, exp); - - if (c_promoting_integer_type_p (type)) - { - /* Preserve unsignedness if not really getting any wider. */ - if (TYPE_UNSIGNED (type) - && TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) - return convert (unsigned_type_node, exp); - - return convert (integer_type_node, exp); - } - - return exp; -} - - -/* Perform default promotions for C data used in expressions. - Enumeral types or short or char are converted to int. - In addition, manifest constants symbols are replaced by their values. */ - -tree -default_conversion (tree exp) -{ - tree orig_exp; - tree type = TREE_TYPE (exp); - enum tree_code code = TREE_CODE (type); - tree promoted_type; - - mark_exp_read (exp); - - /* Functions and arrays have been converted during parsing. */ - gcc_assert (code != FUNCTION_TYPE); - if (code == ARRAY_TYPE) - return exp; - - /* Constants can be used directly unless they're not loadable. */ - if (TREE_CODE (exp) == CONST_DECL) - exp = DECL_INITIAL (exp); - - /* Strip no-op conversions. */ - orig_exp = exp; - STRIP_TYPE_NOPS (exp); - - copy_warning (exp, orig_exp); - - if (code == VOID_TYPE) - { - error_at (EXPR_LOC_OR_LOC (exp, input_location), - "void value not ignored as it ought to be"); - return error_mark_node; - } - - exp = require_complete_type (EXPR_LOC_OR_LOC (exp, input_location), exp); - if (exp == error_mark_node) - return error_mark_node; - - promoted_type = targetm.promoted_type (type); - if (promoted_type) - return convert (promoted_type, exp); - - if (INTEGRAL_TYPE_P (type)) - return perform_integral_promotions (exp); - - return exp; -} - -/* Look up COMPONENT in a structure or union TYPE. - - If the component name is not found, returns NULL_TREE. Otherwise, - the return value is a TREE_LIST, with each TREE_VALUE a FIELD_DECL - stepping down the chain to the component, which is in the last - TREE_VALUE of the list. Normally the list is of length one, but if - the component is embedded within (nested) anonymous structures or - unions, the list steps down the chain to the component. */ - -static tree -lookup_field (tree type, tree component) -{ - tree field; - - /* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers - to the field elements. Use a binary search on this array to quickly - find the element. Otherwise, do a linear search. TYPE_LANG_SPECIFIC - will always be set for structures which have many elements. - - Duplicate field checking replaces duplicates with NULL_TREE so - TYPE_LANG_SPECIFIC arrays are potentially no longer sorted. In that - case just iterate using DECL_CHAIN. */ - - if (TYPE_LANG_SPECIFIC (type) && TYPE_LANG_SPECIFIC (type)->s - && !seen_error ()) - { - int bot, top, half; - tree *field_array = &TYPE_LANG_SPECIFIC (type)->s->elts[0]; - - field = TYPE_FIELDS (type); - bot = 0; - top = TYPE_LANG_SPECIFIC (type)->s->len; - while (top - bot > 1) - { - half = (top - bot + 1) >> 1; - field = field_array[bot+half]; - - if (DECL_NAME (field) == NULL_TREE) - { - /* Step through all anon unions in linear fashion. */ - while (DECL_NAME (field_array[bot]) == NULL_TREE) - { - field = field_array[bot++]; - if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) - { - tree anon = lookup_field (TREE_TYPE (field), component); - - if (anon) - return tree_cons (NULL_TREE, field, anon); - - /* The Plan 9 compiler permits referring - directly to an anonymous struct/union field - using a typedef name. */ - if (flag_plan9_extensions - && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE - && (TREE_CODE (TYPE_NAME (TREE_TYPE (field))) - == TYPE_DECL) - && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) - == component)) - break; - } - } - - /* Entire record is only anon unions. */ - if (bot > top) - return NULL_TREE; - - /* Restart the binary search, with new lower bound. */ - continue; - } - - if (DECL_NAME (field) == component) - break; - if (DECL_NAME (field) < component) - bot += half; - else - top = bot + half; - } - - if (DECL_NAME (field_array[bot]) == component) - field = field_array[bot]; - else if (DECL_NAME (field) != component) - return NULL_TREE; - } - else - { - for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) - { - if (DECL_NAME (field) == NULL_TREE - && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) - { - tree anon = lookup_field (TREE_TYPE (field), component); - - if (anon) - return tree_cons (NULL_TREE, field, anon); - - /* The Plan 9 compiler permits referring directly to an - anonymous struct/union field using a typedef - name. */ - if (flag_plan9_extensions - && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE - && TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL - && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) - == component)) - break; - } - - if (DECL_NAME (field) == component) - break; - } - - if (field == NULL_TREE) - return NULL_TREE; - } - - return tree_cons (NULL_TREE, field, NULL_TREE); -} - -/* Recursively append candidate IDENTIFIER_NODEs to CANDIDATES. */ - -static void -lookup_field_fuzzy_find_candidates (tree type, tree component, - vec *candidates) -{ - tree field; - for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) - { - if (DECL_NAME (field) == NULL_TREE - && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) - lookup_field_fuzzy_find_candidates (TREE_TYPE (field), component, - candidates); - - if (DECL_NAME (field)) - candidates->safe_push (DECL_NAME (field)); - } -} - -/* Like "lookup_field", but find the closest matching IDENTIFIER_NODE, - rather than returning a TREE_LIST for an exact match. */ - -static tree -lookup_field_fuzzy (tree type, tree component) -{ - gcc_assert (TREE_CODE (component) == IDENTIFIER_NODE); - - /* First, gather a list of candidates. */ - auto_vec candidates; - - lookup_field_fuzzy_find_candidates (type, component, - &candidates); - - return find_closest_identifier (component, &candidates); -} - -/* Support function for build_component_ref's error-handling. - - Given DATUM_TYPE, and "DATUM.COMPONENT", where DATUM is *not* a - struct or union, should we suggest "DATUM->COMPONENT" as a hint? */ - -static bool -should_suggest_deref_p (tree datum_type) -{ - /* We don't do it for Objective-C, since Objective-C 2.0 dot-syntax - allows "." for ptrs; we could be handling a failed attempt - to access a property. */ - if (c_dialect_objc ()) - return false; - - /* Only suggest it for pointers... */ - if (TREE_CODE (datum_type) != POINTER_TYPE) - return false; - - /* ...to structs/unions. */ - tree underlying_type = TREE_TYPE (datum_type); - enum tree_code code = TREE_CODE (underlying_type); - if (code == RECORD_TYPE || code == UNION_TYPE) - return true; - else - return false; -} - -/* Make an expression to refer to the COMPONENT field of structure or - union value DATUM. COMPONENT is an IDENTIFIER_NODE. LOC is the - location of the COMPONENT_REF. COMPONENT_LOC is the location - of COMPONENT. */ - -tree -build_component_ref (location_t loc, tree datum, tree component, - location_t component_loc) -{ - tree type = TREE_TYPE (datum); - enum tree_code code = TREE_CODE (type); - tree field = NULL; - tree ref; - bool datum_lvalue = lvalue_p (datum); - - if (!objc_is_public (datum, component)) - return error_mark_node; - - /* Detect Objective-C property syntax object.property. */ - if (c_dialect_objc () - && (ref = objc_maybe_build_component_ref (datum, component))) - return ref; - - /* See if there is a field or component with name COMPONENT. */ - - if (code == RECORD_TYPE || code == UNION_TYPE) - { - if (!COMPLETE_TYPE_P (type)) - { - c_incomplete_type_error (loc, NULL_TREE, type); - return error_mark_node; - } - - field = lookup_field (type, component); - - if (!field) - { - tree guessed_id = lookup_field_fuzzy (type, component); - if (guessed_id) - { - /* Attempt to provide a fixit replacement hint, if - we have a valid range for the component. */ - location_t reported_loc - = (component_loc != UNKNOWN_LOCATION) ? component_loc : loc; - gcc_rich_location rich_loc (reported_loc); - if (component_loc != UNKNOWN_LOCATION) - rich_loc.add_fixit_misspelled_id (component_loc, guessed_id); - error_at (&rich_loc, - "%qT has no member named %qE; did you mean %qE?", - type, component, guessed_id); - } - else - error_at (loc, "%qT has no member named %qE", type, component); - return error_mark_node; - } - - /* Accessing elements of atomic structures or unions is undefined - behavior (C11 6.5.2.3#5). */ - if (TYPE_ATOMIC (type) && c_inhibit_evaluation_warnings == 0) - { - if (code == RECORD_TYPE) - warning_at (loc, 0, "accessing a member %qE of an atomic " - "structure %qE", component, datum); - else - warning_at (loc, 0, "accessing a member %qE of an atomic " - "union %qE", component, datum); - } - - /* Chain the COMPONENT_REFs if necessary down to the FIELD. - This might be better solved in future the way the C++ front - end does it - by giving the anonymous entities each a - separate name and type, and then have build_component_ref - recursively call itself. We can't do that here. */ - do - { - tree subdatum = TREE_VALUE (field); - int quals; - tree subtype; - bool use_datum_quals; - - if (TREE_TYPE (subdatum) == error_mark_node) - return error_mark_node; - - /* If this is an rvalue, it does not have qualifiers in C - standard terms and we must avoid propagating such - qualifiers down to a non-lvalue array that is then - converted to a pointer. */ - use_datum_quals = (datum_lvalue - || TREE_CODE (TREE_TYPE (subdatum)) != ARRAY_TYPE); - - quals = TYPE_QUALS (strip_array_types (TREE_TYPE (subdatum))); - if (use_datum_quals) - quals |= TYPE_QUALS (TREE_TYPE (datum)); - subtype = c_build_qualified_type (TREE_TYPE (subdatum), quals); - - ref = build3 (COMPONENT_REF, subtype, datum, subdatum, - NULL_TREE); - SET_EXPR_LOCATION (ref, loc); - if (TREE_READONLY (subdatum) - || (use_datum_quals && TREE_READONLY (datum))) - TREE_READONLY (ref) = 1; - if (TREE_THIS_VOLATILE (subdatum) - || (use_datum_quals && TREE_THIS_VOLATILE (datum))) - TREE_THIS_VOLATILE (ref) = 1; - - if (TREE_UNAVAILABLE (subdatum)) - error_unavailable_use (subdatum, NULL_TREE); - else if (TREE_DEPRECATED (subdatum)) - warn_deprecated_use (subdatum, NULL_TREE); - - datum = ref; - - field = TREE_CHAIN (field); - } - while (field); - - return ref; - } - else if (should_suggest_deref_p (type)) - { - /* Special-case the error message for "ptr.field" for the case - where the user has confused "." vs "->". */ - rich_location richloc (line_table, loc); - /* "loc" should be the "." token. */ - richloc.add_fixit_replace ("->"); - error_at (&richloc, - "%qE is a pointer; did you mean to use %<->%>?", - datum); - return error_mark_node; - } - else if (code != ERROR_MARK) - error_at (loc, - "request for member %qE in something not a structure or union", - component); - - return error_mark_node; -} - -/* Given an expression PTR for a pointer, return an expression - for the value pointed to. - ERRORSTRING is the name of the operator to appear in error messages. - - LOC is the location to use for the generated tree. */ - -tree -build_indirect_ref (location_t loc, tree ptr, ref_operator errstring) -{ - tree pointer = default_conversion (ptr); - tree type = TREE_TYPE (pointer); - tree ref; - - if (TREE_CODE (type) == POINTER_TYPE) - { - if (CONVERT_EXPR_P (pointer) - || TREE_CODE (pointer) == VIEW_CONVERT_EXPR) - { - /* If a warning is issued, mark it to avoid duplicates from - the backend. This only needs to be done at - warn_strict_aliasing > 2. */ - if (warn_strict_aliasing > 2) - if (strict_aliasing_warning (EXPR_LOCATION (pointer), - type, TREE_OPERAND (pointer, 0))) - suppress_warning (pointer, OPT_Wstrict_aliasing_); - } - - if (TREE_CODE (pointer) == ADDR_EXPR - && (TREE_TYPE (TREE_OPERAND (pointer, 0)) - == TREE_TYPE (type))) - { - ref = TREE_OPERAND (pointer, 0); - protected_set_expr_location (ref, loc); - return ref; - } - else - { - tree t = TREE_TYPE (type); - - ref = build1 (INDIRECT_REF, t, pointer); - - if (VOID_TYPE_P (t) && c_inhibit_evaluation_warnings == 0) - warning_at (loc, 0, "dereferencing % pointer"); - - /* We *must* set TREE_READONLY when dereferencing a pointer to const, - so that we get the proper error message if the result is used - to assign to. Also, &* is supposed to be a no-op. - And ANSI C seems to specify that the type of the result - should be the const type. */ - /* A de-reference of a pointer to const is not a const. It is valid - to change it via some other pointer. */ - TREE_READONLY (ref) = TYPE_READONLY (t); - TREE_SIDE_EFFECTS (ref) - = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer); - TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t); - protected_set_expr_location (ref, loc); - return ref; - } - } - else if (TREE_CODE (pointer) != ERROR_MARK) - invalid_indirection_error (loc, type, errstring); - - return error_mark_node; -} - -/* This handles expressions of the form "a[i]", which denotes - an array reference. - - This is logically equivalent in C to *(a+i), but we may do it differently. - If A is a variable or a member, we generate a primitive ARRAY_REF. - This avoids forcing the array out of registers, and can work on - arrays that are not lvalues (for example, members of structures returned - by functions). - - For vector types, allow vector[i] but not i[vector], and create - *(((type*)&vectortype) + i) for the expression. - - LOC is the location to use for the returned expression. */ - -tree -build_array_ref (location_t loc, tree array, tree index) -{ - tree ret; - bool swapped = false; - if (TREE_TYPE (array) == error_mark_node - || TREE_TYPE (index) == error_mark_node) - return error_mark_node; - - if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE - && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE - /* Allow vector[index] but not index[vector]. */ - && !gnu_vector_type_p (TREE_TYPE (array))) - { - if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE - && TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE) - { - error_at (loc, - "subscripted value is neither array nor pointer nor vector"); - - return error_mark_node; - } - std::swap (array, index); - swapped = true; - } - - if (!INTEGRAL_TYPE_P (TREE_TYPE (index))) - { - error_at (loc, "array subscript is not an integer"); - return error_mark_node; - } - - if (TREE_CODE (TREE_TYPE (TREE_TYPE (array))) == FUNCTION_TYPE) - { - error_at (loc, "subscripted value is pointer to function"); - return error_mark_node; - } - - /* ??? Existing practice has been to warn only when the char - index is syntactically the index, not for char[array]. */ - if (!swapped) - warn_array_subscript_with_type_char (loc, index); - - /* Apply default promotions *after* noticing character types. */ - index = default_conversion (index); - if (index == error_mark_node) - return error_mark_node; - - gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE); - - bool was_vector = VECTOR_TYPE_P (TREE_TYPE (array)); - bool non_lvalue = convert_vector_to_array_for_subscript (loc, &array, index); - - if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE) - { - tree rval, type; - - /* An array that is indexed by a non-constant - cannot be stored in a register; we must be able to do - address arithmetic on its address. - Likewise an array of elements of variable size. */ - if (TREE_CODE (index) != INTEGER_CST - || (COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (array))) - && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST)) - { - if (!c_mark_addressable (array, true)) - return error_mark_node; - } - /* An array that is indexed by a constant value which is not within - the array bounds cannot be stored in a register either; because we - would get a crash in store_bit_field/extract_bit_field when trying - to access a non-existent part of the register. */ - if (TREE_CODE (index) == INTEGER_CST - && TYPE_DOMAIN (TREE_TYPE (array)) - && !int_fits_type_p (index, TYPE_DOMAIN (TREE_TYPE (array)))) - { - if (!c_mark_addressable (array)) - return error_mark_node; - } - - if ((pedantic || warn_c90_c99_compat) - && ! was_vector) - { - tree foo = array; - while (TREE_CODE (foo) == COMPONENT_REF) - foo = TREE_OPERAND (foo, 0); - if (VAR_P (foo) && C_DECL_REGISTER (foo)) - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids subscripting % array"); - else if (!lvalue_p (foo)) - pedwarn_c90 (loc, OPT_Wpedantic, - "ISO C90 forbids subscripting non-lvalue " - "array"); - } - - type = TREE_TYPE (TREE_TYPE (array)); - rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE); - /* Array ref is const/volatile if the array elements are - or if the array is. */ - TREE_READONLY (rval) - |= (TYPE_READONLY (TREE_TYPE (TREE_TYPE (array))) - | TREE_READONLY (array)); - TREE_SIDE_EFFECTS (rval) - |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) - | TREE_SIDE_EFFECTS (array)); - TREE_THIS_VOLATILE (rval) - |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) - /* This was added by rms on 16 Nov 91. - It fixes vol struct foo *a; a->elts[1] - in an inline function. - Hope it doesn't break something else. */ - | TREE_THIS_VOLATILE (array)); - ret = require_complete_type (loc, rval); - protected_set_expr_location (ret, loc); - if (non_lvalue) - ret = non_lvalue_loc (loc, ret); - return ret; - } - else - { - tree ar = default_conversion (array); - - if (ar == error_mark_node) - return ar; - - gcc_assert (TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE); - gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE); - - ret = build_indirect_ref (loc, build_binary_op (loc, PLUS_EXPR, ar, - index, false), - RO_ARRAY_INDEXING); - if (non_lvalue) - ret = non_lvalue_loc (loc, ret); - return ret; - } -} - -/* Build an external reference to identifier ID. FUN indicates - whether this will be used for a function call. LOC is the source - location of the identifier. This sets *TYPE to the type of the - identifier, which is not the same as the type of the returned value - for CONST_DECLs defined as enum constants. If the type of the - identifier is not available, *TYPE is set to NULL. */ -tree -build_external_ref (location_t loc, tree id, bool fun, tree *type) -{ - tree ref; - tree decl = lookup_name (id); - - /* In Objective-C, an instance variable (ivar) may be preferred to - whatever lookup_name() found. */ - decl = objc_lookup_ivar (decl, id); - - *type = NULL; - if (decl && decl != error_mark_node) - { - ref = decl; - *type = TREE_TYPE (ref); - } - else if (fun) - /* Implicit function declaration. */ - ref = implicitly_declare (loc, id); - else if (decl == error_mark_node) - /* Don't complain about something that's already been - complained about. */ - return error_mark_node; - else - { - undeclared_variable (loc, id); - return error_mark_node; - } - - if (TREE_TYPE (ref) == error_mark_node) - return error_mark_node; - - if (TREE_UNAVAILABLE (ref)) - error_unavailable_use (ref, NULL_TREE); - else if (TREE_DEPRECATED (ref)) - warn_deprecated_use (ref, NULL_TREE); - - /* Recursive call does not count as usage. */ - if (ref != current_function_decl) - { - TREE_USED (ref) = 1; - } - - if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof) - { - if (!in_sizeof && !in_typeof) - C_DECL_USED (ref) = 1; - else if (DECL_INITIAL (ref) == NULL_TREE - && DECL_EXTERNAL (ref) - && !TREE_PUBLIC (ref)) - record_maybe_used_decl (ref); - } - - if (TREE_CODE (ref) == CONST_DECL) - { - used_types_insert (TREE_TYPE (ref)); - - if (warn_cxx_compat - && TREE_CODE (TREE_TYPE (ref)) == ENUMERAL_TYPE - && C_TYPE_DEFINED_IN_STRUCT (TREE_TYPE (ref))) - { - warning_at (loc, OPT_Wc___compat, - ("enum constant defined in struct or union " - "is not visible in C++")); - inform (DECL_SOURCE_LOCATION (ref), "enum constant defined here"); - } - - ref = DECL_INITIAL (ref); - TREE_CONSTANT (ref) = 1; - } - else if (current_function_decl != NULL_TREE - && !DECL_FILE_SCOPE_P (current_function_decl) - && (VAR_OR_FUNCTION_DECL_P (ref) - || TREE_CODE (ref) == PARM_DECL)) - { - tree context = decl_function_context (ref); - - if (context != NULL_TREE && context != current_function_decl) - DECL_NONLOCAL (ref) = 1; - } - /* C99 6.7.4p3: An inline definition of a function with external - linkage ... shall not contain a reference to an identifier with - internal linkage. */ - else if (current_function_decl != NULL_TREE - && DECL_DECLARED_INLINE_P (current_function_decl) - && DECL_EXTERNAL (current_function_decl) - && VAR_OR_FUNCTION_DECL_P (ref) - && (!VAR_P (ref) || TREE_STATIC (ref)) - && ! TREE_PUBLIC (ref) - && DECL_CONTEXT (ref) != current_function_decl) - record_inline_static (loc, current_function_decl, ref, - csi_internal); - - return ref; -} - -/* Record details of decls possibly used inside sizeof or typeof. */ -struct maybe_used_decl -{ - /* The decl. */ - tree decl; - /* The level seen at (in_sizeof + in_typeof). */ - int level; - /* The next one at this level or above, or NULL. */ - struct maybe_used_decl *next; -}; - -static struct maybe_used_decl *maybe_used_decls; - -/* Record that DECL, an undefined static function reference seen - inside sizeof or typeof, might be used if the operand of sizeof is - a VLA type or the operand of typeof is a variably modified - type. */ - -static void -record_maybe_used_decl (tree decl) -{ - struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl); - t->decl = decl; - t->level = in_sizeof + in_typeof; - t->next = maybe_used_decls; - maybe_used_decls = t; -} - -/* Pop the stack of decls possibly used inside sizeof or typeof. If - USED is false, just discard them. If it is true, mark them used - (if no longer inside sizeof or typeof) or move them to the next - level up (if still inside sizeof or typeof). */ - -void -pop_maybe_used (bool used) -{ - struct maybe_used_decl *p = maybe_used_decls; - int cur_level = in_sizeof + in_typeof; - while (p && p->level > cur_level) - { - if (used) - { - if (cur_level == 0) - C_DECL_USED (p->decl) = 1; - else - p->level = cur_level; - } - p = p->next; - } - if (!used || cur_level == 0) - maybe_used_decls = p; -} - -/* Return the result of sizeof applied to EXPR. */ - -struct c_expr -c_expr_sizeof_expr (location_t loc, struct c_expr expr) -{ - struct c_expr ret; - if (expr.value == error_mark_node) - { - ret.value = error_mark_node; - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - pop_maybe_used (false); - } - else - { - bool expr_const_operands = true; - - if (TREE_CODE (expr.value) == PARM_DECL - && C_ARRAY_PARAMETER (expr.value)) - { - auto_diagnostic_group d; - if (warning_at (loc, OPT_Wsizeof_array_argument, - "% on array function parameter %qE will " - "return size of %qT", expr.value, - TREE_TYPE (expr.value))) - inform (DECL_SOURCE_LOCATION (expr.value), "declared here"); - } - tree folded_expr = c_fully_fold (expr.value, require_constant_value, - &expr_const_operands); - ret.value = c_sizeof (loc, TREE_TYPE (folded_expr)); - c_last_sizeof_arg = expr.value; - c_last_sizeof_loc = loc; - ret.original_code = SIZEOF_EXPR; - ret.original_type = NULL; - if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr))) - { - /* sizeof is evaluated when given a vla (C99 6.5.3.4p2). */ - ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), - folded_expr, ret.value); - C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands; - SET_EXPR_LOCATION (ret.value, loc); - } - pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr))); - } - return ret; -} - -/* Return the result of sizeof applied to T, a structure for the type - name passed to sizeof (rather than the type itself). LOC is the - location of the original expression. */ - -struct c_expr -c_expr_sizeof_type (location_t loc, struct c_type_name *t) -{ - tree type; - struct c_expr ret; - tree type_expr = NULL_TREE; - bool type_expr_const = true; - type = groktypename (t, &type_expr, &type_expr_const); - ret.value = c_sizeof (loc, type); - c_last_sizeof_arg = type; - c_last_sizeof_loc = loc; - ret.original_code = SIZEOF_EXPR; - ret.original_type = NULL; - if (type == error_mark_node) - { - ret.value = error_mark_node; - ret.original_code = ERROR_MARK; - } - else - if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST) - && C_TYPE_VARIABLE_SIZE (type)) - { - /* If the type is a [*] array, it is a VLA but is represented as - having a size of zero. In such a case we must ensure that - the result of sizeof does not get folded to a constant by - c_fully_fold, because if the size is evaluated the result is - not constant and so constraints on zero or negative size - arrays must not be applied when this sizeof call is inside - another array declarator. */ - if (!type_expr) - type_expr = integer_zero_node; - ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), - type_expr, ret.value); - C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const; - } - pop_maybe_used (type != error_mark_node - ? C_TYPE_VARIABLE_SIZE (type) : false); - return ret; -} - -/* Build a function call to function FUNCTION with parameters PARAMS. - The function call is at LOC. - PARAMS is a list--a chain of TREE_LIST nodes--in which the - TREE_VALUE of each node is a parameter-expression. - FUNCTION's data type may be a function type or a pointer-to-function. */ - -tree -build_function_call (location_t loc, tree function, tree params) -{ - vec *v; - tree ret; - - vec_alloc (v, list_length (params)); - for (; params; params = TREE_CHAIN (params)) - v->quick_push (TREE_VALUE (params)); - ret = c_build_function_call_vec (loc, vNULL, function, v, NULL); - vec_free (v); - return ret; -} - -/* Give a note about the location of the declaration of DECL. */ - -static void -inform_declaration (tree decl) -{ - if (decl && (TREE_CODE (decl) != FUNCTION_DECL - || !DECL_IS_UNDECLARED_BUILTIN (decl))) - inform (DECL_SOURCE_LOCATION (decl), "declared here"); -} - -/* Build a function call to function FUNCTION with parameters PARAMS. - If FUNCTION is the result of resolving an overloaded target built-in, - ORIG_FUNDECL is the original function decl, otherwise it is null. - ORIGTYPES, if not NULL, is a vector of types; each element is - either NULL or the original type of the corresponding element in - PARAMS. The original type may differ from TREE_TYPE of the - parameter for enums. FUNCTION's data type may be a function type - or pointer-to-function. This function changes the elements of - PARAMS. */ - -tree -build_function_call_vec (location_t loc, vec arg_loc, - tree function, vec *params, - vec *origtypes, tree orig_fundecl) -{ - tree fntype, fundecl = NULL_TREE; - tree name = NULL_TREE, result; - tree tem; - int nargs; - tree *argarray; - - - /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ - STRIP_TYPE_NOPS (function); - - /* Convert anything with function type to a pointer-to-function. */ - if (TREE_CODE (function) == FUNCTION_DECL) - { - name = DECL_NAME (function); - - if (flag_tm) - tm_malloc_replacement (function); - fundecl = function; - if (!orig_fundecl) - orig_fundecl = fundecl; - /* Atomic functions have type checking/casting already done. They are - often rewritten and don't match the original parameter list. */ - if (name && startswith (IDENTIFIER_POINTER (name), "__atomic_")) - origtypes = NULL; - } - if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE) - function = function_to_pointer_conversion (loc, function); - - /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF - expressions, like those used for ObjC messenger dispatches. */ - if (params && !params->is_empty ()) - function = objc_rewrite_function_call (function, (*params)[0]); - - function = c_fully_fold (function, false, NULL); - - fntype = TREE_TYPE (function); - - if (TREE_CODE (fntype) == ERROR_MARK) - return error_mark_node; - - if (!(TREE_CODE (fntype) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)) - { - if (!flag_diagnostics_show_caret && !STATEMENT_CLASS_P (function)) - error_at (loc, - "called object %qE is not a function or function pointer", - function); - else if (DECL_P (function)) - { - error_at (loc, - "called object %qD is not a function or function pointer", - function); - inform_declaration (function); - } - else - error_at (loc, - "called object is not a function or function pointer"); - return error_mark_node; - } - - if (fundecl && TREE_THIS_VOLATILE (fundecl)) - current_function_returns_abnormally = 1; - - /* fntype now gets the type of function pointed to. */ - fntype = TREE_TYPE (fntype); - - /* Convert the parameters to the types declared in the - function prototype, or apply default promotions. */ - - nargs = convert_arguments (loc, arg_loc, TYPE_ARG_TYPES (fntype), params, - origtypes, function, fundecl); - if (nargs < 0) - return error_mark_node; - - /* Check that the function is called through a compatible prototype. - If it is not, warn. */ - if (CONVERT_EXPR_P (function) - && TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR - && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL - && !comptypes (fntype, TREE_TYPE (tem))) - { - tree return_type = TREE_TYPE (fntype); - - /* This situation leads to run-time undefined behavior. We can't, - therefore, simply error unless we can prove that all possible - executions of the program must execute the code. */ - warning_at (loc, 0, "function called through a non-compatible type"); - - if (VOID_TYPE_P (return_type) - && TYPE_QUALS (return_type) != TYPE_UNQUALIFIED) - pedwarn (loc, 0, - "function with qualified void return type called"); - } - - argarray = vec_safe_address (params); - - /* Check that arguments to builtin functions match the expectations. */ - if (fundecl - && fndecl_built_in_p (fundecl) - && !check_builtin_function_arguments (loc, arg_loc, fundecl, - orig_fundecl, nargs, argarray)) - return error_mark_node; - - /* Check that the arguments to the function are valid. */ - bool warned_p = check_function_arguments (loc, fundecl, fntype, - nargs, argarray, &arg_loc); - - if (name != NULL_TREE - && startswith (IDENTIFIER_POINTER (name), "__builtin_")) - { - if (require_constant_value) - result - = fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype), - function, nargs, argarray); - else - result = fold_build_call_array_loc (loc, TREE_TYPE (fntype), - function, nargs, argarray); - if (TREE_CODE (result) == NOP_EXPR - && TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST) - STRIP_TYPE_NOPS (result); - } - else - result = build_call_array_loc (loc, TREE_TYPE (fntype), - function, nargs, argarray); - /* If -Wnonnull warning has been diagnosed, avoid diagnosing it again - later. */ - if (warned_p && TREE_CODE (result) == CALL_EXPR) - suppress_warning (result, OPT_Wnonnull); - - /* In this improbable scenario, a nested function returns a VM type. - Create a TARGET_EXPR so that the call always has a LHS, much as - what the C++ FE does for functions returning non-PODs. */ - if (variably_modified_type_p (TREE_TYPE (fntype), NULL_TREE)) - { - tree tmp = create_tmp_var_raw (TREE_TYPE (fntype)); - result = build4 (TARGET_EXPR, TREE_TYPE (fntype), tmp, result, - NULL_TREE, NULL_TREE); - } - - if (VOID_TYPE_P (TREE_TYPE (result))) - { - if (TYPE_QUALS (TREE_TYPE (result)) != TYPE_UNQUALIFIED) - pedwarn (loc, 0, - "function with qualified void return type called"); - return result; - } - return require_complete_type (loc, result); -} - -/* Like build_function_call_vec, but call also resolve_overloaded_builtin. */ - -tree -c_build_function_call_vec (location_t loc, const vec &arg_loc, - tree function, vec *params, - vec *origtypes) -{ - /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ - STRIP_TYPE_NOPS (function); - - /* Convert anything with function type to a pointer-to-function. */ - if (TREE_CODE (function) == FUNCTION_DECL) - { - /* Implement type-directed function overloading for builtins. - resolve_overloaded_builtin and targetm.resolve_overloaded_builtin - handle all the type checking. The result is a complete expression - that implements this function call. */ - tree tem = resolve_overloaded_builtin (loc, function, params); - if (tem) - return tem; - } - return build_function_call_vec (loc, arg_loc, function, params, origtypes); -} - -/* Helper for convert_arguments called to convert the VALue of argument - number ARGNUM from ORIGTYPE to the corresponding parameter number - PARMNUM and TYPE. - PLOC is the location where the conversion is being performed. - FUNCTION and FUNDECL are the same as in convert_arguments. - VALTYPE is the original type of VAL before the conversion and, - for EXCESS_PRECISION_EXPR, the operand of the expression. - NPC is true if VAL represents the null pointer constant (VAL itself - will have been folded to an integer constant). - RNAME is the same as FUNCTION except in Objective C when it's - the function selector. - EXCESS_PRECISION is true when VAL was originally represented - as EXCESS_PRECISION_EXPR. - WARNOPT is the same as in convert_for_assignment. */ - -static tree -convert_argument (location_t ploc, tree function, tree fundecl, - tree type, tree origtype, tree val, tree valtype, - bool npc, tree rname, int parmnum, int argnum, - bool excess_precision, int warnopt) -{ - /* Formal parm type is specified by a function prototype. */ - - if (type == error_mark_node || !COMPLETE_TYPE_P (type)) - { - error_at (ploc, "type of formal parameter %d is incomplete", - parmnum + 1); - return val; - } - - /* Optionally warn about conversions that differ from the default - conversions. */ - if (warn_traditional_conversion || warn_traditional) - { - unsigned int formal_prec = TYPE_PRECISION (type); - - if (INTEGRAL_TYPE_P (type) - && TREE_CODE (valtype) == REAL_TYPE) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as integer rather " - "than floating due to prototype", - argnum, rname); - if (INTEGRAL_TYPE_P (type) - && TREE_CODE (valtype) == COMPLEX_TYPE) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as integer rather " - "than complex due to prototype", - argnum, rname); - else if (TREE_CODE (type) == COMPLEX_TYPE - && TREE_CODE (valtype) == REAL_TYPE) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as complex rather " - "than floating due to prototype", - argnum, rname); - else if (TREE_CODE (type) == REAL_TYPE - && INTEGRAL_TYPE_P (valtype)) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as floating rather " - "than integer due to prototype", - argnum, rname); - else if (TREE_CODE (type) == COMPLEX_TYPE - && INTEGRAL_TYPE_P (valtype)) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as complex rather " - "than integer due to prototype", - argnum, rname); - else if (TREE_CODE (type) == REAL_TYPE - && TREE_CODE (valtype) == COMPLEX_TYPE) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as floating rather " - "than complex due to prototype", - argnum, rname); - /* ??? At some point, messages should be written about - conversions between complex types, but that's too messy - to do now. */ - else if (TREE_CODE (type) == REAL_TYPE - && TREE_CODE (valtype) == REAL_TYPE) - { - /* Warn if any argument is passed as `float', - since without a prototype it would be `double'. */ - if (formal_prec == TYPE_PRECISION (float_type_node) - && type != dfloat32_type_node) - warning_at (ploc, 0, - "passing argument %d of %qE as % " - "rather than % due to prototype", - argnum, rname); - - /* Warn if mismatch between argument and prototype - for decimal float types. Warn of conversions with - binary float types and of precision narrowing due to - prototype. */ - else if (type != valtype - && (type == dfloat32_type_node - || type == dfloat64_type_node - || type == dfloat128_type_node - || valtype == dfloat32_type_node - || valtype == dfloat64_type_node - || valtype == dfloat128_type_node) - && (formal_prec - <= TYPE_PRECISION (valtype) - || (type == dfloat128_type_node - && (valtype - != dfloat64_type_node - && (valtype - != dfloat32_type_node))) - || (type == dfloat64_type_node - && (valtype - != dfloat32_type_node)))) - warning_at (ploc, 0, - "passing argument %d of %qE as %qT " - "rather than %qT due to prototype", - argnum, rname, type, valtype); - - } - /* Detect integer changing in width or signedness. - These warnings are only activated with - -Wtraditional-conversion, not with -Wtraditional. */ - else if (warn_traditional_conversion - && INTEGRAL_TYPE_P (type) - && INTEGRAL_TYPE_P (valtype)) - { - tree would_have_been = default_conversion (val); - tree type1 = TREE_TYPE (would_have_been); - - if (val == error_mark_node) - /* VAL could have been of incomplete type. */; - else if (TREE_CODE (type) == ENUMERAL_TYPE - && (TYPE_MAIN_VARIANT (type) - == TYPE_MAIN_VARIANT (valtype))) - /* No warning if function asks for enum - and the actual arg is that enum type. */ - ; - else if (formal_prec != TYPE_PRECISION (type1)) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE " - "with different width due to prototype", - argnum, rname); - else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1)) - ; - /* Don't complain if the formal parameter type - is an enum, because we can't tell now whether - the value was an enum--even the same enum. */ - else if (TREE_CODE (type) == ENUMERAL_TYPE) - ; - else if (TREE_CODE (val) == INTEGER_CST - && int_fits_type_p (val, type)) - /* Change in signedness doesn't matter - if a constant value is unaffected. */ - ; - /* If the value is extended from a narrower - unsigned type, it doesn't matter whether we - pass it as signed or unsigned; the value - certainly is the same either way. */ - else if (TYPE_PRECISION (valtype) < TYPE_PRECISION (type) - && TYPE_UNSIGNED (valtype)) - ; - else if (TYPE_UNSIGNED (type)) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE " - "as unsigned due to prototype", - argnum, rname); - else - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE " - "as signed due to prototype", - argnum, rname); - } - } - - /* Possibly restore an EXCESS_PRECISION_EXPR for the - sake of better warnings from convert_and_check. */ - if (excess_precision) - val = build1 (EXCESS_PRECISION_EXPR, valtype, val); - - tree parmval = convert_for_assignment (ploc, ploc, type, - val, origtype, ic_argpass, - npc, fundecl, function, - parmnum + 1, warnopt); - - if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0) - && INTEGRAL_TYPE_P (type) - && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) - parmval = default_conversion (parmval); - - return parmval; -} - -/* Convert the argument expressions in the vector VALUES - to the types in the list TYPELIST. - - If TYPELIST is exhausted, or when an element has NULL as its type, - perform the default conversions. - - ORIGTYPES is the original types of the expressions in VALUES. This - holds the type of enum values which have been converted to integral - types. It may be NULL. - - FUNCTION is a tree for the called function. It is used only for - error messages, where it is formatted with %qE. - - This is also where warnings about wrong number of args are generated. - - ARG_LOC are locations of function arguments (if any). - - Returns the actual number of arguments processed (which may be less - than the length of VALUES in some error situations), or -1 on - failure. */ - -static int -convert_arguments (location_t loc, vec arg_loc, tree typelist, - vec *values, vec *origtypes, - tree function, tree fundecl) -{ - unsigned int parmnum; - bool error_args = false; - const bool type_generic = fundecl - && lookup_attribute ("type generic", TYPE_ATTRIBUTES (TREE_TYPE (fundecl))); - bool type_generic_remove_excess_precision = false; - bool type_generic_overflow_p = false; - tree selector; - - /* Change pointer to function to the function itself for - diagnostics. */ - if (TREE_CODE (function) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) - function = TREE_OPERAND (function, 0); - - /* Handle an ObjC selector specially for diagnostics. */ - selector = objc_message_selector (); - - /* For a call to a built-in function declared without a prototype, - set to the built-in function's argument list. */ - tree builtin_typelist = NULL_TREE; - - /* For type-generic built-in functions, determine whether excess - precision should be removed (classification) or not - (comparison). */ - if (fundecl - && fndecl_built_in_p (fundecl, BUILT_IN_NORMAL)) - { - built_in_function code = DECL_FUNCTION_CODE (fundecl); - if (C_DECL_BUILTIN_PROTOTYPE (fundecl)) - { - /* For a call to a built-in function declared without a prototype - use the types of the parameters of the internal built-in to - match those of the arguments to. */ - if (tree bdecl = builtin_decl_explicit (code)) - builtin_typelist = TYPE_ARG_TYPES (TREE_TYPE (bdecl)); - } - - /* For type-generic built-in functions, determine whether excess - precision should be removed (classification) or not - (comparison). */ - if (type_generic) - switch (code) - { - case BUILT_IN_ISFINITE: - case BUILT_IN_ISINF: - case BUILT_IN_ISINF_SIGN: - case BUILT_IN_ISNAN: - case BUILT_IN_ISNORMAL: - case BUILT_IN_FPCLASSIFY: - type_generic_remove_excess_precision = true; - break; - - case BUILT_IN_ADD_OVERFLOW_P: - case BUILT_IN_SUB_OVERFLOW_P: - case BUILT_IN_MUL_OVERFLOW_P: - /* The last argument of these type-generic builtins - should not be promoted. */ - type_generic_overflow_p = true; - break; - - default: - break; - } - } - - /* Scan the given expressions (VALUES) and types (TYPELIST), producing - individual converted arguments. */ - - tree typetail, builtin_typetail, val; - for (typetail = typelist, - builtin_typetail = builtin_typelist, - parmnum = 0; - values && values->iterate (parmnum, &val); - ++parmnum) - { - /* The type of the function parameter (if it was declared with one). */ - tree type = typetail ? TREE_VALUE (typetail) : NULL_TREE; - /* The type of the built-in function parameter (if the function - is a built-in). Used to detect type incompatibilities in - calls to built-ins declared without a prototype. */ - tree builtin_type = (builtin_typetail - ? TREE_VALUE (builtin_typetail) : NULL_TREE); - /* The original type of the argument being passed to the function. */ - tree valtype = TREE_TYPE (val); - /* The called function (or function selector in Objective C). */ - tree rname = function; - int argnum = parmnum + 1; - const char *invalid_func_diag; - /* Set for EXCESS_PRECISION_EXPR arguments. */ - bool excess_precision = false; - /* The value of the argument after conversion to the type - of the function parameter it is passed to. */ - tree parmval; - /* Some __atomic_* builtins have additional hidden argument at - position 0. */ - location_t ploc - = !arg_loc.is_empty () && values->length () == arg_loc.length () - ? expansion_point_location_if_in_system_header (arg_loc[parmnum]) - : input_location; - - if (type == void_type_node) - { - if (selector) - error_at (loc, "too many arguments to method %qE", selector); - else - error_at (loc, "too many arguments to function %qE", function); - inform_declaration (fundecl); - return error_args ? -1 : (int) parmnum; - } - - if (builtin_type == void_type_node) - { - if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch, - "too many arguments to built-in function %qE " - "expecting %d", function, parmnum)) - inform_declaration (fundecl); - builtin_typetail = NULL_TREE; - } - - if (selector && argnum > 2) - { - rname = selector; - argnum -= 2; - } - - /* Determine if VAL is a null pointer constant before folding it. */ - bool npc = null_pointer_constant_p (val); - - /* If there is excess precision and a prototype, convert once to - the required type rather than converting via the semantic - type. Likewise without a prototype a float value represented - as long double should be converted once to double. But for - type-generic classification functions excess precision must - be removed here. */ - if (TREE_CODE (val) == EXCESS_PRECISION_EXPR - && (type || !type_generic || !type_generic_remove_excess_precision)) - { - val = TREE_OPERAND (val, 0); - excess_precision = true; - } - val = c_fully_fold (val, false, NULL); - STRIP_TYPE_NOPS (val); - - val = require_complete_type (ploc, val); - - /* Some floating-point arguments must be promoted to double when - no type is specified by a prototype. This applies to - arguments of type float, and to architecture-specific types - (ARM __fp16), but not to _FloatN or _FloatNx types. */ - bool promote_float_arg = false; - if (type == NULL_TREE - && TREE_CODE (valtype) == REAL_TYPE - && (TYPE_PRECISION (valtype) - <= TYPE_PRECISION (double_type_node)) - && TYPE_MAIN_VARIANT (valtype) != double_type_node - && TYPE_MAIN_VARIANT (valtype) != long_double_type_node - && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype))) - { - /* Promote this argument, unless it has a _FloatN or - _FloatNx type. */ - promote_float_arg = true; - for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++) - if (TYPE_MAIN_VARIANT (valtype) == FLOATN_NX_TYPE_NODE (i)) - { - promote_float_arg = false; - break; - } - } - - if (type != NULL_TREE) - { - tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum]; - parmval = convert_argument (ploc, function, fundecl, type, origtype, - val, valtype, npc, rname, parmnum, argnum, - excess_precision, 0); - } - else if (promote_float_arg) - { - if (type_generic) - parmval = val; - else - { - /* Convert `float' to `double'. */ - if (warn_double_promotion && !c_inhibit_evaluation_warnings) - warning_at (ploc, OPT_Wdouble_promotion, - "implicit conversion from %qT to %qT when passing " - "argument to function", - valtype, double_type_node); - parmval = convert (double_type_node, val); - } - } - else if ((excess_precision && !type_generic) - || (type_generic_overflow_p && parmnum == 2)) - /* A "double" argument with excess precision being passed - without a prototype or in variable arguments. - The last argument of __builtin_*_overflow_p should not be - promoted. */ - parmval = convert (valtype, val); - else if ((invalid_func_diag = - targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val))) - { - error (invalid_func_diag); - return -1; - } - else if (TREE_CODE (val) == ADDR_EXPR && reject_gcc_builtin (val)) - { - return -1; - } - else - /* Convert `short' and `char' to full-size `int'. */ - parmval = default_conversion (val); - - (*values)[parmnum] = parmval; - if (parmval == error_mark_node) - error_args = true; - - if (!type && builtin_type && TREE_CODE (builtin_type) != VOID_TYPE) - { - /* For a call to a built-in function declared without a prototype, - perform the conversions from the argument to the expected type - but issue warnings rather than errors for any mismatches. - Ignore the converted argument and use the PARMVAL obtained - above by applying default conversions instead. */ - tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum]; - convert_argument (ploc, function, fundecl, builtin_type, origtype, - val, valtype, npc, rname, parmnum, argnum, - excess_precision, - OPT_Wbuiltin_declaration_mismatch); - } - - if (typetail) - typetail = TREE_CHAIN (typetail); - - if (builtin_typetail) - builtin_typetail = TREE_CHAIN (builtin_typetail); - } - - gcc_assert (parmnum == vec_safe_length (values)); - - if (typetail != NULL_TREE && TREE_VALUE (typetail) != void_type_node) - { - error_at (loc, "too few arguments to function %qE", function); - inform_declaration (fundecl); - return -1; - } - - if (builtin_typetail && TREE_VALUE (builtin_typetail) != void_type_node) - { - unsigned nargs = parmnum; - for (tree t = builtin_typetail; t; t = TREE_CHAIN (t)) - ++nargs; - - if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch, - "too few arguments to built-in function %qE " - "expecting %u", function, nargs - 1)) - inform_declaration (fundecl); - } - - return error_args ? -1 : (int) parmnum; -} - -/* This is the entry point used by the parser to build unary operators - in the input. CODE, a tree_code, specifies the unary operator, and - ARG is the operand. For unary plus, the C parser currently uses - CONVERT_EXPR for code. - - LOC is the location to use for the tree generated. -*/ - -struct c_expr -parser_build_unary_op (location_t loc, enum tree_code code, struct c_expr arg) -{ - struct c_expr result; - - result.original_code = code; - result.original_type = NULL; - - if (reject_gcc_builtin (arg.value)) - { - result.value = error_mark_node; - } - else - { - result.value = build_unary_op (loc, code, arg.value, false); - - if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value)) - overflow_warning (loc, result.value, arg.value); - } - - /* We are typically called when parsing a prefix token at LOC acting on - ARG. Reflect this by updating the source range of the result to - start at LOC and end at the end of ARG. */ - set_c_expr_source_range (&result, - loc, arg.get_finish ()); - - return result; -} - -/* Returns true if TYPE is a character type, *not* including wchar_t. */ - -bool -char_type_p (tree type) -{ - return (type == char_type_node - || type == unsigned_char_type_node - || type == signed_char_type_node - || type == char16_type_node - || type == char32_type_node); -} - -/* This is the entry point used by the parser to build binary operators - in the input. CODE, a tree_code, specifies the binary operator, and - ARG1 and ARG2 are the operands. In addition to constructing the - expression, we check for operands that were written with other binary - operators in a way that is likely to confuse the user. - - LOCATION is the location of the binary operator. */ - -struct c_expr -parser_build_binary_op (location_t location, enum tree_code code, - struct c_expr arg1, struct c_expr arg2) -{ - struct c_expr result; - - enum tree_code code1 = arg1.original_code; - enum tree_code code2 = arg2.original_code; - tree type1 = (arg1.original_type - ? arg1.original_type - : TREE_TYPE (arg1.value)); - tree type2 = (arg2.original_type - ? arg2.original_type - : TREE_TYPE (arg2.value)); - - result.value = build_binary_op (location, code, - arg1.value, arg2.value, true); - result.original_code = code; - result.original_type = NULL; - - if (TREE_CODE (result.value) == ERROR_MARK) - { - set_c_expr_source_range (&result, - arg1.get_start (), - arg2.get_finish ()); - return result; - } - - if (location != UNKNOWN_LOCATION) - protected_set_expr_location (result.value, location); - - set_c_expr_source_range (&result, - arg1.get_start (), - arg2.get_finish ()); - - /* Check for cases such as x+y< used in subtraction"); - if (TREE_CODE (target_type) == FUNCTION_TYPE) - pedwarn (loc, OPT_Wpointer_arith, - "pointer to a function used in subtraction"); - - if (current_function_decl != NULL_TREE - && sanitize_flags_p (SANITIZE_POINTER_SUBTRACT)) - { - op0 = save_expr (op0); - op1 = save_expr (op1); - - tree tt = builtin_decl_explicit (BUILT_IN_ASAN_POINTER_SUBTRACT); - *instrument_expr = build_call_expr_loc (loc, tt, 2, op0, op1); - } - - /* First do the subtraction, then build the divide operator - and only convert at the very end. - Do not do default conversions in case restype is a short type. */ - - /* POINTER_DIFF_EXPR requires a signed integer type of the same size as - pointers. If some platform cannot provide that, or has a larger - ptrdiff_type to support differences larger than half the address - space, cast the pointers to some larger integer type and do the - computations in that type. */ - if (TYPE_PRECISION (inttype) > TYPE_PRECISION (TREE_TYPE (op0))) - op0 = build_binary_op (loc, MINUS_EXPR, convert (inttype, op0), - convert (inttype, op1), false); - else - { - /* Cast away qualifiers. */ - op0 = convert (c_common_type (TREE_TYPE (op0), TREE_TYPE (op0)), op0); - op1 = convert (c_common_type (TREE_TYPE (op1), TREE_TYPE (op1)), op1); - op0 = build2_loc (loc, POINTER_DIFF_EXPR, inttype, op0, op1); - } - - /* This generates an error if op1 is pointer to incomplete type. */ - if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1)))) - error_at (loc, "arithmetic on pointer to an incomplete type"); - else if (verify_type_context (loc, TCTX_POINTER_ARITH, - TREE_TYPE (TREE_TYPE (orig_op0)))) - verify_type_context (loc, TCTX_POINTER_ARITH, - TREE_TYPE (TREE_TYPE (orig_op1))); - - op1 = c_size_in_bytes (target_type); - - if (pointer_to_zero_sized_aggr_p (TREE_TYPE (orig_op1))) - error_at (loc, "arithmetic on pointer to an empty aggregate"); - - /* Divide by the size, in easiest possible way. */ - result = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype, - op0, convert (inttype, op1)); - - /* Convert to final result type if necessary. */ - return convert (restype, result); -} - -/* Expand atomic compound assignments into an appropriate sequence as - specified by the C11 standard section 6.5.16.2. - - _Atomic T1 E1 - T2 E2 - E1 op= E2 - - This sequence is used for all types for which these operations are - supported. - - In addition, built-in versions of the 'fe' prefixed routines may - need to be invoked for floating point (real, complex or vector) when - floating-point exceptions are supported. See 6.5.16.2 footnote 113. - - T1 newval; - T1 old; - T1 *addr - T2 val - fenv_t fenv - - addr = &E1; - val = (E2); - __atomic_load (addr, &old, SEQ_CST); - feholdexcept (&fenv); -loop: - newval = old op val; - if (__atomic_compare_exchange_strong (addr, &old, &newval, SEQ_CST, - SEQ_CST)) - goto done; - feclearexcept (FE_ALL_EXCEPT); - goto loop: -done: - feupdateenv (&fenv); - - The compiler will issue the __atomic_fetch_* built-in when possible, - otherwise it will generate the generic form of the atomic operations. - This requires temp(s) and has their address taken. The atomic processing - is smart enough to figure out when the size of an object can utilize - a lock-free version, and convert the built-in call to the appropriate - lock-free routine. The optimizers will then dispose of any temps that - are no longer required, and lock-free implementations are utilized as - long as there is target support for the required size. - - If the operator is NOP_EXPR, then this is a simple assignment, and - an __atomic_store is issued to perform the assignment rather than - the above loop. */ - -/* Build an atomic assignment at LOC, expanding into the proper - sequence to store LHS MODIFYCODE= RHS. Return a value representing - the result of the operation, unless RETURN_OLD_P, in which case - return the old value of LHS (this is only for postincrement and - postdecrement). */ - -static tree -build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode, - tree rhs, bool return_old_p) -{ - tree fndecl, func_call; - vec *params; - tree val, nonatomic_lhs_type, nonatomic_rhs_type, newval, newval_addr; - tree old, old_addr; - tree compound_stmt = NULL_TREE; - tree stmt, goto_stmt; - tree loop_label, loop_decl, done_label, done_decl; - - tree lhs_type = TREE_TYPE (lhs); - tree lhs_addr = build_unary_op (loc, ADDR_EXPR, lhs, false); - tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); - tree rhs_semantic_type = TREE_TYPE (rhs); - tree nonatomic_rhs_semantic_type; - tree rhs_type; - - gcc_assert (TYPE_ATOMIC (lhs_type)); - - if (return_old_p) - gcc_assert (modifycode == PLUS_EXPR || modifycode == MINUS_EXPR); - - /* Allocate enough vector items for a compare_exchange. */ - vec_alloc (params, 6); - - /* Create a compound statement to hold the sequence of statements - with a loop. */ - if (modifycode != NOP_EXPR) - { - compound_stmt = c_begin_compound_stmt (false); - - /* For consistency with build_modify_expr on non-_Atomic, - mark the lhs as read. Also, it would be very hard to match - such expressions in mark_exp_read. */ - mark_exp_read (lhs); - } - - /* Remove any excess precision (which is only present here in the - case of compound assignments). */ - if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) - { - gcc_assert (modifycode != NOP_EXPR); - rhs = TREE_OPERAND (rhs, 0); - } - rhs_type = TREE_TYPE (rhs); - - /* Fold the RHS if it hasn't already been folded. */ - if (modifycode != NOP_EXPR) - rhs = c_fully_fold (rhs, false, NULL); - - /* Remove the qualifiers for the rest of the expressions and create - the VAL temp variable to hold the RHS. */ - nonatomic_lhs_type = build_qualified_type (lhs_type, TYPE_UNQUALIFIED); - nonatomic_rhs_type = build_qualified_type (rhs_type, TYPE_UNQUALIFIED); - nonatomic_rhs_semantic_type = build_qualified_type (rhs_semantic_type, - TYPE_UNQUALIFIED); - val = create_tmp_var_raw (nonatomic_rhs_type); - TREE_ADDRESSABLE (val) = 1; - suppress_warning (val); - rhs = build4 (TARGET_EXPR, nonatomic_rhs_type, val, rhs, NULL_TREE, - NULL_TREE); - TREE_SIDE_EFFECTS (rhs) = 1; - SET_EXPR_LOCATION (rhs, loc); - if (modifycode != NOP_EXPR) - add_stmt (rhs); - - /* NOP_EXPR indicates it's a straight store of the RHS. Simply issue - an atomic_store. */ - if (modifycode == NOP_EXPR) - { - compound_stmt = rhs; - /* Build __atomic_store (&lhs, &val, SEQ_CST) */ - rhs = build_unary_op (loc, ADDR_EXPR, val, false); - fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_STORE); - params->quick_push (lhs_addr); - params->quick_push (rhs); - params->quick_push (seq_cst); - func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); - - compound_stmt = build2 (COMPOUND_EXPR, void_type_node, - compound_stmt, func_call); - - /* VAL is the value which was stored, return a COMPOUND_STMT of - the statement and that value. */ - return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt, val); - } - - /* Attempt to implement the atomic operation as an __atomic_fetch_* or - __atomic_*_fetch built-in rather than a CAS loop. atomic_bool type - isn't applicable for such builtins. ??? Do we want to handle enums? */ - if ((TREE_CODE (lhs_type) == INTEGER_TYPE || POINTER_TYPE_P (lhs_type)) - && TREE_CODE (rhs_type) == INTEGER_TYPE) - { - built_in_function fncode; - switch (modifycode) - { - case PLUS_EXPR: - case POINTER_PLUS_EXPR: - fncode = (return_old_p - ? BUILT_IN_ATOMIC_FETCH_ADD_N - : BUILT_IN_ATOMIC_ADD_FETCH_N); - break; - case MINUS_EXPR: - fncode = (return_old_p - ? BUILT_IN_ATOMIC_FETCH_SUB_N - : BUILT_IN_ATOMIC_SUB_FETCH_N); - break; - case BIT_AND_EXPR: - fncode = (return_old_p - ? BUILT_IN_ATOMIC_FETCH_AND_N - : BUILT_IN_ATOMIC_AND_FETCH_N); - break; - case BIT_IOR_EXPR: - fncode = (return_old_p - ? BUILT_IN_ATOMIC_FETCH_OR_N - : BUILT_IN_ATOMIC_OR_FETCH_N); - break; - case BIT_XOR_EXPR: - fncode = (return_old_p - ? BUILT_IN_ATOMIC_FETCH_XOR_N - : BUILT_IN_ATOMIC_XOR_FETCH_N); - break; - default: - goto cas_loop; - } - - /* We can only use "_1" through "_16" variants of the atomic fetch - built-ins. */ - unsigned HOST_WIDE_INT size = tree_to_uhwi (TYPE_SIZE_UNIT (lhs_type)); - if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) - goto cas_loop; - - /* If this is a pointer type, we need to multiply by the size of - the pointer target type. */ - if (POINTER_TYPE_P (lhs_type)) - { - if (!COMPLETE_TYPE_P (TREE_TYPE (lhs_type)) - /* ??? This would introduce -Wdiscarded-qualifiers - warning: __atomic_fetch_* expect volatile void * - type as the first argument. (Assignments between - atomic and non-atomic objects are OK.) */ - || TYPE_RESTRICT (lhs_type)) - goto cas_loop; - tree sz = TYPE_SIZE_UNIT (TREE_TYPE (lhs_type)); - rhs = fold_build2_loc (loc, MULT_EXPR, ptrdiff_type_node, - convert (ptrdiff_type_node, rhs), - convert (ptrdiff_type_node, sz)); - } - - /* Build __atomic_fetch_* (&lhs, &val, SEQ_CST), or - __atomic_*_fetch (&lhs, &val, SEQ_CST). */ - fndecl = builtin_decl_explicit (fncode); - params->quick_push (lhs_addr); - params->quick_push (rhs); - params->quick_push (seq_cst); - func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); - - newval = create_tmp_var_raw (nonatomic_lhs_type); - TREE_ADDRESSABLE (newval) = 1; - suppress_warning (newval); - rhs = build4 (TARGET_EXPR, nonatomic_lhs_type, newval, func_call, - NULL_TREE, NULL_TREE); - SET_EXPR_LOCATION (rhs, loc); - add_stmt (rhs); - - /* Finish the compound statement. */ - compound_stmt = c_end_compound_stmt (loc, compound_stmt, false); - - /* NEWVAL is the value which was stored, return a COMPOUND_STMT of - the statement and that value. */ - return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt, newval); - } - -cas_loop: - /* Create the variables and labels required for the op= form. */ - old = create_tmp_var_raw (nonatomic_lhs_type); - old_addr = build_unary_op (loc, ADDR_EXPR, old, false); - TREE_ADDRESSABLE (old) = 1; - suppress_warning (old); - - newval = create_tmp_var_raw (nonatomic_lhs_type); - newval_addr = build_unary_op (loc, ADDR_EXPR, newval, false); - TREE_ADDRESSABLE (newval) = 1; - suppress_warning (newval); - - loop_decl = create_artificial_label (loc); - loop_label = build1 (LABEL_EXPR, void_type_node, loop_decl); - - done_decl = create_artificial_label (loc); - done_label = build1 (LABEL_EXPR, void_type_node, done_decl); - - /* __atomic_load (addr, &old, SEQ_CST). */ - fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD); - params->quick_push (lhs_addr); - params->quick_push (old_addr); - params->quick_push (seq_cst); - func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); - old = build4 (TARGET_EXPR, nonatomic_lhs_type, old, func_call, NULL_TREE, - NULL_TREE); - add_stmt (old); - params->truncate (0); - - /* Create the expressions for floating-point environment - manipulation, if required. */ - bool need_fenv = (flag_trapping_math - && (FLOAT_TYPE_P (lhs_type) || FLOAT_TYPE_P (rhs_type))); - tree hold_call = NULL_TREE, clear_call = NULL_TREE, update_call = NULL_TREE; - if (need_fenv) - targetm.atomic_assign_expand_fenv (&hold_call, &clear_call, &update_call); - - if (hold_call) - add_stmt (hold_call); - - /* loop: */ - add_stmt (loop_label); - - /* newval = old + val; */ - if (rhs_type != rhs_semantic_type) - val = build1 (EXCESS_PRECISION_EXPR, nonatomic_rhs_semantic_type, val); - rhs = build_binary_op (loc, modifycode, old, val, true); - if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) - { - tree eptype = TREE_TYPE (rhs); - rhs = c_fully_fold (TREE_OPERAND (rhs, 0), false, NULL); - rhs = build1 (EXCESS_PRECISION_EXPR, eptype, rhs); - } - else - rhs = c_fully_fold (rhs, false, NULL); - rhs = convert_for_assignment (loc, UNKNOWN_LOCATION, nonatomic_lhs_type, - rhs, NULL_TREE, ic_assign, false, NULL_TREE, - NULL_TREE, 0); - if (rhs != error_mark_node) - { - rhs = build4 (TARGET_EXPR, nonatomic_lhs_type, newval, rhs, NULL_TREE, - NULL_TREE); - SET_EXPR_LOCATION (rhs, loc); - add_stmt (rhs); - } - - /* if (__atomic_compare_exchange (addr, &old, &new, false, SEQ_CST, SEQ_CST)) - goto done; */ - fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_COMPARE_EXCHANGE); - params->quick_push (lhs_addr); - params->quick_push (old_addr); - params->quick_push (newval_addr); - params->quick_push (integer_zero_node); - params->quick_push (seq_cst); - params->quick_push (seq_cst); - func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); - - goto_stmt = build1 (GOTO_EXPR, void_type_node, done_decl); - SET_EXPR_LOCATION (goto_stmt, loc); - - stmt = build3 (COND_EXPR, void_type_node, func_call, goto_stmt, NULL_TREE); - SET_EXPR_LOCATION (stmt, loc); - add_stmt (stmt); - - if (clear_call) - add_stmt (clear_call); - - /* goto loop; */ - goto_stmt = build1 (GOTO_EXPR, void_type_node, loop_decl); - SET_EXPR_LOCATION (goto_stmt, loc); - add_stmt (goto_stmt); - - /* done: */ - add_stmt (done_label); - - if (update_call) - add_stmt (update_call); - - /* Finish the compound statement. */ - compound_stmt = c_end_compound_stmt (loc, compound_stmt, false); - - /* NEWVAL is the value that was successfully stored, return a - COMPOUND_EXPR of the statement and the appropriate value. */ - return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt, - return_old_p ? old : newval); -} - -/* Construct and perhaps optimize a tree representation - for a unary operation. CODE, a tree_code, specifies the operation - and XARG is the operand. - For any CODE other than ADDR_EXPR, NOCONVERT suppresses the default - promotions (such as from short to int). - For ADDR_EXPR, the default promotions are not applied; NOCONVERT allows - non-lvalues; this is only used to handle conversion of non-lvalue arrays - to pointers in C99. - - LOCATION is the location of the operator. */ - -tree -build_unary_op (location_t location, enum tree_code code, tree xarg, - bool noconvert) -{ - /* No default_conversion here. It causes trouble for ADDR_EXPR. */ - tree arg = xarg; - tree argtype = NULL_TREE; - enum tree_code typecode; - tree val; - tree ret = error_mark_node; - tree eptype = NULL_TREE; - const char *invalid_op_diag; - bool int_operands; - - int_operands = EXPR_INT_CONST_OPERANDS (xarg); - if (int_operands) - arg = remove_c_maybe_const_expr (arg); - - if (code != ADDR_EXPR) - arg = require_complete_type (location, arg); - - typecode = TREE_CODE (TREE_TYPE (arg)); - if (typecode == ERROR_MARK) - return error_mark_node; - if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE) - typecode = INTEGER_TYPE; - - if ((invalid_op_diag - = targetm.invalid_unary_op (code, TREE_TYPE (xarg)))) - { - error_at (location, invalid_op_diag); - return error_mark_node; - } - - if (TREE_CODE (arg) == EXCESS_PRECISION_EXPR) - { - eptype = TREE_TYPE (arg); - arg = TREE_OPERAND (arg, 0); - } - - switch (code) - { - case CONVERT_EXPR: - /* This is used for unary plus, because a CONVERT_EXPR - is enough to prevent anybody from looking inside for - associativity, but won't generate any code. */ - if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE - || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE - || gnu_vector_type_p (TREE_TYPE (arg)))) - { - error_at (location, "wrong type argument to unary plus"); - return error_mark_node; - } - else if (!noconvert) - arg = default_conversion (arg); - arg = non_lvalue_loc (location, arg); - break; - - case NEGATE_EXPR: - if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE - || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE - || gnu_vector_type_p (TREE_TYPE (arg)))) - { - error_at (location, "wrong type argument to unary minus"); - return error_mark_node; - } - else if (!noconvert) - arg = default_conversion (arg); - break; - - case BIT_NOT_EXPR: - /* ~ works on integer types and non float vectors. */ - if (typecode == INTEGER_TYPE - || (gnu_vector_type_p (TREE_TYPE (arg)) - && !VECTOR_FLOAT_TYPE_P (TREE_TYPE (arg)))) - { - tree e = arg; - - /* Warn if the expression has boolean value. */ - while (TREE_CODE (e) == COMPOUND_EXPR) - e = TREE_OPERAND (e, 1); - - if ((TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE - || truth_value_p (TREE_CODE (e)))) - { - auto_diagnostic_group d; - if (warning_at (location, OPT_Wbool_operation, - "%<~%> on a boolean expression")) - { - gcc_rich_location richloc (location); - richloc.add_fixit_insert_before (location, "!"); - inform (&richloc, "did you mean to use logical not?"); - } - } - if (!noconvert) - arg = default_conversion (arg); - } - else if (typecode == COMPLEX_TYPE) - { - code = CONJ_EXPR; - pedwarn (location, OPT_Wpedantic, - "ISO C does not support %<~%> for complex conjugation"); - if (!noconvert) - arg = default_conversion (arg); - } - else - { - error_at (location, "wrong type argument to bit-complement"); - return error_mark_node; - } - break; - - case ABS_EXPR: - if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE)) - { - error_at (location, "wrong type argument to abs"); - return error_mark_node; - } - else if (!noconvert) - arg = default_conversion (arg); - break; - - case ABSU_EXPR: - if (!(typecode == INTEGER_TYPE)) - { - error_at (location, "wrong type argument to absu"); - return error_mark_node; - } - else if (!noconvert) - arg = default_conversion (arg); - break; - - case CONJ_EXPR: - /* Conjugating a real value is a no-op, but allow it anyway. */ - if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE - || typecode == COMPLEX_TYPE)) - { - error_at (location, "wrong type argument to conjugation"); - return error_mark_node; - } - else if (!noconvert) - arg = default_conversion (arg); - break; - - case TRUTH_NOT_EXPR: - if (typecode != INTEGER_TYPE && typecode != FIXED_POINT_TYPE - && typecode != REAL_TYPE && typecode != POINTER_TYPE - && typecode != COMPLEX_TYPE) - { - error_at (location, - "wrong type argument to unary exclamation mark"); - return error_mark_node; - } - if (int_operands) - { - arg = c_objc_common_truthvalue_conversion (location, xarg); - arg = remove_c_maybe_const_expr (arg); - } - else - arg = c_objc_common_truthvalue_conversion (location, arg); - ret = invert_truthvalue_loc (location, arg); - /* If the TRUTH_NOT_EXPR has been folded, reset the location. */ - if (EXPR_P (ret) && EXPR_HAS_LOCATION (ret)) - location = EXPR_LOCATION (ret); - goto return_build_unary_op; - - case REALPART_EXPR: - case IMAGPART_EXPR: - ret = build_real_imag_expr (location, code, arg); - if (ret == error_mark_node) - return error_mark_node; - if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE) - eptype = TREE_TYPE (eptype); - goto return_build_unary_op; - - case PREINCREMENT_EXPR: - case POSTINCREMENT_EXPR: - case PREDECREMENT_EXPR: - case POSTDECREMENT_EXPR: - - if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR) - { - tree inner = build_unary_op (location, code, - C_MAYBE_CONST_EXPR_EXPR (arg), - noconvert); - if (inner == error_mark_node) - return error_mark_node; - ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner), - C_MAYBE_CONST_EXPR_PRE (arg), inner); - gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg)); - C_MAYBE_CONST_EXPR_NON_CONST (ret) = 1; - goto return_build_unary_op; - } - - /* Complain about anything that is not a true lvalue. In - Objective-C, skip this check for property_refs. */ - if (!objc_is_property_ref (arg) - && !lvalue_or_else (location, - arg, ((code == PREINCREMENT_EXPR - || code == POSTINCREMENT_EXPR) - ? lv_increment - : lv_decrement))) - return error_mark_node; - - if (warn_cxx_compat && TREE_CODE (TREE_TYPE (arg)) == ENUMERAL_TYPE) - { - if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) - warning_at (location, OPT_Wc___compat, - "increment of enumeration value is invalid in C++"); - else - warning_at (location, OPT_Wc___compat, - "decrement of enumeration value is invalid in C++"); - } - - if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) - { - if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) - warning_at (location, OPT_Wbool_operation, - "increment of a boolean expression"); - else - warning_at (location, OPT_Wbool_operation, - "decrement of a boolean expression"); - } - - /* Ensure the argument is fully folded inside any SAVE_EXPR. */ - arg = c_fully_fold (arg, false, NULL, true); - - bool atomic_op; - atomic_op = really_atomic_lvalue (arg); - - /* Increment or decrement the real part of the value, - and don't change the imaginary part. */ - if (typecode == COMPLEX_TYPE) - { - tree real, imag; - - pedwarn (location, OPT_Wpedantic, - "ISO C does not support %<++%> and %<--%> on complex types"); - - if (!atomic_op) - { - arg = stabilize_reference (arg); - real = build_unary_op (EXPR_LOCATION (arg), REALPART_EXPR, arg, - true); - imag = build_unary_op (EXPR_LOCATION (arg), IMAGPART_EXPR, arg, - true); - real = build_unary_op (EXPR_LOCATION (arg), code, real, true); - if (real == error_mark_node || imag == error_mark_node) - return error_mark_node; - ret = build2 (COMPLEX_EXPR, TREE_TYPE (arg), - real, imag); - goto return_build_unary_op; - } - } - - /* Report invalid types. */ - - if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE - && typecode != INTEGER_TYPE && typecode != REAL_TYPE - && typecode != COMPLEX_TYPE - && !gnu_vector_type_p (TREE_TYPE (arg))) - { - if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) - error_at (location, "wrong type argument to increment"); - else - error_at (location, "wrong type argument to decrement"); - - return error_mark_node; - } - - { - tree inc; - - argtype = TREE_TYPE (arg); - - /* Compute the increment. */ - - if (typecode == POINTER_TYPE) - { - /* If pointer target is an incomplete type, - we just cannot know how to do the arithmetic. */ - if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (argtype))) - { - if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) - error_at (location, - "increment of pointer to an incomplete type %qT", - TREE_TYPE (argtype)); - else - error_at (location, - "decrement of pointer to an incomplete type %qT", - TREE_TYPE (argtype)); - } - else if (TREE_CODE (TREE_TYPE (argtype)) == FUNCTION_TYPE - || TREE_CODE (TREE_TYPE (argtype)) == VOID_TYPE) - { - if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) - pedwarn (location, OPT_Wpointer_arith, - "wrong type argument to increment"); - else - pedwarn (location, OPT_Wpointer_arith, - "wrong type argument to decrement"); - } - else - verify_type_context (location, TCTX_POINTER_ARITH, - TREE_TYPE (argtype)); - - inc = c_size_in_bytes (TREE_TYPE (argtype)); - inc = convert_to_ptrofftype_loc (location, inc); - } - else if (FRACT_MODE_P (TYPE_MODE (argtype))) - { - /* For signed fract types, we invert ++ to -- or - -- to ++, and change inc from 1 to -1, because - it is not possible to represent 1 in signed fract constants. - For unsigned fract types, the result always overflows and - we get an undefined (original) or the maximum value. */ - if (code == PREINCREMENT_EXPR) - code = PREDECREMENT_EXPR; - else if (code == PREDECREMENT_EXPR) - code = PREINCREMENT_EXPR; - else if (code == POSTINCREMENT_EXPR) - code = POSTDECREMENT_EXPR; - else /* code == POSTDECREMENT_EXPR */ - code = POSTINCREMENT_EXPR; - - inc = integer_minus_one_node; - inc = convert (argtype, inc); - } - else - { - inc = VECTOR_TYPE_P (argtype) - ? build_one_cst (argtype) - : integer_one_node; - inc = convert (argtype, inc); - } - - /* If 'arg' is an Objective-C PROPERTY_REF expression, then we - need to ask Objective-C to build the increment or decrement - expression for it. */ - if (objc_is_property_ref (arg)) - return objc_build_incr_expr_for_property_ref (location, code, - arg, inc); - - /* Report a read-only lvalue. */ - if (TYPE_READONLY (argtype)) - { - readonly_error (location, arg, - ((code == PREINCREMENT_EXPR - || code == POSTINCREMENT_EXPR) - ? lv_increment : lv_decrement)); - return error_mark_node; - } - else if (TREE_READONLY (arg)) - readonly_warning (arg, - ((code == PREINCREMENT_EXPR - || code == POSTINCREMENT_EXPR) - ? lv_increment : lv_decrement)); - - /* If the argument is atomic, use the special code sequences for - atomic compound assignment. */ - if (atomic_op) - { - arg = stabilize_reference (arg); - ret = build_atomic_assign (location, arg, - ((code == PREINCREMENT_EXPR - || code == POSTINCREMENT_EXPR) - ? PLUS_EXPR - : MINUS_EXPR), - (FRACT_MODE_P (TYPE_MODE (argtype)) - ? inc - : integer_one_node), - (code == POSTINCREMENT_EXPR - || code == POSTDECREMENT_EXPR)); - goto return_build_unary_op; - } - - if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) - val = boolean_increment (code, arg); - else - val = build2 (code, TREE_TYPE (arg), arg, inc); - TREE_SIDE_EFFECTS (val) = 1; - ret = val; - goto return_build_unary_op; - } - - case ADDR_EXPR: - /* Note that this operation never does default_conversion. */ - - /* The operand of unary '&' must be an lvalue (which excludes - expressions of type void), or, in C99, the result of a [] or - unary '*' operator. */ - if (VOID_TYPE_P (TREE_TYPE (arg)) - && TYPE_QUALS (TREE_TYPE (arg)) == TYPE_UNQUALIFIED - && (!INDIRECT_REF_P (arg) || !flag_isoc99)) - pedwarn (location, 0, "taking address of expression of type %"); - - /* Let &* cancel out to simplify resulting code. */ - if (INDIRECT_REF_P (arg)) - { - /* Don't let this be an lvalue. */ - if (lvalue_p (TREE_OPERAND (arg, 0))) - return non_lvalue_loc (location, TREE_OPERAND (arg, 0)); - ret = TREE_OPERAND (arg, 0); - goto return_build_unary_op; - } - - /* Anything not already handled and not a true memory reference - or a non-lvalue array is an error. */ - if (typecode != FUNCTION_TYPE && !noconvert - && !lvalue_or_else (location, arg, lv_addressof)) - return error_mark_node; - - /* Move address operations inside C_MAYBE_CONST_EXPR to simplify - folding later. */ - if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR) - { - tree inner = build_unary_op (location, code, - C_MAYBE_CONST_EXPR_EXPR (arg), - noconvert); - ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner), - C_MAYBE_CONST_EXPR_PRE (arg), inner); - gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg)); - C_MAYBE_CONST_EXPR_NON_CONST (ret) - = C_MAYBE_CONST_EXPR_NON_CONST (arg); - goto return_build_unary_op; - } - - /* Ordinary case; arg is a COMPONENT_REF or a decl. */ - argtype = TREE_TYPE (arg); - - /* If the lvalue is const or volatile, merge that into the type - to which the address will point. This is only needed - for function types. */ - if ((DECL_P (arg) || REFERENCE_CLASS_P (arg)) - && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)) - && TREE_CODE (argtype) == FUNCTION_TYPE) - { - int orig_quals = TYPE_QUALS (strip_array_types (argtype)); - int quals = orig_quals; - - if (TREE_READONLY (arg)) - quals |= TYPE_QUAL_CONST; - if (TREE_THIS_VOLATILE (arg)) - quals |= TYPE_QUAL_VOLATILE; - - argtype = c_build_qualified_type (argtype, quals); - } - - switch (TREE_CODE (arg)) - { - case COMPONENT_REF: - if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1))) - { - error_at (location, "cannot take address of bit-field %qD", - TREE_OPERAND (arg, 1)); - return error_mark_node; - } - - /* fall through */ - - case ARRAY_REF: - if (TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (TREE_OPERAND (arg, 0)))) - { - if (!AGGREGATE_TYPE_P (TREE_TYPE (arg)) - && !POINTER_TYPE_P (TREE_TYPE (arg)) - && !VECTOR_TYPE_P (TREE_TYPE (arg))) - { - error_at (location, "cannot take address of scalar with " - "reverse storage order"); - return error_mark_node; - } - - if (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE - && TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (arg))) - warning_at (location, OPT_Wscalar_storage_order, - "address of array with reverse scalar storage " - "order requested"); - } - - default: - break; - } - - if (!c_mark_addressable (arg)) - return error_mark_node; - - gcc_assert (TREE_CODE (arg) != COMPONENT_REF - || !DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1))); - - argtype = build_pointer_type (argtype); - - /* ??? Cope with user tricks that amount to offsetof. Delete this - when we have proper support for integer constant expressions. */ - val = get_base_address (arg); - if (val && INDIRECT_REF_P (val) - && TREE_CONSTANT (TREE_OPERAND (val, 0))) - { - ret = fold_offsetof (arg, argtype); - goto return_build_unary_op; - } - - val = build1 (ADDR_EXPR, argtype, arg); - - ret = val; - goto return_build_unary_op; - - default: - gcc_unreachable (); - } - - if (argtype == NULL_TREE) - argtype = TREE_TYPE (arg); - if (TREE_CODE (arg) == INTEGER_CST) - ret = (require_constant_value - ? fold_build1_initializer_loc (location, code, argtype, arg) - : fold_build1_loc (location, code, argtype, arg)); - else - ret = build1 (code, argtype, arg); - return_build_unary_op: - gcc_assert (ret != error_mark_node); - if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret) - && !(TREE_CODE (xarg) == INTEGER_CST && !TREE_OVERFLOW (xarg))) - ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret); - else if (TREE_CODE (ret) != INTEGER_CST && int_operands) - ret = note_integer_operands (ret); - if (eptype) - ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret); - protected_set_expr_location (ret, location); - return ret; -} - -/* Return nonzero if REF is an lvalue valid for this language. - Lvalues can be assigned, unless their type has TYPE_READONLY. - Lvalues can have their address taken, unless they have C_DECL_REGISTER. */ - -bool -lvalue_p (const_tree ref) -{ - const enum tree_code code = TREE_CODE (ref); - - switch (code) - { - case REALPART_EXPR: - case IMAGPART_EXPR: - case COMPONENT_REF: - return lvalue_p (TREE_OPERAND (ref, 0)); - - case C_MAYBE_CONST_EXPR: - return lvalue_p (TREE_OPERAND (ref, 1)); - - case COMPOUND_LITERAL_EXPR: - case STRING_CST: - return true; - - case MEM_REF: - case TARGET_MEM_REF: - /* MEM_REFs can appear from -fgimple parsing or folding, so allow them - here as well. */ - case INDIRECT_REF: - case ARRAY_REF: - case VAR_DECL: - case PARM_DECL: - case RESULT_DECL: - case ERROR_MARK: - return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE - && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE); - - case BIND_EXPR: - return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE; - - default: - return false; - } -} - -/* Give a warning for storing in something that is read-only in GCC - terms but not const in ISO C terms. */ - -static void -readonly_warning (tree arg, enum lvalue_use use) -{ - switch (use) - { - case lv_assign: - warning (0, "assignment of read-only location %qE", arg); - break; - case lv_increment: - warning (0, "increment of read-only location %qE", arg); - break; - case lv_decrement: - warning (0, "decrement of read-only location %qE", arg); - break; - default: - gcc_unreachable (); - } - return; -} - - -/* Return nonzero if REF is an lvalue valid for this language; - otherwise, print an error message and return zero. USE says - how the lvalue is being used and so selects the error message. - LOCATION is the location at which any error should be reported. */ - -static int -lvalue_or_else (location_t loc, const_tree ref, enum lvalue_use use) -{ - int win = lvalue_p (ref); - - if (!win) - lvalue_error (loc, use); - - return win; -} - -/* Mark EXP saying that we need to be able to take the - address of it; it should not be allocated in a register. - Returns true if successful. ARRAY_REF_P is true if this - is for ARRAY_REF construction - in that case we don't want - to look through VIEW_CONVERT_EXPR from VECTOR_TYPE to ARRAY_TYPE, - it is fine to use ARRAY_REFs for vector subscripts on vector - register variables. */ - -bool -c_mark_addressable (tree exp, bool array_ref_p) -{ - tree x = exp; - - while (1) - switch (TREE_CODE (x)) - { - case VIEW_CONVERT_EXPR: - if (array_ref_p - && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE - && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0)))) - return true; - x = TREE_OPERAND (x, 0); - break; - - case COMPONENT_REF: - if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1))) - { - error ("cannot take address of bit-field %qD", - TREE_OPERAND (x, 1)); - return false; - } - /* FALLTHRU */ - case ADDR_EXPR: - case ARRAY_REF: - case REALPART_EXPR: - case IMAGPART_EXPR: - x = TREE_OPERAND (x, 0); - break; - - case COMPOUND_LITERAL_EXPR: - TREE_ADDRESSABLE (x) = 1; - TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (x)) = 1; - return true; - - case CONSTRUCTOR: - TREE_ADDRESSABLE (x) = 1; - return true; - - case VAR_DECL: - case CONST_DECL: - case PARM_DECL: - case RESULT_DECL: - if (C_DECL_REGISTER (x) - && DECL_NONLOCAL (x)) - { - if (TREE_PUBLIC (x) || is_global_var (x)) - { - error - ("global register variable %qD used in nested function", x); - return false; - } - pedwarn (input_location, 0, "register variable %qD used in nested function", x); - } - else if (C_DECL_REGISTER (x)) - { - if (TREE_PUBLIC (x) || is_global_var (x)) - error ("address of global register variable %qD requested", x); - else - error ("address of register variable %qD requested", x); - return false; - } - - /* FALLTHRU */ - case FUNCTION_DECL: - TREE_ADDRESSABLE (x) = 1; - /* FALLTHRU */ - default: - return true; - } -} - -/* Convert EXPR to TYPE, warning about conversion problems with - constants. SEMANTIC_TYPE is the type this conversion would use - without excess precision. If SEMANTIC_TYPE is NULL, this function - is equivalent to convert_and_check. This function is a wrapper that - handles conversions that may be different than - the usual ones because of excess precision. */ - -static tree -ep_convert_and_check (location_t loc, tree type, tree expr, - tree semantic_type) -{ - if (TREE_TYPE (expr) == type) - return expr; - - /* For C11, integer conversions may have results with excess - precision. */ - if (flag_isoc11 || !semantic_type) - return convert_and_check (loc, type, expr); - - if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE - && TREE_TYPE (expr) != semantic_type) - { - /* For integers, we need to check the real conversion, not - the conversion to the excess precision type. */ - expr = convert_and_check (loc, semantic_type, expr); - } - /* Result type is the excess precision type, which should be - large enough, so do not check. */ - return convert (type, expr); -} - -/* If EXPR refers to a built-in declared without a prototype returns - the actual type of the built-in and, if non-null, set *BLTIN to - a pointer to the built-in. Otherwise return the type of EXPR - and clear *BLTIN if non-null. */ - -static tree -type_or_builtin_type (tree expr, tree *bltin = NULL) -{ - tree dummy; - if (!bltin) - bltin = &dummy; - - *bltin = NULL_TREE; - - tree type = TREE_TYPE (expr); - if (TREE_CODE (expr) != ADDR_EXPR) - return type; - - tree oper = TREE_OPERAND (expr, 0); - if (!DECL_P (oper) - || TREE_CODE (oper) != FUNCTION_DECL - || !fndecl_built_in_p (oper, BUILT_IN_NORMAL)) - return type; - - built_in_function code = DECL_FUNCTION_CODE (oper); - if (!C_DECL_BUILTIN_PROTOTYPE (oper)) - return type; - - if ((*bltin = builtin_decl_implicit (code))) - type = build_pointer_type (TREE_TYPE (*bltin)); - - return type; -} - -/* Build and return a conditional expression IFEXP ? OP1 : OP2. If - IFEXP_BCP then the condition is a call to __builtin_constant_p, and - if folded to an integer constant then the unselected half may - contain arbitrary operations not normally permitted in constant - expressions. Set the location of the expression to LOC. */ - -tree -build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, - tree op1, tree op1_original_type, location_t op1_loc, - tree op2, tree op2_original_type, location_t op2_loc) -{ - tree type1; - tree type2; - enum tree_code code1; - enum tree_code code2; - tree result_type = NULL; - tree semantic_result_type = NULL; - tree orig_op1 = op1, orig_op2 = op2; - bool int_const, op1_int_operands, op2_int_operands, int_operands; - bool ifexp_int_operands; - tree ret; - - op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1); - if (op1_int_operands) - op1 = remove_c_maybe_const_expr (op1); - op2_int_operands = EXPR_INT_CONST_OPERANDS (orig_op2); - if (op2_int_operands) - op2 = remove_c_maybe_const_expr (op2); - ifexp_int_operands = EXPR_INT_CONST_OPERANDS (ifexp); - if (ifexp_int_operands) - ifexp = remove_c_maybe_const_expr (ifexp); - - /* Promote both alternatives. */ - - if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE) - op1 = default_conversion (op1); - if (TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE) - op2 = default_conversion (op2); - - if (TREE_CODE (ifexp) == ERROR_MARK - || TREE_CODE (TREE_TYPE (op1)) == ERROR_MARK - || TREE_CODE (TREE_TYPE (op2)) == ERROR_MARK) - return error_mark_node; - - tree bltin1 = NULL_TREE; - tree bltin2 = NULL_TREE; - type1 = type_or_builtin_type (op1, &bltin1); - code1 = TREE_CODE (type1); - type2 = type_or_builtin_type (op2, &bltin2); - code2 = TREE_CODE (type2); - - if (code1 == POINTER_TYPE && reject_gcc_builtin (op1)) - return error_mark_node; - - if (code2 == POINTER_TYPE && reject_gcc_builtin (op2)) - return error_mark_node; - - /* C90 does not permit non-lvalue arrays in conditional expressions. - In C99 they will be pointers by now. */ - if (code1 == ARRAY_TYPE || code2 == ARRAY_TYPE) - { - error_at (colon_loc, "non-lvalue array in conditional expression"); - return error_mark_node; - } - - if ((TREE_CODE (op1) == EXCESS_PRECISION_EXPR - || TREE_CODE (op2) == EXCESS_PRECISION_EXPR) - && (code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == COMPLEX_TYPE) - && (code2 == INTEGER_TYPE || code2 == REAL_TYPE - || code2 == COMPLEX_TYPE)) - { - semantic_result_type = c_common_type (type1, type2); - if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR) - { - op1 = TREE_OPERAND (op1, 0); - type1 = TREE_TYPE (op1); - gcc_assert (TREE_CODE (type1) == code1); - } - if (TREE_CODE (op2) == EXCESS_PRECISION_EXPR) - { - op2 = TREE_OPERAND (op2, 0); - type2 = TREE_TYPE (op2); - gcc_assert (TREE_CODE (type2) == code2); - } - } - - if (warn_cxx_compat) - { - tree t1 = op1_original_type ? op1_original_type : TREE_TYPE (orig_op1); - tree t2 = op2_original_type ? op2_original_type : TREE_TYPE (orig_op2); - - if (TREE_CODE (t1) == ENUMERAL_TYPE - && TREE_CODE (t2) == ENUMERAL_TYPE - && TYPE_MAIN_VARIANT (t1) != TYPE_MAIN_VARIANT (t2)) - warning_at (colon_loc, OPT_Wc___compat, - ("different enum types in conditional is " - "invalid in C++: %qT vs %qT"), - t1, t2); - } - - /* Quickly detect the usual case where op1 and op2 have the same type - after promotion. */ - if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)) - { - if (type1 == type2) - result_type = type1; - else - result_type = TYPE_MAIN_VARIANT (type1); - } - else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == COMPLEX_TYPE) - && (code2 == INTEGER_TYPE || code2 == REAL_TYPE - || code2 == COMPLEX_TYPE)) - { - /* In C11, a conditional expression between a floating-point - type and an integer type should convert the integer type to - the evaluation format of the floating-point type, with - possible excess precision. */ - tree eptype1 = type1; - tree eptype2 = type2; - if (flag_isoc11) - { - tree eptype; - if (ANY_INTEGRAL_TYPE_P (type1) - && (eptype = excess_precision_type (type2)) != NULL_TREE) - { - eptype2 = eptype; - if (!semantic_result_type) - semantic_result_type = c_common_type (type1, type2); - } - else if (ANY_INTEGRAL_TYPE_P (type2) - && (eptype = excess_precision_type (type1)) != NULL_TREE) - { - eptype1 = eptype; - if (!semantic_result_type) - semantic_result_type = c_common_type (type1, type2); - } - } - result_type = c_common_type (eptype1, eptype2); - if (result_type == error_mark_node) - return error_mark_node; - do_warn_double_promotion (result_type, type1, type2, - "implicit conversion from %qT to %qT to " - "match other result of conditional", - colon_loc); - - /* If -Wsign-compare, warn here if type1 and type2 have - different signedness. We'll promote the signed to unsigned - and later code won't know it used to be different. - Do this check on the original types, so that explicit casts - will be considered, but default promotions won't. */ - if (c_inhibit_evaluation_warnings == 0) - { - int unsigned_op1 = TYPE_UNSIGNED (TREE_TYPE (orig_op1)); - int unsigned_op2 = TYPE_UNSIGNED (TREE_TYPE (orig_op2)); - - if (unsigned_op1 ^ unsigned_op2) - { - bool ovf; - - /* Do not warn if the result type is signed, since the - signed type will only be chosen if it can represent - all the values of the unsigned type. */ - if (!TYPE_UNSIGNED (result_type)) - /* OK */; - else - { - bool op1_maybe_const = true; - bool op2_maybe_const = true; - - /* Do not warn if the signed quantity is an - unsuffixed integer literal (or some static - constant expression involving such literals) and - it is non-negative. This warning requires the - operands to be folded for best results, so do - that folding in this case even without - warn_sign_compare to avoid warning options - possibly affecting code generation. */ - c_inhibit_evaluation_warnings - += (ifexp == truthvalue_false_node); - op1 = c_fully_fold (op1, require_constant_value, - &op1_maybe_const); - c_inhibit_evaluation_warnings - -= (ifexp == truthvalue_false_node); - - c_inhibit_evaluation_warnings - += (ifexp == truthvalue_true_node); - op2 = c_fully_fold (op2, require_constant_value, - &op2_maybe_const); - c_inhibit_evaluation_warnings - -= (ifexp == truthvalue_true_node); - - if (warn_sign_compare) - { - if ((unsigned_op2 - && tree_expr_nonnegative_warnv_p (op1, &ovf)) - || (unsigned_op1 - && tree_expr_nonnegative_warnv_p (op2, &ovf))) - /* OK */; - else if (unsigned_op2) - warning_at (op1_loc, OPT_Wsign_compare, - "operand of % changes signedness from " - "%qT to %qT due to unsignedness of other " - "operand", TREE_TYPE (orig_op1), - TREE_TYPE (orig_op2)); - else - warning_at (op2_loc, OPT_Wsign_compare, - "operand of % changes signedness from " - "%qT to %qT due to unsignedness of other " - "operand", TREE_TYPE (orig_op2), - TREE_TYPE (orig_op1)); - } - if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST) - op1 = c_wrap_maybe_const (op1, !op1_maybe_const); - if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST) - op2 = c_wrap_maybe_const (op2, !op2_maybe_const); - } - } - } - } - else if (code1 == VOID_TYPE || code2 == VOID_TYPE) - { - if (code1 != VOID_TYPE || code2 != VOID_TYPE) - pedwarn (colon_loc, OPT_Wpedantic, - "ISO C forbids conditional expr with only one void side"); - result_type = void_type_node; - } - else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE) - { - addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); - addr_space_t as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2)); - addr_space_t as_common; - - if (comp_target_types (colon_loc, type1, type2)) - result_type = common_pointer_type (type1, type2); - else if (null_pointer_constant_p (orig_op1)) - result_type = type2; - else if (null_pointer_constant_p (orig_op2)) - result_type = type1; - else if (!addr_space_superset (as1, as2, &as_common)) - { - error_at (colon_loc, "pointers to disjoint address spaces " - "used in conditional expression"); - return error_mark_node; - } - else if ((VOID_TYPE_P (TREE_TYPE (type1)) - && !TYPE_ATOMIC (TREE_TYPE (type1))) - || (VOID_TYPE_P (TREE_TYPE (type2)) - && !TYPE_ATOMIC (TREE_TYPE (type2)))) - { - tree t1 = TREE_TYPE (type1); - tree t2 = TREE_TYPE (type2); - if (!(VOID_TYPE_P (t1) - && !TYPE_ATOMIC (t1))) - { - /* roles are swapped */ - t1 = t2; - t2 = TREE_TYPE (type1); - } - tree t2_stripped = strip_array_types (t2); - if ((TREE_CODE (t2) == ARRAY_TYPE) - && (TYPE_QUALS (t2_stripped) & ~TYPE_QUALS (t1))) - { - if (!flag_isoc2x) - warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers, - "pointer to array loses qualifier " - "in conditional expression"); - else if (warn_c11_c2x_compat > 0) - warning_at (colon_loc, OPT_Wc11_c2x_compat, - "pointer to array loses qualifier " - "in conditional expression in ISO C before C2X"); - } - if (TREE_CODE (t2) == FUNCTION_TYPE) - pedwarn (colon_loc, OPT_Wpedantic, - "ISO C forbids conditional expr between " - "% and function pointer"); - /* for array, use qualifiers of element type */ - if (flag_isoc2x) - t2 = t2_stripped; - result_type = build_pointer_type (qualify_type (t1, t2)); - } - /* Objective-C pointer comparisons are a bit more lenient. */ - else if (objc_have_common_type (type1, type2, -3, NULL_TREE)) - result_type = objc_common_type (type1, type2); - else - { - int qual = ENCODE_QUAL_ADDR_SPACE (as_common); - if (bltin1 && bltin2) - warning_at (colon_loc, OPT_Wincompatible_pointer_types, - "pointer type mismatch between %qT and %qT " - "of %qD and %qD in conditional expression", - type1, type2, bltin1, bltin2); - else - pedwarn (colon_loc, 0, - "pointer type mismatch in conditional expression"); - result_type = build_pointer_type - (build_qualified_type (void_type_node, qual)); - } - } - else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) - { - if (!null_pointer_constant_p (orig_op2)) - pedwarn (colon_loc, 0, - "pointer/integer type mismatch in conditional expression"); - else - { - op2 = null_pointer_node; - } - result_type = type1; - } - else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE) - { - if (!null_pointer_constant_p (orig_op1)) - pedwarn (colon_loc, 0, - "pointer/integer type mismatch in conditional expression"); - else - { - op1 = null_pointer_node; - } - result_type = type2; - } - - if (!result_type) - { - if (flag_cond_mismatch) - result_type = void_type_node; - else - { - error_at (colon_loc, "type mismatch in conditional expression"); - return error_mark_node; - } - } - - /* Merge const and volatile flags of the incoming types. */ - result_type - = build_type_variant (result_type, - TYPE_READONLY (type1) || TYPE_READONLY (type2), - TYPE_VOLATILE (type1) || TYPE_VOLATILE (type2)); - - op1 = ep_convert_and_check (colon_loc, result_type, op1, - semantic_result_type); - op2 = ep_convert_and_check (colon_loc, result_type, op2, - semantic_result_type); - - if (ifexp_bcp && ifexp == truthvalue_true_node) - { - op2_int_operands = true; - op1 = c_fully_fold (op1, require_constant_value, NULL); - } - if (ifexp_bcp && ifexp == truthvalue_false_node) - { - op1_int_operands = true; - op2 = c_fully_fold (op2, require_constant_value, NULL); - } - int_const = int_operands = (ifexp_int_operands - && op1_int_operands - && op2_int_operands); - if (int_operands) - { - int_const = ((ifexp == truthvalue_true_node - && TREE_CODE (orig_op1) == INTEGER_CST - && !TREE_OVERFLOW (orig_op1)) - || (ifexp == truthvalue_false_node - && TREE_CODE (orig_op2) == INTEGER_CST - && !TREE_OVERFLOW (orig_op2))); - } - - /* Need to convert condition operand into a vector mask. */ - if (VECTOR_TYPE_P (TREE_TYPE (ifexp))) - { - tree vectype = TREE_TYPE (ifexp); - tree elem_type = TREE_TYPE (vectype); - tree zero = build_int_cst (elem_type, 0); - tree zero_vec = build_vector_from_val (vectype, zero); - tree cmp_type = truth_type_for (vectype); - ifexp = build2 (NE_EXPR, cmp_type, ifexp, zero_vec); - } - - if (int_const || (ifexp_bcp && TREE_CODE (ifexp) == INTEGER_CST)) - ret = fold_build3_loc (colon_loc, COND_EXPR, result_type, ifexp, op1, op2); - else - { - if (int_operands) - { - /* Use c_fully_fold here, since C_MAYBE_CONST_EXPR might be - nested inside of the expression. */ - op1 = c_fully_fold (op1, false, NULL); - op2 = c_fully_fold (op2, false, NULL); - } - ret = build3 (COND_EXPR, result_type, ifexp, op1, op2); - if (int_operands) - ret = note_integer_operands (ret); - } - if (semantic_result_type) - ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret); - - protected_set_expr_location (ret, colon_loc); - - /* If the OP1 and OP2 are the same and don't have side-effects, - warn here, because the COND_EXPR will be turned into OP1. */ - if (warn_duplicated_branches - && TREE_CODE (ret) == COND_EXPR - && (op1 == op2 || operand_equal_p (op1, op2, OEP_ADDRESS_OF_SAME_FIELD))) - warning_at (EXPR_LOCATION (ret), OPT_Wduplicated_branches, - "this condition has identical branches"); - - return ret; -} - -/* EXPR is an expression, location LOC, whose result is discarded. - Warn if it is a call to a nodiscard function (or a COMPOUND_EXPR - whose right-hand operand is such a call, possibly recursively). */ - -static void -maybe_warn_nodiscard (location_t loc, tree expr) -{ - if (VOID_TYPE_P (TREE_TYPE (expr))) - return; - while (TREE_CODE (expr) == COMPOUND_EXPR) - { - expr = TREE_OPERAND (expr, 1); - if (EXPR_HAS_LOCATION (expr)) - loc = EXPR_LOCATION (expr); - } - if (TREE_CODE (expr) != CALL_EXPR) - return; - tree fn = CALL_EXPR_FN (expr); - if (!fn) - return; - tree attr; - if (TREE_CODE (fn) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL - && (attr = lookup_attribute ("nodiscard", - DECL_ATTRIBUTES (TREE_OPERAND (fn, 0))))) - { - fn = TREE_OPERAND (fn, 0); - tree args = TREE_VALUE (attr); - if (args) - args = TREE_VALUE (args); - auto_diagnostic_group d; - int warned; - if (args) - warned = warning_at (loc, OPT_Wunused_result, - "ignoring return value of %qD, declared with " - "attribute %: %E", fn, args); - else - warned = warning_at (loc, OPT_Wunused_result, - "ignoring return value of %qD, declared with " - "attribute %", fn); - if (warned) - inform (DECL_SOURCE_LOCATION (fn), "declared here"); - } - else - { - tree rettype = TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))); - attr = lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype)); - if (!attr) - return; - tree args = TREE_VALUE (attr); - if (args) - args = TREE_VALUE (args); - auto_diagnostic_group d; - int warned; - if (args) - warned = warning_at (loc, OPT_Wunused_result, - "ignoring return value of type %qT, declared " - "with attribute %: %E", - rettype, args); - else - warned = warning_at (loc, OPT_Wunused_result, - "ignoring return value of type %qT, declared " - "with attribute %", rettype); - if (warned) - { - if (TREE_CODE (fn) == ADDR_EXPR) - { - fn = TREE_OPERAND (fn, 0); - if (TREE_CODE (fn) == FUNCTION_DECL) - inform (DECL_SOURCE_LOCATION (fn), - "in call to %qD, declared here", fn); - } - } - } -} - -/* Return a compound expression that performs two expressions and - returns the value of the second of them. - - LOC is the location of the COMPOUND_EXPR. */ - -tree -build_compound_expr (location_t loc, tree expr1, tree expr2) -{ - bool expr1_int_operands, expr2_int_operands; - tree eptype = NULL_TREE; - tree ret; - - expr1_int_operands = EXPR_INT_CONST_OPERANDS (expr1); - if (expr1_int_operands) - expr1 = remove_c_maybe_const_expr (expr1); - expr2_int_operands = EXPR_INT_CONST_OPERANDS (expr2); - if (expr2_int_operands) - expr2 = remove_c_maybe_const_expr (expr2); - - if (TREE_CODE (expr1) == EXCESS_PRECISION_EXPR) - expr1 = TREE_OPERAND (expr1, 0); - if (TREE_CODE (expr2) == EXCESS_PRECISION_EXPR) - { - eptype = TREE_TYPE (expr2); - expr2 = TREE_OPERAND (expr2, 0); - } - - if (!TREE_SIDE_EFFECTS (expr1)) - { - /* The left-hand operand of a comma expression is like an expression - statement: with -Wunused, we should warn if it doesn't have - any side-effects, unless it was explicitly cast to (void). */ - if (warn_unused_value) - { - if (VOID_TYPE_P (TREE_TYPE (expr1)) - && CONVERT_EXPR_P (expr1)) - ; /* (void) a, b */ - else if (VOID_TYPE_P (TREE_TYPE (expr1)) - && TREE_CODE (expr1) == COMPOUND_EXPR - && CONVERT_EXPR_P (TREE_OPERAND (expr1, 1))) - ; /* (void) a, (void) b, c */ - else - warning_at (loc, OPT_Wunused_value, - "left-hand operand of comma expression has no effect"); - } - } - else if (TREE_CODE (expr1) == COMPOUND_EXPR - && warn_unused_value) - { - tree r = expr1; - location_t cloc = loc; - while (TREE_CODE (r) == COMPOUND_EXPR) - { - if (EXPR_HAS_LOCATION (r)) - cloc = EXPR_LOCATION (r); - r = TREE_OPERAND (r, 1); - } - if (!TREE_SIDE_EFFECTS (r) - && !VOID_TYPE_P (TREE_TYPE (r)) - && !CONVERT_EXPR_P (r)) - warning_at (cloc, OPT_Wunused_value, - "right-hand operand of comma expression has no effect"); - } - - /* With -Wunused, we should also warn if the left-hand operand does have - side-effects, but computes a value which is not used. For example, in - `foo() + bar(), baz()' the result of the `+' operator is not used, - so we should issue a warning. */ - else if (warn_unused_value) - warn_if_unused_value (expr1, loc); - - maybe_warn_nodiscard (loc, expr1); - - if (expr2 == error_mark_node) - return error_mark_node; - - ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2); - - if (flag_isoc99 - && expr1_int_operands - && expr2_int_operands) - ret = note_integer_operands (ret); - - if (eptype) - ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret); - - protected_set_expr_location (ret, loc); - return ret; -} - -/* Issue -Wcast-qual warnings when appropriate. TYPE is the type to - which we are casting. OTYPE is the type of the expression being - cast. Both TYPE and OTYPE are pointer types. LOC is the location - of the cast. -Wcast-qual appeared on the command line. Named - address space qualifiers are not handled here, because they result - in different warnings. */ - -static void -handle_warn_cast_qual (location_t loc, tree type, tree otype) -{ - tree in_type = type; - tree in_otype = otype; - int added = 0; - int discarded = 0; - bool is_const; - - /* Check that the qualifiers on IN_TYPE are a superset of the - qualifiers of IN_OTYPE. The outermost level of POINTER_TYPE - nodes is uninteresting and we stop as soon as we hit a - non-POINTER_TYPE node on either type. */ - do - { - in_otype = TREE_TYPE (in_otype); - in_type = TREE_TYPE (in_type); - - /* GNU C allows cv-qualified function types. 'const' means the - function is very pure, 'volatile' means it can't return. We - need to warn when such qualifiers are added, not when they're - taken away. */ - if (TREE_CODE (in_otype) == FUNCTION_TYPE - && TREE_CODE (in_type) == FUNCTION_TYPE) - added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type) - & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype)); - else - discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype) - & ~TYPE_QUALS_NO_ADDR_SPACE (in_type)); - } - while (TREE_CODE (in_type) == POINTER_TYPE - && TREE_CODE (in_otype) == POINTER_TYPE); - - if (added) - warning_at (loc, OPT_Wcast_qual, - "cast adds %q#v qualifier to function type", added); - - if (discarded) - /* There are qualifiers present in IN_OTYPE that are not present - in IN_TYPE. */ - warning_at (loc, OPT_Wcast_qual, - "cast discards %qv qualifier from pointer target type", - discarded); - - if (added || discarded) - return; - - /* A cast from **T to const **T is unsafe, because it can cause a - const value to be changed with no additional warning. We only - issue this warning if T is the same on both sides, and we only - issue the warning if there are the same number of pointers on - both sides, as otherwise the cast is clearly unsafe anyhow. A - cast is unsafe when a qualifier is added at one level and const - is not present at all outer levels. - - To issue this warning, we check at each level whether the cast - adds new qualifiers not already seen. We don't need to special - case function types, as they won't have the same - TYPE_MAIN_VARIANT. */ - - if (TYPE_MAIN_VARIANT (in_type) != TYPE_MAIN_VARIANT (in_otype)) - return; - if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE) - return; - - in_type = type; - in_otype = otype; - is_const = TYPE_READONLY (TREE_TYPE (in_type)); - do - { - in_type = TREE_TYPE (in_type); - in_otype = TREE_TYPE (in_otype); - if ((TYPE_QUALS (in_type) &~ TYPE_QUALS (in_otype)) != 0 - && !is_const) - { - warning_at (loc, OPT_Wcast_qual, - "to be safe all intermediate pointers in cast from " - "%qT to %qT must be % qualified", - otype, type); - break; - } - if (is_const) - is_const = TYPE_READONLY (in_type); - } - while (TREE_CODE (in_type) == POINTER_TYPE); -} - -/* Heuristic check if two parameter types can be considered ABI-equivalent. */ - -static bool -c_safe_arg_type_equiv_p (tree t1, tree t2) -{ - t1 = TYPE_MAIN_VARIANT (t1); - t2 = TYPE_MAIN_VARIANT (t2); - - if (TREE_CODE (t1) == POINTER_TYPE - && TREE_CODE (t2) == POINTER_TYPE) - return true; - - /* The signedness of the parameter matters only when an integral - type smaller than int is promoted to int, otherwise only the - precision of the parameter matters. - This check should make sure that the callee does not see - undefined values in argument registers. */ - if (INTEGRAL_TYPE_P (t1) - && INTEGRAL_TYPE_P (t2) - && TYPE_PRECISION (t1) == TYPE_PRECISION (t2) - && (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2) - || !targetm.calls.promote_prototypes (NULL_TREE) - || TYPE_PRECISION (t1) >= TYPE_PRECISION (integer_type_node))) - return true; - - return comptypes (t1, t2); -} - -/* Check if a type cast between two function types can be considered safe. */ - -static bool -c_safe_function_type_cast_p (tree t1, tree t2) -{ - if (TREE_TYPE (t1) == void_type_node && - TYPE_ARG_TYPES (t1) == void_list_node) - return true; - - if (TREE_TYPE (t2) == void_type_node && - TYPE_ARG_TYPES (t2) == void_list_node) - return true; - - if (!c_safe_arg_type_equiv_p (TREE_TYPE (t1), TREE_TYPE (t2))) - return false; - - for (t1 = TYPE_ARG_TYPES (t1), t2 = TYPE_ARG_TYPES (t2); - t1 && t2; - t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) - if (!c_safe_arg_type_equiv_p (TREE_VALUE (t1), TREE_VALUE (t2))) - return false; - - return true; -} - -/* Build an expression representing a cast to type TYPE of expression EXPR. - LOC is the location of the cast-- typically the open paren of the cast. */ - -tree -build_c_cast (location_t loc, tree type, tree expr) -{ - tree value; - - bool int_operands = EXPR_INT_CONST_OPERANDS (expr); - - if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) - expr = TREE_OPERAND (expr, 0); - - value = expr; - if (int_operands) - value = remove_c_maybe_const_expr (value); - - if (type == error_mark_node || expr == error_mark_node) - return error_mark_node; - - /* The ObjC front-end uses TYPE_MAIN_VARIANT to tie together types differing - only in qualifications. But when constructing cast expressions, - the protocols do matter and must be kept around. */ - if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr))) - return build1 (NOP_EXPR, type, expr); - - type = TYPE_MAIN_VARIANT (type); - - if (TREE_CODE (type) == ARRAY_TYPE) - { - error_at (loc, "cast specifies array type"); - return error_mark_node; - } - - if (TREE_CODE (type) == FUNCTION_TYPE) - { - error_at (loc, "cast specifies function type"); - return error_mark_node; - } - - if (!VOID_TYPE_P (type)) - { - value = require_complete_type (loc, value); - if (value == error_mark_node) - return error_mark_node; - } - - if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value))) - { - if (RECORD_OR_UNION_TYPE_P (type)) - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids casting nonscalar to the same type"); - - /* Convert to remove any qualifiers from VALUE's type. */ - value = convert (type, value); - } - else if (TREE_CODE (type) == UNION_TYPE) - { - tree field; - - for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) - if (TREE_TYPE (field) != error_mark_node - && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)), - TYPE_MAIN_VARIANT (TREE_TYPE (value)))) - break; - - if (field) - { - tree t; - bool maybe_const = true; - - pedwarn (loc, OPT_Wpedantic, "ISO C forbids casts to union type"); - t = c_fully_fold (value, false, &maybe_const); - t = build_constructor_single (type, field, t); - if (!maybe_const) - t = c_wrap_maybe_const (t, true); - t = digest_init (loc, type, t, - NULL_TREE, false, true, 0); - TREE_CONSTANT (t) = TREE_CONSTANT (value); - return t; - } - error_at (loc, "cast to union type from type not present in union"); - return error_mark_node; - } - else - { - tree otype, ovalue; - - if (type == void_type_node) - { - tree t = build1 (CONVERT_EXPR, type, value); - SET_EXPR_LOCATION (t, loc); - return t; - } - - otype = TREE_TYPE (value); - - /* Optionally warn about potentially worrisome casts. */ - if (warn_cast_qual - && TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (otype) == POINTER_TYPE) - handle_warn_cast_qual (loc, type, otype); - - /* Warn about conversions between pointers to disjoint - address spaces. */ - if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (otype) == POINTER_TYPE - && !null_pointer_constant_p (value)) - { - addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type)); - addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype)); - addr_space_t as_common; - - if (!addr_space_superset (as_to, as_from, &as_common)) - { - if (ADDR_SPACE_GENERIC_P (as_from)) - warning_at (loc, 0, "cast to %s address space pointer " - "from disjoint generic address space pointer", - c_addr_space_name (as_to)); - - else if (ADDR_SPACE_GENERIC_P (as_to)) - warning_at (loc, 0, "cast to generic address space pointer " - "from disjoint %s address space pointer", - c_addr_space_name (as_from)); - - else - warning_at (loc, 0, "cast to %s address space pointer " - "from disjoint %s address space pointer", - c_addr_space_name (as_to), - c_addr_space_name (as_from)); - } - } - - /* Warn about possible alignment problems. */ - if ((STRICT_ALIGNMENT || warn_cast_align == 2) - && TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (otype) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE - && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE - /* Don't warn about opaque types, where the actual alignment - restriction is unknown. */ - && !(RECORD_OR_UNION_TYPE_P (TREE_TYPE (otype)) - && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode) - && min_align_of_type (TREE_TYPE (type)) - > min_align_of_type (TREE_TYPE (otype))) - warning_at (loc, OPT_Wcast_align, - "cast increases required alignment of target type"); - - if (TREE_CODE (type) == INTEGER_TYPE - && TREE_CODE (otype) == POINTER_TYPE - && TYPE_PRECISION (type) != TYPE_PRECISION (otype)) - /* Unlike conversion of integers to pointers, where the - warning is disabled for converting constants because - of cases such as SIG_*, warn about converting constant - pointers to integers. In some cases it may cause unwanted - sign extension, and a warning is appropriate. */ - warning_at (loc, OPT_Wpointer_to_int_cast, - "cast from pointer to integer of different size"); - - if (TREE_CODE (value) == CALL_EXPR - && TREE_CODE (type) != TREE_CODE (otype)) - warning_at (loc, OPT_Wbad_function_cast, - "cast from function call of type %qT " - "to non-matching type %qT", otype, type); - - if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (otype) == INTEGER_TYPE - && TYPE_PRECISION (type) != TYPE_PRECISION (otype) - /* Don't warn about converting any constant. */ - && !TREE_CONSTANT (value)) - warning_at (loc, - OPT_Wint_to_pointer_cast, "cast to pointer from integer " - "of different size"); - - if (warn_strict_aliasing <= 2) - strict_aliasing_warning (EXPR_LOCATION (value), type, expr); - - /* If pedantic, warn for conversions between function and object - pointer types, except for converting a null pointer constant - to function pointer type. */ - if (pedantic - && TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (otype) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE - && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE) - pedwarn (loc, OPT_Wpedantic, "ISO C forbids " - "conversion of function pointer to object pointer type"); - - if (pedantic - && TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (otype) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE - && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE - && !null_pointer_constant_p (value)) - pedwarn (loc, OPT_Wpedantic, "ISO C forbids " - "conversion of object pointer to function pointer type"); - - if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (otype) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE - && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE - && !c_safe_function_type_cast_p (TREE_TYPE (type), - TREE_TYPE (otype))) - warning_at (loc, OPT_Wcast_function_type, - "cast between incompatible function types" - " from %qT to %qT", otype, type); - - ovalue = value; - value = convert (type, value); - - /* Ignore any integer overflow caused by the cast. */ - if (TREE_CODE (value) == INTEGER_CST && !FLOAT_TYPE_P (otype)) - { - if (CONSTANT_CLASS_P (ovalue) && TREE_OVERFLOW (ovalue)) - { - if (!TREE_OVERFLOW (value)) - { - /* Avoid clobbering a shared constant. */ - value = copy_node (value); - TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue); - } - } - else if (TREE_OVERFLOW (value)) - /* Reset VALUE's overflow flags, ensuring constant sharing. */ - value = wide_int_to_tree (TREE_TYPE (value), wi::to_wide (value)); - } - } - - /* Don't let a cast be an lvalue. */ - if (lvalue_p (value)) - value = non_lvalue_loc (loc, value); - - /* Don't allow the results of casting to floating-point or complex - types be confused with actual constants, or casts involving - integer and pointer types other than direct integer-to-integer - and integer-to-pointer be confused with integer constant - expressions and null pointer constants. */ - if (TREE_CODE (value) == REAL_CST - || TREE_CODE (value) == COMPLEX_CST - || (TREE_CODE (value) == INTEGER_CST - && !((TREE_CODE (expr) == INTEGER_CST - && INTEGRAL_TYPE_P (TREE_TYPE (expr))) - || TREE_CODE (expr) == REAL_CST - || TREE_CODE (expr) == COMPLEX_CST))) - value = build1 (NOP_EXPR, type, value); - - /* If the expression has integer operands and so can occur in an - unevaluated part of an integer constant expression, ensure the - return value reflects this. */ - if (int_operands - && INTEGRAL_TYPE_P (type) - && value != error_mark_node - && !EXPR_INT_CONST_OPERANDS (value)) - value = note_integer_operands (value); - - protected_set_expr_location (value, loc); - return value; -} - -/* Interpret a cast of expression EXPR to type TYPE. LOC is the - location of the open paren of the cast, or the position of the cast - expr. */ -tree -c_cast_expr (location_t loc, struct c_type_name *type_name, tree expr) -{ - tree type; - tree type_expr = NULL_TREE; - bool type_expr_const = true; - tree ret; - int saved_wsp = warn_strict_prototypes; - - /* This avoids warnings about unprototyped casts on - integers. E.g. "#define SIG_DFL (void(*)())0". */ - if (TREE_CODE (expr) == INTEGER_CST) - warn_strict_prototypes = 0; - type = groktypename (type_name, &type_expr, &type_expr_const); - warn_strict_prototypes = saved_wsp; - - if (TREE_CODE (expr) == ADDR_EXPR && !VOID_TYPE_P (type) - && reject_gcc_builtin (expr)) - return error_mark_node; - - ret = build_c_cast (loc, type, expr); - if (type_expr) - { - bool inner_expr_const = true; - ret = c_fully_fold (ret, require_constant_value, &inner_expr_const); - ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret), type_expr, ret); - C_MAYBE_CONST_EXPR_NON_CONST (ret) = !(type_expr_const - && inner_expr_const); - SET_EXPR_LOCATION (ret, loc); - } - - if (!EXPR_HAS_LOCATION (ret)) - protected_set_expr_location (ret, loc); - - /* C++ does not permits types to be defined in a cast, but it - allows references to incomplete types. */ - if (warn_cxx_compat && type_name->specs->typespec_kind == ctsk_tagdef) - warning_at (loc, OPT_Wc___compat, - "defining a type in a cast is invalid in C++"); - - return ret; -} - -/* Build an assignment expression of lvalue LHS from value RHS. - If LHS_ORIGTYPE is not NULL, it is the original type of LHS, which - may differ from TREE_TYPE (LHS) for an enum bitfield. - MODIFYCODE is the code for a binary operator that we use - to combine the old value of LHS with RHS to get the new value. - Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment. - If RHS_ORIGTYPE is not NULL_TREE, it is the original type of RHS, - which may differ from TREE_TYPE (RHS) for an enum value. - - LOCATION is the location of the MODIFYCODE operator. - RHS_LOC is the location of the RHS. */ - -tree -build_modify_expr (location_t location, tree lhs, tree lhs_origtype, - enum tree_code modifycode, - location_t rhs_loc, tree rhs, tree rhs_origtype) -{ - tree result; - tree newrhs; - tree rhseval = NULL_TREE; - tree lhstype = TREE_TYPE (lhs); - tree olhstype = lhstype; - bool npc; - bool is_atomic_op; - - /* Types that aren't fully specified cannot be used in assignments. */ - lhs = require_complete_type (location, lhs); - - /* Avoid duplicate error messages from operands that had errors. */ - if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK) - return error_mark_node; - - /* Ensure an error for assigning a non-lvalue array to an array in - C90. */ - if (TREE_CODE (lhstype) == ARRAY_TYPE) - { - error_at (location, "assignment to expression with array type"); - return error_mark_node; - } - - /* For ObjC properties, defer this check. */ - if (!objc_is_property_ref (lhs) && !lvalue_or_else (location, lhs, lv_assign)) - return error_mark_node; - - is_atomic_op = really_atomic_lvalue (lhs); - - newrhs = rhs; - - if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR) - { - tree inner = build_modify_expr (location, C_MAYBE_CONST_EXPR_EXPR (lhs), - lhs_origtype, modifycode, rhs_loc, rhs, - rhs_origtype); - if (inner == error_mark_node) - return error_mark_node; - result = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner), - C_MAYBE_CONST_EXPR_PRE (lhs), inner); - gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (lhs)); - C_MAYBE_CONST_EXPR_NON_CONST (result) = 1; - protected_set_expr_location (result, location); - return result; - } - - /* If a binary op has been requested, combine the old LHS value with the RHS - producing the value we should actually store into the LHS. */ - - if (modifycode != NOP_EXPR) - { - lhs = c_fully_fold (lhs, false, NULL, true); - lhs = stabilize_reference (lhs); - - /* Construct the RHS for any non-atomic compound assignemnt. */ - if (!is_atomic_op) - { - /* If in LHS op= RHS the RHS has side-effects, ensure they - are preevaluated before the rest of the assignment expression's - side-effects, because RHS could contain e.g. function calls - that modify LHS. */ - if (TREE_SIDE_EFFECTS (rhs)) - { - if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) - newrhs = save_expr (TREE_OPERAND (rhs, 0)); - else - newrhs = save_expr (rhs); - rhseval = newrhs; - if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) - newrhs = build1 (EXCESS_PRECISION_EXPR, TREE_TYPE (rhs), - newrhs); - } - newrhs = build_binary_op (location, - modifycode, lhs, newrhs, true); - - /* The original type of the right hand side is no longer - meaningful. */ - rhs_origtype = NULL_TREE; - } - } - - if (c_dialect_objc ()) - { - /* Check if we are modifying an Objective-C property reference; - if so, we need to generate setter calls. */ - if (TREE_CODE (newrhs) == EXCESS_PRECISION_EXPR) - result = objc_maybe_build_modify_expr (lhs, TREE_OPERAND (newrhs, 0)); - else - result = objc_maybe_build_modify_expr (lhs, newrhs); - if (result) - goto return_result; - - /* Else, do the check that we postponed for Objective-C. */ - if (!lvalue_or_else (location, lhs, lv_assign)) - return error_mark_node; - } - - /* Give an error for storing in something that is 'const'. */ - - if (TYPE_READONLY (lhstype) - || (RECORD_OR_UNION_TYPE_P (lhstype) - && C_TYPE_FIELDS_READONLY (lhstype))) - { - readonly_error (location, lhs, lv_assign); - return error_mark_node; - } - else if (TREE_READONLY (lhs)) - readonly_warning (lhs, lv_assign); - - /* If storing into a structure or union member, - it has probably been given type `int'. - Compute the type that would go with - the actual amount of storage the member occupies. */ - - if (TREE_CODE (lhs) == COMPONENT_REF - && (TREE_CODE (lhstype) == INTEGER_TYPE - || TREE_CODE (lhstype) == BOOLEAN_TYPE - || TREE_CODE (lhstype) == REAL_TYPE - || TREE_CODE (lhstype) == ENUMERAL_TYPE)) - lhstype = TREE_TYPE (get_unwidened (lhs, 0)); - - /* If storing in a field that is in actuality a short or narrower than one, - we must store in the field in its actual type. */ - - if (lhstype != TREE_TYPE (lhs)) - { - lhs = copy_node (lhs); - TREE_TYPE (lhs) = lhstype; - } - - /* Issue -Wc++-compat warnings about an assignment to an enum type - when LHS does not have its original type. This happens for, - e.g., an enum bitfield in a struct. */ - if (warn_cxx_compat - && lhs_origtype != NULL_TREE - && lhs_origtype != lhstype - && TREE_CODE (lhs_origtype) == ENUMERAL_TYPE) - { - tree checktype = (rhs_origtype != NULL_TREE - ? rhs_origtype - : TREE_TYPE (rhs)); - if (checktype != error_mark_node - && (TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (lhs_origtype) - || (is_atomic_op && modifycode != NOP_EXPR))) - warning_at (location, OPT_Wc___compat, - "enum conversion in assignment is invalid in C++"); - } - - /* Remove qualifiers. */ - lhstype = build_qualified_type (lhstype, TYPE_UNQUALIFIED); - olhstype = build_qualified_type (olhstype, TYPE_UNQUALIFIED); - - /* Convert new value to destination type. Fold it first, then - restore any excess precision information, for the sake of - conversion warnings. */ - - if (!(is_atomic_op && modifycode != NOP_EXPR)) - { - tree rhs_semantic_type = NULL_TREE; - if (!c_in_omp_for) - { - if (TREE_CODE (newrhs) == EXCESS_PRECISION_EXPR) - { - rhs_semantic_type = TREE_TYPE (newrhs); - newrhs = TREE_OPERAND (newrhs, 0); - } - npc = null_pointer_constant_p (newrhs); - newrhs = c_fully_fold (newrhs, false, NULL); - if (rhs_semantic_type) - newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs); - } - else - npc = null_pointer_constant_p (newrhs); - newrhs = convert_for_assignment (location, rhs_loc, lhstype, newrhs, - rhs_origtype, ic_assign, npc, - NULL_TREE, NULL_TREE, 0); - if (TREE_CODE (newrhs) == ERROR_MARK) - return error_mark_node; - } - - /* Emit ObjC write barrier, if necessary. */ - if (c_dialect_objc () && flag_objc_gc) - { - result = objc_generate_write_barrier (lhs, modifycode, newrhs); - if (result) - { - protected_set_expr_location (result, location); - goto return_result; - } - } - - /* Scan operands. */ - - if (is_atomic_op) - result = build_atomic_assign (location, lhs, modifycode, newrhs, false); - else - { - result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs); - TREE_SIDE_EFFECTS (result) = 1; - protected_set_expr_location (result, location); - } - - /* If we got the LHS in a different type for storing in, - convert the result back to the nominal type of LHS - so that the value we return always has the same type - as the LHS argument. */ - - if (olhstype == TREE_TYPE (result)) - goto return_result; - - result = convert_for_assignment (location, rhs_loc, olhstype, result, - rhs_origtype, ic_assign, false, NULL_TREE, - NULL_TREE, 0); - protected_set_expr_location (result, location); - -return_result: - if (rhseval) - result = build2 (COMPOUND_EXPR, TREE_TYPE (result), rhseval, result); - return result; -} - -/* Return whether STRUCT_TYPE has an anonymous field with type TYPE. - This is used to implement -fplan9-extensions. */ - -static bool -find_anonymous_field_with_type (tree struct_type, tree type) -{ - tree field; - bool found; - - gcc_assert (RECORD_OR_UNION_TYPE_P (struct_type)); - found = false; - for (field = TYPE_FIELDS (struct_type); - field != NULL_TREE; - field = TREE_CHAIN (field)) - { - tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field)) - ? c_build_qualified_type (TREE_TYPE (field), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (TREE_TYPE (field))); - if (DECL_NAME (field) == NULL - && comptypes (type, fieldtype)) - { - if (found) - return false; - found = true; - } - else if (DECL_NAME (field) == NULL - && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)) - && find_anonymous_field_with_type (TREE_TYPE (field), type)) - { - if (found) - return false; - found = true; - } - } - return found; -} - -/* RHS is an expression whose type is pointer to struct. If there is - an anonymous field in RHS with type TYPE, then return a pointer to - that field in RHS. This is used with -fplan9-extensions. This - returns NULL if no conversion could be found. */ - -static tree -convert_to_anonymous_field (location_t location, tree type, tree rhs) -{ - tree rhs_struct_type, lhs_main_type; - tree field, found_field; - bool found_sub_field; - tree ret; - - gcc_assert (POINTER_TYPE_P (TREE_TYPE (rhs))); - rhs_struct_type = TREE_TYPE (TREE_TYPE (rhs)); - gcc_assert (RECORD_OR_UNION_TYPE_P (rhs_struct_type)); - - gcc_assert (POINTER_TYPE_P (type)); - lhs_main_type = (TYPE_ATOMIC (TREE_TYPE (type)) - ? c_build_qualified_type (TREE_TYPE (type), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (TREE_TYPE (type))); - - found_field = NULL_TREE; - found_sub_field = false; - for (field = TYPE_FIELDS (rhs_struct_type); - field != NULL_TREE; - field = TREE_CHAIN (field)) - { - if (DECL_NAME (field) != NULL_TREE - || !RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) - continue; - tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field)) - ? c_build_qualified_type (TREE_TYPE (field), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (TREE_TYPE (field))); - if (comptypes (lhs_main_type, fieldtype)) - { - if (found_field != NULL_TREE) - return NULL_TREE; - found_field = field; - } - else if (find_anonymous_field_with_type (TREE_TYPE (field), - lhs_main_type)) - { - if (found_field != NULL_TREE) - return NULL_TREE; - found_field = field; - found_sub_field = true; - } - } - - if (found_field == NULL_TREE) - return NULL_TREE; - - ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (found_field), - build_fold_indirect_ref (rhs), found_field, - NULL_TREE); - ret = build_fold_addr_expr_loc (location, ret); - - if (found_sub_field) - { - ret = convert_to_anonymous_field (location, type, ret); - gcc_assert (ret != NULL_TREE); - } - - return ret; -} - -/* Issue an error message for a bad initializer component. - GMSGID identifies the message. - The component name is taken from the spelling stack. */ - -static void ATTRIBUTE_GCC_DIAG (2,0) -error_init (location_t loc, const char *gmsgid, ...) -{ - char *ofwhat; - - auto_diagnostic_group d; - - /* The gmsgid may be a format string with %< and %>. */ - va_list ap; - va_start (ap, gmsgid); - bool warned = emit_diagnostic_valist (DK_ERROR, loc, -1, gmsgid, &ap); - va_end (ap); - - ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); - if (*ofwhat && warned) - inform (loc, "(near initialization for %qs)", ofwhat); -} - -/* Issue a pedantic warning for a bad initializer component. OPT is - the option OPT_* (from options.h) controlling this warning or 0 if - it is unconditionally given. GMSGID identifies the message. The - component name is taken from the spelling stack. */ - -static void ATTRIBUTE_GCC_DIAG (3,0) -pedwarn_init (location_t loc, int opt, const char *gmsgid, ...) -{ - /* Use the location where a macro was expanded rather than where - it was defined to make sure macros defined in system headers - but used incorrectly elsewhere are diagnosed. */ - location_t exploc = expansion_point_location_if_in_system_header (loc); - auto_diagnostic_group d; - va_list ap; - va_start (ap, gmsgid); - bool warned = emit_diagnostic_valist (DK_PEDWARN, exploc, opt, gmsgid, &ap); - va_end (ap); - char *ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); - if (*ofwhat && warned) - inform (exploc, "(near initialization for %qs)", ofwhat); -} - -/* Issue a warning for a bad initializer component. - - OPT is the OPT_W* value corresponding to the warning option that - controls this warning. GMSGID identifies the message. The - component name is taken from the spelling stack. */ - -static void -warning_init (location_t loc, int opt, const char *gmsgid) -{ - char *ofwhat; - bool warned; - - auto_diagnostic_group d; - - /* Use the location where a macro was expanded rather than where - it was defined to make sure macros defined in system headers - but used incorrectly elsewhere are diagnosed. */ - location_t exploc = expansion_point_location_if_in_system_header (loc); - - /* The gmsgid may be a format string with %< and %>. */ - warned = warning_at (exploc, opt, gmsgid); - ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); - if (*ofwhat && warned) - inform (exploc, "(near initialization for %qs)", ofwhat); -} - -/* If TYPE is an array type and EXPR is a parenthesized string - constant, warn if pedantic that EXPR is being used to initialize an - object of type TYPE. */ - -void -maybe_warn_string_init (location_t loc, tree type, struct c_expr expr) -{ - if (pedantic - && TREE_CODE (type) == ARRAY_TYPE - && TREE_CODE (expr.value) == STRING_CST - && expr.original_code != STRING_CST) - pedwarn_init (loc, OPT_Wpedantic, - "array initialized from parenthesized string constant"); -} - -/* Attempt to locate the parameter with the given index within FNDECL, - returning DECL_SOURCE_LOCATION (FNDECL) if it can't be found. */ - -static location_t -get_fndecl_argument_location (tree fndecl, int argnum) -{ - int i; - tree param; - - /* Locate param by index within DECL_ARGUMENTS (fndecl). */ - for (i = 0, param = DECL_ARGUMENTS (fndecl); - i < argnum && param; - i++, param = TREE_CHAIN (param)) - ; - - /* If something went wrong (e.g. if we have a builtin and thus no arguments), - return DECL_SOURCE_LOCATION (FNDECL). */ - if (param == NULL) - return DECL_SOURCE_LOCATION (fndecl); - - return DECL_SOURCE_LOCATION (param); -} - -/* Issue a note about a mismatching argument for parameter PARMNUM - to FUNDECL, for types EXPECTED_TYPE and ACTUAL_TYPE. - Attempt to issue the note at the pertinent parameter of the decl; - failing that issue it at the location of FUNDECL; failing that - issue it at PLOC. */ - -static void -inform_for_arg (tree fundecl, location_t ploc, int parmnum, - tree expected_type, tree actual_type) -{ - location_t loc; - if (fundecl && !DECL_IS_UNDECLARED_BUILTIN (fundecl)) - loc = get_fndecl_argument_location (fundecl, parmnum - 1); - else - loc = ploc; - - inform (loc, - "expected %qT but argument is of type %qT", - expected_type, actual_type); -} - -/* Issue a warning when an argument of ARGTYPE is passed to a built-in - function FUNDECL declared without prototype to parameter PARMNUM of - PARMTYPE when ARGTYPE does not promote to PARMTYPE. */ - -static void -maybe_warn_builtin_no_proto_arg (location_t loc, tree fundecl, int parmnum, - tree parmtype, tree argtype) -{ - tree_code parmcode = TREE_CODE (parmtype); - tree_code argcode = TREE_CODE (argtype); - tree promoted = c_type_promotes_to (argtype); - - /* Avoid warning for enum arguments that promote to an integer type - of the same size/mode. */ - if (parmcode == INTEGER_TYPE - && argcode == ENUMERAL_TYPE - && TYPE_MODE (parmtype) == TYPE_MODE (argtype)) - return; - - if ((parmcode == argcode - || (parmcode == INTEGER_TYPE - && argcode == ENUMERAL_TYPE)) - && TYPE_MAIN_VARIANT (parmtype) == TYPE_MAIN_VARIANT (promoted)) - return; - - /* This diagnoses even signed/unsigned mismatches. Those might be - safe in many cases but GCC may emit suboptimal code for them so - warning on those cases drives efficiency improvements. */ - if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch, - TYPE_MAIN_VARIANT (promoted) == argtype - ? G_("%qD argument %d type is %qT where %qT is expected " - "in a call to built-in function declared without " - "prototype") - : G_("%qD argument %d promotes to %qT where %qT is expected " - "in a call to built-in function declared without " - "prototype"), - fundecl, parmnum, promoted, parmtype)) - inform (DECL_SOURCE_LOCATION (fundecl), - "built-in %qD declared here", - fundecl); -} - -/* Convert value RHS to type TYPE as preparation for an assignment to - an lvalue of type TYPE. If ORIGTYPE is not NULL_TREE, it is the - original type of RHS; this differs from TREE_TYPE (RHS) for enum - types. NULL_POINTER_CONSTANT says whether RHS was a null pointer - constant before any folding. - The real work of conversion is done by `convert'. - The purpose of this function is to generate error messages - for assignments that are not allowed in C. - ERRTYPE says whether it is argument passing, assignment, - initialization or return. - - In the following example, '~' denotes where EXPR_LOC and '^' where - LOCATION point to: - - f (var); [ic_argpass] - ^ ~~~ - x = var; [ic_assign] - ^ ~~~; - int x = var; [ic_init] - ^^^ - return x; [ic_return] - ^ - - FUNCTION is a tree for the function being called. - PARMNUM is the number of the argument, for printing in error messages. - WARNOPT may be set to a warning option to issue the corresponding warning - rather than an error for invalid conversions. Used for calls to built-in - functions declared without a prototype. */ - -static tree -convert_for_assignment (location_t location, location_t expr_loc, tree type, - tree rhs, tree origtype, enum impl_conv errtype, - bool null_pointer_constant, tree fundecl, - tree function, int parmnum, int warnopt /* = 0 */) -{ - enum tree_code codel = TREE_CODE (type); - tree orig_rhs = rhs; - tree rhstype; - enum tree_code coder; - tree rname = NULL_TREE; - bool objc_ok = false; - - /* Use the expansion point location to handle cases such as user's - function returning a wrong-type macro defined in a system header. */ - location = expansion_point_location_if_in_system_header (location); - - if (errtype == ic_argpass) - { - tree selector; - /* Change pointer to function to the function itself for - diagnostics. */ - if (TREE_CODE (function) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) - function = TREE_OPERAND (function, 0); - - /* Handle an ObjC selector specially for diagnostics. */ - selector = objc_message_selector (); - rname = function; - if (selector && parmnum > 2) - { - rname = selector; - parmnum -= 2; - } - } - - /* This macro is used to emit diagnostics to ensure that all format - strings are complete sentences, visible to gettext and checked at - compile time. */ -#define PEDWARN_FOR_ASSIGNMENT(LOCATION, PLOC, OPT, AR, AS, IN, RE) \ - do { \ - switch (errtype) \ - { \ - case ic_argpass: \ - { \ - auto_diagnostic_group d; \ - if (pedwarn (PLOC, OPT, AR, parmnum, rname)) \ - inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ - } \ - break; \ - case ic_assign: \ - pedwarn (LOCATION, OPT, AS); \ - break; \ - case ic_init: \ - case ic_init_const: \ - pedwarn_init (LOCATION, OPT, IN); \ - break; \ - case ic_return: \ - pedwarn (LOCATION, OPT, RE); \ - break; \ - default: \ - gcc_unreachable (); \ - } \ - } while (0) - - /* This macro is used to emit diagnostics to ensure that all format - strings are complete sentences, visible to gettext and checked at - compile time. It can be called with 'pedwarn' or 'warning_at'. */ -#define WARNING_FOR_QUALIFIERS(PEDWARN, LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \ - do { \ - switch (errtype) \ - { \ - case ic_argpass: \ - { \ - auto_diagnostic_group d; \ - if (PEDWARN) { \ - if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS)) \ - inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ - } else { \ - if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS)) \ - inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ - } \ - } \ - break; \ - case ic_assign: \ - if (PEDWARN) \ - pedwarn (LOCATION, OPT, AS, QUALS); \ - else \ - warning_at (LOCATION, OPT, AS, QUALS); \ - break; \ - case ic_init: \ - case ic_init_const: \ - if (PEDWARN) \ - pedwarn (LOCATION, OPT, IN, QUALS); \ - else \ - warning_at (LOCATION, OPT, IN, QUALS); \ - break; \ - case ic_return: \ - if (PEDWARN) \ - pedwarn (LOCATION, OPT, RE, QUALS); \ - else \ - warning_at (LOCATION, OPT, RE, QUALS); \ - break; \ - default: \ - gcc_unreachable (); \ - } \ - } while (0) - - /* This macro is used to emit diagnostics to ensure that all format - strings are complete sentences, visible to gettext and checked at - compile time. It is the same as PEDWARN_FOR_ASSIGNMENT but with an - extra parameter to enumerate qualifiers. */ -#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \ - WARNING_FOR_QUALIFIERS (true, LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) - - - if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) - rhs = TREE_OPERAND (rhs, 0); - - rhstype = TREE_TYPE (rhs); - coder = TREE_CODE (rhstype); - - if (coder == ERROR_MARK) - return error_mark_node; - - if (c_dialect_objc ()) - { - int parmno; - - switch (errtype) - { - case ic_return: - parmno = 0; - break; - - case ic_assign: - parmno = -1; - break; - - case ic_init: - case ic_init_const: - parmno = -2; - break; - - default: - parmno = parmnum; - break; - } - - objc_ok = objc_compare_types (type, rhstype, parmno, rname); - } - - if (warn_cxx_compat) - { - tree checktype = origtype != NULL_TREE ? origtype : rhstype; - if (checktype != error_mark_node - && TREE_CODE (type) == ENUMERAL_TYPE - && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) - switch (errtype) - { - case ic_argpass: - if (pedwarn (expr_loc, OPT_Wc___compat, "enum conversion when " - "passing argument %d of %qE is invalid in C++", - parmnum, rname)) - inform ((fundecl && !DECL_IS_UNDECLARED_BUILTIN (fundecl)) - ? DECL_SOURCE_LOCATION (fundecl) : expr_loc, - "expected %qT but argument is of type %qT", - type, rhstype); - break; - case ic_assign: - pedwarn (location, OPT_Wc___compat, "enum conversion from %qT to " - "%qT in assignment is invalid in C++", rhstype, type); - break; - case ic_init: - case ic_init_const: - pedwarn_init (location, OPT_Wc___compat, "enum conversion from " - "%qT to %qT in initialization is invalid in C++", - rhstype, type); - break; - case ic_return: - pedwarn (location, OPT_Wc___compat, "enum conversion from %qT to " - "%qT in return is invalid in C++", rhstype, type); - break; - default: - gcc_unreachable (); - } - } - - if (warn_enum_conversion) - { - tree checktype = origtype != NULL_TREE ? origtype : rhstype; - if (checktype != error_mark_node - && TREE_CODE (checktype) == ENUMERAL_TYPE - && TREE_CODE (type) == ENUMERAL_TYPE - && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) - { - gcc_rich_location loc (location); - warning_at (&loc, OPT_Wenum_conversion, - "implicit conversion from %qT to %qT", - checktype, type); - } - } - - if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)) - { - warn_for_address_or_pointer_of_packed_member (type, orig_rhs); - return rhs; - } - - if (coder == VOID_TYPE) - { - /* Except for passing an argument to an unprototyped function, - this is a constraint violation. When passing an argument to - an unprototyped function, it is compile-time undefined; - making it a constraint in that case was rejected in - DR#252. */ - const char msg[] = "void value not ignored as it ought to be"; - if (warnopt) - warning_at (location, warnopt, msg); - else - error_at (location, msg); - return error_mark_node; - } - rhs = require_complete_type (location, rhs); - if (rhs == error_mark_node) - return error_mark_node; - - if (coder == POINTER_TYPE && reject_gcc_builtin (rhs)) - return error_mark_node; - - /* A non-reference type can convert to a reference. This handles - va_start, va_copy and possibly port built-ins. */ - if (codel == REFERENCE_TYPE && coder != REFERENCE_TYPE) - { - if (!lvalue_p (rhs)) - { - const char msg[] = "cannot pass rvalue to reference parameter"; - if (warnopt) - warning_at (location, warnopt, msg); - else - error_at (location, msg); - return error_mark_node; - } - if (!c_mark_addressable (rhs)) - return error_mark_node; - rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs); - SET_EXPR_LOCATION (rhs, location); - - rhs = convert_for_assignment (location, expr_loc, - build_pointer_type (TREE_TYPE (type)), - rhs, origtype, errtype, - null_pointer_constant, fundecl, function, - parmnum, warnopt); - if (rhs == error_mark_node) - return error_mark_node; - - rhs = build1 (NOP_EXPR, type, rhs); - SET_EXPR_LOCATION (rhs, location); - return rhs; - } - /* Some types can interconvert without explicit casts. */ - else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE - && vector_types_convertible_p (type, TREE_TYPE (rhs), true)) - return convert (type, rhs); - /* Arithmetic types all interconvert, and enum is treated like int. */ - else if ((codel == INTEGER_TYPE || codel == REAL_TYPE - || codel == FIXED_POINT_TYPE - || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE - || codel == BOOLEAN_TYPE) - && (coder == INTEGER_TYPE || coder == REAL_TYPE - || coder == FIXED_POINT_TYPE - || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE - || coder == BOOLEAN_TYPE)) - { - if (warnopt && errtype == ic_argpass) - maybe_warn_builtin_no_proto_arg (expr_loc, fundecl, parmnum, type, - rhstype); - - bool save = in_late_binary_op; - if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE - || (coder == REAL_TYPE - && (codel == INTEGER_TYPE || codel == ENUMERAL_TYPE) - && sanitize_flags_p (SANITIZE_FLOAT_CAST))) - in_late_binary_op = true; - tree ret = convert_and_check (expr_loc != UNKNOWN_LOCATION - ? expr_loc : location, type, orig_rhs, - errtype == ic_init_const); - in_late_binary_op = save; - return ret; - } - - /* Aggregates in different TUs might need conversion. */ - if ((codel == RECORD_TYPE || codel == UNION_TYPE) - && codel == coder - && comptypes (type, rhstype)) - return convert_and_check (expr_loc != UNKNOWN_LOCATION - ? expr_loc : location, type, rhs); - - /* Conversion to a transparent union or record from its member types. - This applies only to function arguments. */ - if (((codel == UNION_TYPE || codel == RECORD_TYPE) - && TYPE_TRANSPARENT_AGGR (type)) - && errtype == ic_argpass) - { - tree memb, marginal_memb = NULL_TREE; - - for (memb = TYPE_FIELDS (type); memb ; memb = DECL_CHAIN (memb)) - { - tree memb_type = TREE_TYPE (memb); - - if (comptypes (TYPE_MAIN_VARIANT (memb_type), - TYPE_MAIN_VARIANT (rhstype))) - break; - - if (TREE_CODE (memb_type) != POINTER_TYPE) - continue; - - if (coder == POINTER_TYPE) - { - tree ttl = TREE_TYPE (memb_type); - tree ttr = TREE_TYPE (rhstype); - - /* Any non-function converts to a [const][volatile] void * - and vice versa; otherwise, targets must be the same. - Meanwhile, the lhs target must have all the qualifiers of - the rhs. */ - if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl)) - || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr)) - || comp_target_types (location, memb_type, rhstype)) - { - int lquals = TYPE_QUALS (ttl) & ~TYPE_QUAL_ATOMIC; - int rquals = TYPE_QUALS (ttr) & ~TYPE_QUAL_ATOMIC; - /* If this type won't generate any warnings, use it. */ - if (lquals == rquals - || ((TREE_CODE (ttr) == FUNCTION_TYPE - && TREE_CODE (ttl) == FUNCTION_TYPE) - ? ((lquals | rquals) == rquals) - : ((lquals | rquals) == lquals))) - break; - - /* Keep looking for a better type, but remember this one. */ - if (!marginal_memb) - marginal_memb = memb; - } - } - - /* Can convert integer zero to any pointer type. */ - if (null_pointer_constant) - { - rhs = null_pointer_node; - break; - } - } - - if (memb || marginal_memb) - { - if (!memb) - { - /* We have only a marginally acceptable member type; - it needs a warning. */ - tree ttl = TREE_TYPE (TREE_TYPE (marginal_memb)); - tree ttr = TREE_TYPE (rhstype); - - /* Const and volatile mean something different for function - types, so the usual warnings are not appropriate. */ - if (TREE_CODE (ttr) == FUNCTION_TYPE - && TREE_CODE (ttl) == FUNCTION_TYPE) - { - /* Because const and volatile on functions are - restrictions that say the function will not do - certain things, it is okay to use a const or volatile - function where an ordinary one is wanted, but not - vice-versa. */ - if (TYPE_QUALS_NO_ADDR_SPACE (ttl) - & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) - PEDWARN_FOR_QUALIFIERS (location, expr_loc, - OPT_Wdiscarded_qualifiers, - G_("passing argument %d of %qE " - "makes %q#v qualified function " - "pointer from unqualified"), - G_("assignment makes %q#v qualified " - "function pointer from " - "unqualified"), - G_("initialization makes %q#v qualified " - "function pointer from " - "unqualified"), - G_("return makes %q#v qualified function " - "pointer from unqualified"), - TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)); - } - else if (TYPE_QUALS_NO_ADDR_SPACE (ttr) - & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) - PEDWARN_FOR_QUALIFIERS (location, expr_loc, - OPT_Wdiscarded_qualifiers, - G_("passing argument %d of %qE discards " - "%qv qualifier from pointer target type"), - G_("assignment discards %qv qualifier " - "from pointer target type"), - G_("initialization discards %qv qualifier " - "from pointer target type"), - G_("return discards %qv qualifier from " - "pointer target type"), - TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); - - memb = marginal_memb; - } - - if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl)) - pedwarn (location, OPT_Wpedantic, - "ISO C prohibits argument conversion to union type"); - - rhs = fold_convert_loc (location, TREE_TYPE (memb), rhs); - return build_constructor_single (type, memb, rhs); - } - } - - /* Conversions among pointers */ - else if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE) - && (coder == codel)) - { - /* If RHS refers to a built-in declared without a prototype - BLTIN is the declaration of the built-in with a prototype - and RHSTYPE is set to the actual type of the built-in. */ - tree bltin; - rhstype = type_or_builtin_type (rhs, &bltin); - - tree ttl = TREE_TYPE (type); - tree ttr = TREE_TYPE (rhstype); - tree mvl = ttl; - tree mvr = ttr; - bool is_opaque_pointer; - int target_cmp = 0; /* Cache comp_target_types () result. */ - addr_space_t asl; - addr_space_t asr; - - if (TREE_CODE (mvl) != ARRAY_TYPE) - mvl = (TYPE_ATOMIC (mvl) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mvl)); - if (TREE_CODE (mvr) != ARRAY_TYPE) - mvr = (TYPE_ATOMIC (mvr) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mvr)); - /* Opaque pointers are treated like void pointers. */ - is_opaque_pointer = vector_targets_convertible_p (ttl, ttr); - - /* The Plan 9 compiler permits a pointer to a struct to be - automatically converted into a pointer to an anonymous field - within the struct. */ - if (flag_plan9_extensions - && RECORD_OR_UNION_TYPE_P (mvl) - && RECORD_OR_UNION_TYPE_P (mvr) - && mvl != mvr) - { - tree new_rhs = convert_to_anonymous_field (location, type, rhs); - if (new_rhs != NULL_TREE) - { - rhs = new_rhs; - rhstype = TREE_TYPE (rhs); - coder = TREE_CODE (rhstype); - ttr = TREE_TYPE (rhstype); - mvr = TYPE_MAIN_VARIANT (ttr); - } - } - - /* C++ does not allow the implicit conversion void* -> T*. However, - for the purpose of reducing the number of false positives, we - tolerate the special case of - - int *p = NULL; - - where NULL is typically defined in C to be '(void *) 0'. */ - if (VOID_TYPE_P (ttr) && rhs != null_pointer_node && !VOID_TYPE_P (ttl)) - warning_at (errtype == ic_argpass ? expr_loc : location, - OPT_Wc___compat, - "request for implicit conversion " - "from %qT to %qT not permitted in C++", rhstype, type); - - /* See if the pointers point to incompatible address spaces. */ - asl = TYPE_ADDR_SPACE (ttl); - asr = TYPE_ADDR_SPACE (ttr); - if (!null_pointer_constant_p (rhs) - && asr != asl && !targetm.addr_space.subset_p (asr, asl)) - { - switch (errtype) - { - case ic_argpass: - { - const char msg[] = G_("passing argument %d of %qE from " - "pointer to non-enclosed address space"); - if (warnopt) - warning_at (expr_loc, warnopt, msg, parmnum, rname); - else - error_at (expr_loc, msg, parmnum, rname); - break; - } - case ic_assign: - { - const char msg[] = G_("assignment from pointer to " - "non-enclosed address space"); - if (warnopt) - warning_at (location, warnopt, msg); - else - error_at (location, msg); - break; - } - case ic_init: - case ic_init_const: - { - const char msg[] = G_("initialization from pointer to " - "non-enclosed address space"); - if (warnopt) - warning_at (location, warnopt, msg); - else - error_at (location, msg); - break; - } - case ic_return: - { - const char msg[] = G_("return from pointer to " - "non-enclosed address space"); - if (warnopt) - warning_at (location, warnopt, msg); - else - error_at (location, msg); - break; - } - default: - gcc_unreachable (); - } - return error_mark_node; - } - - /* Check if the right-hand side has a format attribute but the - left-hand side doesn't. */ - if (warn_suggest_attribute_format - && check_missing_format_attribute (type, rhstype)) - { - switch (errtype) - { - case ic_argpass: - warning_at (expr_loc, OPT_Wsuggest_attribute_format, - "argument %d of %qE might be " - "a candidate for a format attribute", - parmnum, rname); - break; - case ic_assign: - warning_at (location, OPT_Wsuggest_attribute_format, - "assignment left-hand side might be " - "a candidate for a format attribute"); - break; - case ic_init: - case ic_init_const: - warning_at (location, OPT_Wsuggest_attribute_format, - "initialization left-hand side might be " - "a candidate for a format attribute"); - break; - case ic_return: - warning_at (location, OPT_Wsuggest_attribute_format, - "return type might be " - "a candidate for a format attribute"); - break; - default: - gcc_unreachable (); - } - } - - /* See if the pointers point to incompatible scalar storage orders. */ - if (warn_scalar_storage_order - && (AGGREGATE_TYPE_P (ttl) && TYPE_REVERSE_STORAGE_ORDER (ttl)) - != (AGGREGATE_TYPE_P (ttr) && TYPE_REVERSE_STORAGE_ORDER (ttr))) - { - tree t; - - switch (errtype) - { - case ic_argpass: - /* Do not warn for built-in functions, for example memcpy, since we - control how they behave and they can be useful in this area. */ - if (TREE_CODE (rname) != FUNCTION_DECL - || !fndecl_built_in_p (rname)) - warning_at (location, OPT_Wscalar_storage_order, - "passing argument %d of %qE from incompatible " - "scalar storage order", parmnum, rname); - break; - case ic_assign: - /* Do not warn if the RHS is a call to a function that returns a - pointer that is not an alias. */ - if (TREE_CODE (rhs) != CALL_EXPR - || (t = get_callee_fndecl (rhs)) == NULL_TREE - || !DECL_IS_MALLOC (t)) - warning_at (location, OPT_Wscalar_storage_order, - "assignment to %qT from pointer type %qT with " - "incompatible scalar storage order", type, rhstype); - break; - case ic_init: - case ic_init_const: - /* Likewise. */ - if (TREE_CODE (rhs) != CALL_EXPR - || (t = get_callee_fndecl (rhs)) == NULL_TREE - || !DECL_IS_MALLOC (t)) - warning_at (location, OPT_Wscalar_storage_order, - "initialization of %qT from pointer type %qT with " - "incompatible scalar storage order", type, rhstype); - break; - case ic_return: - warning_at (location, OPT_Wscalar_storage_order, - "returning %qT from pointer type with incompatible " - "scalar storage order %qT", rhstype, type); - break; - default: - gcc_unreachable (); - } - } - - /* Any non-function converts to a [const][volatile] void * - and vice versa; otherwise, targets must be the same. - Meanwhile, the lhs target must have all the qualifiers of the rhs. */ - if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl)) - || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr)) - || (target_cmp = comp_target_types (location, type, rhstype)) - || is_opaque_pointer - || ((c_common_unsigned_type (mvl) - == c_common_unsigned_type (mvr)) - && (c_common_signed_type (mvl) - == c_common_signed_type (mvr)) - && TYPE_ATOMIC (mvl) == TYPE_ATOMIC (mvr))) - { - /* Warn about loss of qualifers from pointers to arrays with - qualifiers on the element type. */ - if (TREE_CODE (ttr) == ARRAY_TYPE) - { - ttr = strip_array_types (ttr); - ttl = strip_array_types (ttl); - - if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) - & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl)) - WARNING_FOR_QUALIFIERS (flag_isoc2x, - location, expr_loc, - OPT_Wdiscarded_array_qualifiers, - G_("passing argument %d of %qE discards " - "%qv qualifier from pointer target type"), - G_("assignment discards %qv qualifier " - "from pointer target type"), - G_("initialization discards %qv qualifier " - "from pointer target type"), - G_("return discards %qv qualifier from " - "pointer target type"), - TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); - } - else if (pedantic - && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE) - || - (VOID_TYPE_P (ttr) - && !null_pointer_constant - && TREE_CODE (ttl) == FUNCTION_TYPE))) - PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpedantic, - G_("ISO C forbids passing argument %d of " - "%qE between function pointer " - "and %"), - G_("ISO C forbids assignment between " - "function pointer and %"), - G_("ISO C forbids initialization between " - "function pointer and %"), - G_("ISO C forbids return between function " - "pointer and %")); - /* Const and volatile mean something different for function types, - so the usual warnings are not appropriate. */ - else if (TREE_CODE (ttr) != FUNCTION_TYPE - && TREE_CODE (ttl) != FUNCTION_TYPE) - { - /* Assignments between atomic and non-atomic objects are OK. */ - bool warn_quals_ped = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) - & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl); - bool warn_quals = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) - & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (strip_array_types (ttl)); - - /* Don't warn about loss of qualifier for conversions from - qualified void* to pointers to arrays with corresponding - qualifier on the element type (except for pedantic before C23). */ - if (warn_quals || (warn_quals_ped && pedantic && !flag_isoc2x)) - PEDWARN_FOR_QUALIFIERS (location, expr_loc, - OPT_Wdiscarded_qualifiers, - G_("passing argument %d of %qE discards " - "%qv qualifier from pointer target type"), - G_("assignment discards %qv qualifier " - "from pointer target type"), - G_("initialization discards %qv qualifier " - "from pointer target type"), - G_("return discards %qv qualifier from " - "pointer target type"), - TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); - else if (warn_quals_ped) - pedwarn_c11 (location, OPT_Wc11_c2x_compat, - "array with qualifier on the element is not qualified before C2X"); - - /* If this is not a case of ignoring a mismatch in signedness, - no warning. */ - else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr) - || target_cmp) - ; - /* If there is a mismatch, do warn. */ - else if (warn_pointer_sign) - switch (errtype) - { - case ic_argpass: - { - auto_diagnostic_group d; - range_label_for_type_mismatch rhs_label (rhstype, type); - gcc_rich_location richloc (expr_loc, &rhs_label); - if (pedwarn (&richloc, OPT_Wpointer_sign, - "pointer targets in passing argument %d of " - "%qE differ in signedness", parmnum, rname)) - inform_for_arg (fundecl, expr_loc, parmnum, type, - rhstype); - } - break; - case ic_assign: - pedwarn (location, OPT_Wpointer_sign, - "pointer targets in assignment from %qT to %qT " - "differ in signedness", rhstype, type); - break; - case ic_init: - case ic_init_const: - pedwarn_init (location, OPT_Wpointer_sign, - "pointer targets in initialization of %qT " - "from %qT differ in signedness", type, - rhstype); - break; - case ic_return: - pedwarn (location, OPT_Wpointer_sign, "pointer targets in " - "returning %qT from a function with return type " - "%qT differ in signedness", rhstype, type); - break; - default: - gcc_unreachable (); - } - } - else if (TREE_CODE (ttl) == FUNCTION_TYPE - && TREE_CODE (ttr) == FUNCTION_TYPE) - { - /* Because const and volatile on functions are restrictions - that say the function will not do certain things, - it is okay to use a const or volatile function - where an ordinary one is wanted, but not vice-versa. */ - if (TYPE_QUALS_NO_ADDR_SPACE (ttl) - & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) - PEDWARN_FOR_QUALIFIERS (location, expr_loc, - OPT_Wdiscarded_qualifiers, - G_("passing argument %d of %qE makes " - "%q#v qualified function pointer " - "from unqualified"), - G_("assignment makes %q#v qualified function " - "pointer from unqualified"), - G_("initialization makes %q#v qualified " - "function pointer from unqualified"), - G_("return makes %q#v qualified function " - "pointer from unqualified"), - TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)); - } - } - /* Avoid warning about the volatile ObjC EH puts on decls. */ - else if (!objc_ok) - { - switch (errtype) - { - case ic_argpass: - { - auto_diagnostic_group d; - range_label_for_type_mismatch rhs_label (rhstype, type); - gcc_rich_location richloc (expr_loc, &rhs_label); - if (pedwarn (&richloc, OPT_Wincompatible_pointer_types, - "passing argument %d of %qE from incompatible " - "pointer type", parmnum, rname)) - inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype); - } - break; - case ic_assign: - if (bltin) - pedwarn (location, OPT_Wincompatible_pointer_types, - "assignment to %qT from pointer to " - "%qD with incompatible type %qT", - type, bltin, rhstype); - else - pedwarn (location, OPT_Wincompatible_pointer_types, - "assignment to %qT from incompatible pointer type %qT", - type, rhstype); - break; - case ic_init: - case ic_init_const: - if (bltin) - pedwarn_init (location, OPT_Wincompatible_pointer_types, - "initialization of %qT from pointer to " - "%qD with incompatible type %qT", - type, bltin, rhstype); - else - pedwarn_init (location, OPT_Wincompatible_pointer_types, - "initialization of %qT from incompatible " - "pointer type %qT", - type, rhstype); - break; - case ic_return: - if (bltin) - pedwarn (location, OPT_Wincompatible_pointer_types, - "returning pointer to %qD of type %qT from " - "a function with incompatible type %qT", - bltin, rhstype, type); - else - pedwarn (location, OPT_Wincompatible_pointer_types, - "returning %qT from a function with incompatible " - "return type %qT", rhstype, type); - break; - default: - gcc_unreachable (); - } - } - - /* If RHS isn't an address, check pointer or array of packed - struct or union. */ - warn_for_address_or_pointer_of_packed_member (type, orig_rhs); - - return convert (type, rhs); - } - else if (codel == POINTER_TYPE && coder == ARRAY_TYPE) - { - /* ??? This should not be an error when inlining calls to - unprototyped functions. */ - const char msg[] = "invalid use of non-lvalue array"; - if (warnopt) - warning_at (location, warnopt, msg); - else - error_at (location, msg); - return error_mark_node; - } - else if (codel == POINTER_TYPE && coder == INTEGER_TYPE) - { - /* An explicit constant 0 can convert to a pointer, - or one that results from arithmetic, even including - a cast to integer type. */ - if (!null_pointer_constant) - switch (errtype) - { - case ic_argpass: - { - auto_diagnostic_group d; - range_label_for_type_mismatch rhs_label (rhstype, type); - gcc_rich_location richloc (expr_loc, &rhs_label); - if (pedwarn (&richloc, OPT_Wint_conversion, - "passing argument %d of %qE makes pointer from " - "integer without a cast", parmnum, rname)) - inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype); - } - break; - case ic_assign: - pedwarn (location, OPT_Wint_conversion, - "assignment to %qT from %qT makes pointer from integer " - "without a cast", type, rhstype); - break; - case ic_init: - case ic_init_const: - pedwarn_init (location, OPT_Wint_conversion, - "initialization of %qT from %qT makes pointer from " - "integer without a cast", type, rhstype); - break; - case ic_return: - pedwarn (location, OPT_Wint_conversion, "returning %qT from a " - "function with return type %qT makes pointer from " - "integer without a cast", rhstype, type); - break; - default: - gcc_unreachable (); - } - - return convert (type, rhs); - } - else if (codel == INTEGER_TYPE && coder == POINTER_TYPE) - { - switch (errtype) - { - case ic_argpass: - { - auto_diagnostic_group d; - range_label_for_type_mismatch rhs_label (rhstype, type); - gcc_rich_location richloc (expr_loc, &rhs_label); - if (pedwarn (&richloc, OPT_Wint_conversion, - "passing argument %d of %qE makes integer from " - "pointer without a cast", parmnum, rname)) - inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype); - } - break; - case ic_assign: - pedwarn (location, OPT_Wint_conversion, - "assignment to %qT from %qT makes integer from pointer " - "without a cast", type, rhstype); - break; - case ic_init: - case ic_init_const: - pedwarn_init (location, OPT_Wint_conversion, - "initialization of %qT from %qT makes integer from " - "pointer without a cast", type, rhstype); - break; - case ic_return: - pedwarn (location, OPT_Wint_conversion, "returning %qT from a " - "function with return type %qT makes integer from " - "pointer without a cast", rhstype, type); - break; - default: - gcc_unreachable (); - } - - return convert (type, rhs); - } - else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE) - { - tree ret; - bool save = in_late_binary_op; - in_late_binary_op = true; - ret = convert (type, rhs); - in_late_binary_op = save; - return ret; - } - - switch (errtype) - { - case ic_argpass: - { - auto_diagnostic_group d; - range_label_for_type_mismatch rhs_label (rhstype, type); - gcc_rich_location richloc (expr_loc, &rhs_label); - const char msg[] = G_("incompatible type for argument %d of %qE"); - if (warnopt) - warning_at (expr_loc, warnopt, msg, parmnum, rname); - else - error_at (&richloc, msg, parmnum, rname); - inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype); - } - break; - case ic_assign: - { - const char msg[] - = G_("incompatible types when assigning to type %qT from type %qT"); - if (warnopt) - warning_at (expr_loc, 0, msg, type, rhstype); - else - error_at (expr_loc, msg, type, rhstype); - break; - } - case ic_init: - case ic_init_const: - { - const char msg[] - = G_("incompatible types when initializing type %qT using type %qT"); - if (warnopt) - warning_at (location, 0, msg, type, rhstype); - else - error_at (location, msg, type, rhstype); - break; - } - case ic_return: - { - const char msg[] - = G_("incompatible types when returning type %qT but %qT was expected"); - if (warnopt) - warning_at (location, 0, msg, rhstype, type); - else - error_at (location, msg, rhstype, type); - break; - } - default: - gcc_unreachable (); - } - - return error_mark_node; -} - -/* If VALUE is a compound expr all of whose expressions are constant, then - return its value. Otherwise, return error_mark_node. - - This is for handling COMPOUND_EXPRs as initializer elements - which is allowed with a warning when -pedantic is specified. */ - -static tree -valid_compound_expr_initializer (tree value, tree endtype) -{ - if (TREE_CODE (value) == COMPOUND_EXPR) - { - if (valid_compound_expr_initializer (TREE_OPERAND (value, 0), endtype) - == error_mark_node) - return error_mark_node; - return valid_compound_expr_initializer (TREE_OPERAND (value, 1), - endtype); - } - else if (!initializer_constant_valid_p (value, endtype)) - return error_mark_node; - else - return value; -} - -/* Perform appropriate conversions on the initial value of a variable, - store it in the declaration DECL, - and print any error messages that are appropriate. - If ORIGTYPE is not NULL_TREE, it is the original type of INIT. - If the init is invalid, store an ERROR_MARK. - - INIT_LOC is the location of the initial value. */ - -void -store_init_value (location_t init_loc, tree decl, tree init, tree origtype) -{ - tree value, type; - bool npc = false; - - /* If variable's type was invalidly declared, just ignore it. */ - - type = TREE_TYPE (decl); - if (TREE_CODE (type) == ERROR_MARK) - return; - - /* Digest the specified initializer into an expression. */ - - if (init) - npc = null_pointer_constant_p (init); - value = digest_init (init_loc, type, init, origtype, npc, - true, TREE_STATIC (decl)); - - /* Store the expression if valid; else report error. */ - - if (!in_system_header_at (input_location) - && AGGREGATE_TYPE_P (TREE_TYPE (decl)) && !TREE_STATIC (decl)) - warning (OPT_Wtraditional, "traditional C rejects automatic " - "aggregate initialization"); - - if (value != error_mark_node || TREE_CODE (decl) != FUNCTION_DECL) - DECL_INITIAL (decl) = value; - - /* ANSI wants warnings about out-of-range constant initializers. */ - STRIP_TYPE_NOPS (value); - if (TREE_STATIC (decl)) - constant_expression_warning (value); - - /* Check if we need to set array size from compound literal size. */ - if (TREE_CODE (type) == ARRAY_TYPE - && TYPE_DOMAIN (type) == NULL_TREE - && value != error_mark_node) - { - tree inside_init = init; - - STRIP_TYPE_NOPS (inside_init); - inside_init = fold (inside_init); - - if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) - { - tree cldecl = COMPOUND_LITERAL_EXPR_DECL (inside_init); - - if (TYPE_DOMAIN (TREE_TYPE (cldecl))) - { - /* For int foo[] = (int [3]){1}; we need to set array size - now since later on array initializer will be just the - brace enclosed list of the compound literal. */ - tree etype = strip_array_types (TREE_TYPE (decl)); - type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); - TYPE_DOMAIN (type) = TYPE_DOMAIN (TREE_TYPE (cldecl)); - layout_type (type); - layout_decl (cldecl, 0); - TREE_TYPE (decl) - = c_build_qualified_type (type, TYPE_QUALS (etype)); - } - } - } -} - -/* Methods for storing and printing names for error messages. */ - -/* Implement a spelling stack that allows components of a name to be pushed - and popped. Each element on the stack is this structure. */ - -struct spelling -{ - int kind; - union - { - unsigned HOST_WIDE_INT i; - const char *s; - } u; -}; - -#define SPELLING_STRING 1 -#define SPELLING_MEMBER 2 -#define SPELLING_BOUNDS 3 - -static struct spelling *spelling; /* Next stack element (unused). */ -static struct spelling *spelling_base; /* Spelling stack base. */ -static int spelling_size; /* Size of the spelling stack. */ - -/* Macros to save and restore the spelling stack around push_... functions. - Alternative to SAVE_SPELLING_STACK. */ - -#define SPELLING_DEPTH() (spelling - spelling_base) -#define RESTORE_SPELLING_DEPTH(DEPTH) (spelling = spelling_base + (DEPTH)) - -/* Push an element on the spelling stack with type KIND and assign VALUE - to MEMBER. */ - -#define PUSH_SPELLING(KIND, VALUE, MEMBER) \ -{ \ - int depth = SPELLING_DEPTH (); \ - \ - if (depth >= spelling_size) \ - { \ - spelling_size += 10; \ - spelling_base = XRESIZEVEC (struct spelling, spelling_base, \ - spelling_size); \ - RESTORE_SPELLING_DEPTH (depth); \ - } \ - \ - spelling->kind = (KIND); \ - spelling->MEMBER = (VALUE); \ - spelling++; \ -} - -/* Push STRING on the stack. Printed literally. */ - -static void -push_string (const char *string) -{ - PUSH_SPELLING (SPELLING_STRING, string, u.s); -} - -/* Push a member name on the stack. Printed as '.' STRING. */ - -static void -push_member_name (tree decl) -{ - const char *const string - = (DECL_NAME (decl) - ? identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (decl))) - : _("")); - PUSH_SPELLING (SPELLING_MEMBER, string, u.s); -} - -/* Push an array bounds on the stack. Printed as [BOUNDS]. */ - -static void -push_array_bounds (unsigned HOST_WIDE_INT bounds) -{ - PUSH_SPELLING (SPELLING_BOUNDS, bounds, u.i); -} - -/* Compute the maximum size in bytes of the printed spelling. */ - -static int -spelling_length (void) -{ - int size = 0; - struct spelling *p; - - for (p = spelling_base; p < spelling; p++) - { - if (p->kind == SPELLING_BOUNDS) - size += 25; - else - size += strlen (p->u.s) + 1; - } - - return size; -} - -/* Print the spelling to BUFFER and return it. */ - -static char * -print_spelling (char *buffer) -{ - char *d = buffer; - struct spelling *p; - - for (p = spelling_base; p < spelling; p++) - if (p->kind == SPELLING_BOUNDS) - { - sprintf (d, "[" HOST_WIDE_INT_PRINT_UNSIGNED "]", p->u.i); - d += strlen (d); - } - else - { - const char *s; - if (p->kind == SPELLING_MEMBER) - *d++ = '.'; - for (s = p->u.s; (*d = *s++); d++) - ; - } - *d++ = '\0'; - return buffer; -} - -/* Digest the parser output INIT as an initializer for type TYPE. - Return a C expression of type TYPE to represent the initial value. - - If ORIGTYPE is not NULL_TREE, it is the original type of INIT. - - NULL_POINTER_CONSTANT is true if INIT is a null pointer constant. - - If INIT is a string constant, STRICT_STRING is true if it is - unparenthesized or we should not warn here for it being parenthesized. - For other types of INIT, STRICT_STRING is not used. - - INIT_LOC is the location of the INIT. - - REQUIRE_CONSTANT requests an error if non-constant initializers or - elements are seen. */ - -static tree -digest_init (location_t init_loc, tree type, tree init, tree origtype, - bool null_pointer_constant, bool strict_string, - int require_constant) -{ - enum tree_code code = TREE_CODE (type); - tree inside_init = init; - tree semantic_type = NULL_TREE; - bool maybe_const = true; - - if (type == error_mark_node - || !init - || error_operand_p (init)) - return error_mark_node; - - STRIP_TYPE_NOPS (inside_init); - - if (!c_in_omp_for) - { - if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR) - { - semantic_type = TREE_TYPE (inside_init); - inside_init = TREE_OPERAND (inside_init, 0); - } - inside_init = c_fully_fold (inside_init, require_constant, &maybe_const); - } - - /* Initialization of an array of chars from a string constant - optionally enclosed in braces. */ - - if (code == ARRAY_TYPE && inside_init - && TREE_CODE (inside_init) == STRING_CST) - { - tree typ1 - = (TYPE_ATOMIC (TREE_TYPE (type)) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (TREE_TYPE (type)), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (TREE_TYPE (type))); - /* Note that an array could be both an array of character type - and an array of wchar_t if wchar_t is signed char or unsigned - char. */ - bool char_array = (typ1 == char_type_node - || typ1 == signed_char_type_node - || typ1 == unsigned_char_type_node); - bool wchar_array = !!comptypes (typ1, wchar_type_node); - bool char16_array = !!comptypes (typ1, char16_type_node); - bool char32_array = !!comptypes (typ1, char32_type_node); - - if (char_array || wchar_array || char16_array || char32_array) - { - struct c_expr expr; - tree typ2 = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init))); - bool incompat_string_cst = false; - expr.value = inside_init; - expr.original_code = (strict_string ? STRING_CST : ERROR_MARK); - expr.original_type = NULL; - maybe_warn_string_init (init_loc, type, expr); - - if (TYPE_DOMAIN (type) && !TYPE_MAX_VALUE (TYPE_DOMAIN (type))) - pedwarn_init (init_loc, OPT_Wpedantic, - "initialization of a flexible array member"); - - if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), - TYPE_MAIN_VARIANT (type))) - return inside_init; - - if (char_array) - { - if (typ2 != char_type_node) - incompat_string_cst = true; - } - else if (!comptypes (typ1, typ2)) - incompat_string_cst = true; - - if (incompat_string_cst) - { - error_init (init_loc, "cannot initialize array of %qT from " - "a string literal with type array of %qT", - typ1, typ2); - return error_mark_node; - } - - if (TYPE_DOMAIN (type) != NULL_TREE - && TYPE_SIZE (type) != NULL_TREE - && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST) - { - unsigned HOST_WIDE_INT len = TREE_STRING_LENGTH (inside_init); - unsigned unit = TYPE_PRECISION (typ1) / BITS_PER_UNIT; - - /* Subtract the size of a single (possibly wide) character - because it's ok to ignore the terminating null char - that is counted in the length of the constant. */ - if (compare_tree_int (TYPE_SIZE_UNIT (type), len - unit) < 0) - pedwarn_init (init_loc, 0, - ("initializer-string for array of %qT " - "is too long"), typ1); - else if (warn_cxx_compat - && compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0) - warning_at (init_loc, OPT_Wc___compat, - ("initializer-string for array of %qT " - "is too long for C++"), typ1); - if (compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0) - { - unsigned HOST_WIDE_INT size - = tree_to_uhwi (TYPE_SIZE_UNIT (type)); - const char *p = TREE_STRING_POINTER (inside_init); - - inside_init = build_string (size, p); - } - } - - TREE_TYPE (inside_init) = type; - return inside_init; - } - else if (INTEGRAL_TYPE_P (typ1)) - { - error_init (init_loc, "array of inappropriate type initialized " - "from string constant"); - return error_mark_node; - } - } - - /* Build a VECTOR_CST from a *constant* vector constructor. If the - vector constructor is not constant (e.g. {1,2,3,foo()}) then punt - below and handle as a constructor. */ - if (code == VECTOR_TYPE - && VECTOR_TYPE_P (TREE_TYPE (inside_init)) - && vector_types_convertible_p (TREE_TYPE (inside_init), type, true) - && TREE_CONSTANT (inside_init)) - { - if (TREE_CODE (inside_init) == VECTOR_CST - && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), - TYPE_MAIN_VARIANT (type))) - return inside_init; - - if (TREE_CODE (inside_init) == CONSTRUCTOR) - { - unsigned HOST_WIDE_INT ix; - tree value; - bool constant_p = true; - - /* Iterate through elements and check if all constructor - elements are *_CSTs. */ - FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (inside_init), ix, value) - if (!CONSTANT_CLASS_P (value)) - { - constant_p = false; - break; - } - - if (constant_p) - return build_vector_from_ctor (type, - CONSTRUCTOR_ELTS (inside_init)); - } - } - - if (warn_sequence_point) - verify_sequence_points (inside_init); - - /* Any type can be initialized - from an expression of the same type, optionally with braces. */ - - if (inside_init && TREE_TYPE (inside_init) != NULL_TREE - && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), - TYPE_MAIN_VARIANT (type)) - || (code == ARRAY_TYPE - && comptypes (TREE_TYPE (inside_init), type)) - || (gnu_vector_type_p (type) - && comptypes (TREE_TYPE (inside_init), type)) - || (code == POINTER_TYPE - && TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE - && comptypes (TREE_TYPE (TREE_TYPE (inside_init)), - TREE_TYPE (type))))) - { - if (code == POINTER_TYPE) - { - if (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE) - { - if (TREE_CODE (inside_init) == STRING_CST - || TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) - inside_init = array_to_pointer_conversion - (init_loc, inside_init); - else - { - error_init (init_loc, "invalid use of non-lvalue array"); - return error_mark_node; - } - } - } - - if (code == VECTOR_TYPE) - /* Although the types are compatible, we may require a - conversion. */ - inside_init = convert (type, inside_init); - - if (require_constant - && TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) - { - /* As an extension, allow initializing objects with static storage - duration with compound literals (which are then treated just as - the brace enclosed list they contain). Also allow this for - vectors, as we can only assign them with compound literals. */ - if (flag_isoc99 && code != VECTOR_TYPE) - pedwarn_init (init_loc, OPT_Wpedantic, "initializer element " - "is not constant"); - tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init); - inside_init = DECL_INITIAL (decl); - } - - if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST - && TREE_CODE (inside_init) != CONSTRUCTOR) - { - error_init (init_loc, "array initialized from non-constant array " - "expression"); - return error_mark_node; - } - - /* Compound expressions can only occur here if -Wpedantic or - -pedantic-errors is specified. In the later case, we always want - an error. In the former case, we simply want a warning. */ - if (require_constant && pedantic - && TREE_CODE (inside_init) == COMPOUND_EXPR) - { - inside_init - = valid_compound_expr_initializer (inside_init, - TREE_TYPE (inside_init)); - if (inside_init == error_mark_node) - error_init (init_loc, "initializer element is not constant"); - else - pedwarn_init (init_loc, OPT_Wpedantic, - "initializer element is not constant"); - if (flag_pedantic_errors) - inside_init = error_mark_node; - } - else if (require_constant - && !initializer_constant_valid_p (inside_init, - TREE_TYPE (inside_init))) - { - error_init (init_loc, "initializer element is not constant"); - inside_init = error_mark_node; - } - else if (require_constant && !maybe_const) - pedwarn_init (init_loc, OPT_Wpedantic, - "initializer element is not a constant expression"); - - /* Added to enable additional -Wsuggest-attribute=format warnings. */ - if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE) - inside_init = convert_for_assignment (init_loc, UNKNOWN_LOCATION, - type, inside_init, origtype, - (require_constant - ? ic_init_const - : ic_init), null_pointer_constant, - NULL_TREE, NULL_TREE, 0); - return inside_init; - } - - /* Handle scalar types, including conversions. */ - - if (code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE - || code == POINTER_TYPE || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE - || code == COMPLEX_TYPE || code == VECTOR_TYPE) - { - if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE - && (TREE_CODE (init) == STRING_CST - || TREE_CODE (init) == COMPOUND_LITERAL_EXPR)) - inside_init = init = array_to_pointer_conversion (init_loc, init); - if (semantic_type) - inside_init = build1 (EXCESS_PRECISION_EXPR, semantic_type, - inside_init); - inside_init - = convert_for_assignment (init_loc, UNKNOWN_LOCATION, type, - inside_init, origtype, - require_constant ? ic_init_const : ic_init, - null_pointer_constant, NULL_TREE, NULL_TREE, - 0); - - /* Check to see if we have already given an error message. */ - if (inside_init == error_mark_node) - ; - else if (require_constant && !TREE_CONSTANT (inside_init)) - { - error_init (init_loc, "initializer element is not constant"); - inside_init = error_mark_node; - } - else if (require_constant - && !initializer_constant_valid_p (inside_init, - TREE_TYPE (inside_init))) - { - error_init (init_loc, "initializer element is not computable at " - "load time"); - inside_init = error_mark_node; - } - else if (require_constant && !maybe_const) - pedwarn_init (init_loc, OPT_Wpedantic, - "initializer element is not a constant expression"); - - return inside_init; - } - - /* Come here only for records and arrays. */ - - if (COMPLETE_TYPE_P (type) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) - { - error_init (init_loc, "variable-sized object may not be initialized"); - return error_mark_node; - } - - error_init (init_loc, "invalid initializer"); - return error_mark_node; -} - -/* Handle initializers that use braces. */ - -/* Type of object we are accumulating a constructor for. - This type is always a RECORD_TYPE, UNION_TYPE or ARRAY_TYPE. */ -static tree constructor_type; - -/* For a RECORD_TYPE or UNION_TYPE, this is the chain of fields - left to fill. */ -static tree constructor_fields; - -/* For an ARRAY_TYPE, this is the specified index - at which to store the next element we get. */ -static tree constructor_index; - -/* For an ARRAY_TYPE, this is the maximum index. */ -static tree constructor_max_index; - -/* For a RECORD_TYPE, this is the first field not yet written out. */ -static tree constructor_unfilled_fields; - -/* For an ARRAY_TYPE, this is the index of the first element - not yet written out. */ -static tree constructor_unfilled_index; - -/* In a RECORD_TYPE, the byte index of the next consecutive field. - This is so we can generate gaps between fields, when appropriate. */ -static tree constructor_bit_index; - -/* If we are saving up the elements rather than allocating them, - this is the list of elements so far (in reverse order, - most recent first). */ -static vec *constructor_elements; - -/* 1 if constructor should be incrementally stored into a constructor chain, - 0 if all the elements should be kept in AVL tree. */ -static int constructor_incremental; - -/* 1 if so far this constructor's elements are all compile-time constants. */ -static int constructor_constant; - -/* 1 if so far this constructor's elements are all valid address constants. */ -static int constructor_simple; - -/* 1 if this constructor has an element that cannot be part of a - constant expression. */ -static int constructor_nonconst; - -/* 1 if this constructor is erroneous so far. */ -static int constructor_erroneous; - -/* 1 if this constructor is the universal zero initializer { 0 }. */ -static int constructor_zeroinit; - -/* Structure for managing pending initializer elements, organized as an - AVL tree. */ - -struct init_node -{ - struct init_node *left, *right; - struct init_node *parent; - int balance; - tree purpose; - tree value; - tree origtype; -}; - -/* Tree of pending elements at this constructor level. - These are elements encountered out of order - which belong at places we haven't reached yet in actually - writing the output. - Will never hold tree nodes across GC runs. */ -static struct init_node *constructor_pending_elts; - -/* The SPELLING_DEPTH of this constructor. */ -static int constructor_depth; - -/* DECL node for which an initializer is being read. - 0 means we are reading a constructor expression - such as (struct foo) {...}. */ -static tree constructor_decl; - -/* Nonzero if this is an initializer for a top-level decl. */ -static int constructor_top_level; - -/* Nonzero if there were any member designators in this initializer. */ -static int constructor_designated; - -/* Nesting depth of designator list. */ -static int designator_depth; - -/* Nonzero if there were diagnosed errors in this designator list. */ -static int designator_erroneous; - - -/* This stack has a level for each implicit or explicit level of - structuring in the initializer, including the outermost one. It - saves the values of most of the variables above. */ - -struct constructor_range_stack; - -struct constructor_stack -{ - struct constructor_stack *next; - tree type; - tree fields; - tree index; - tree max_index; - tree unfilled_index; - tree unfilled_fields; - tree bit_index; - vec *elements; - struct init_node *pending_elts; - int offset; - int depth; - /* If value nonzero, this value should replace the entire - constructor at this level. */ - struct c_expr replacement_value; - struct constructor_range_stack *range_stack; - char constant; - char simple; - char nonconst; - char implicit; - char erroneous; - char outer; - char incremental; - char designated; - int designator_depth; -}; - -static struct constructor_stack *constructor_stack; - -/* This stack represents designators from some range designator up to - the last designator in the list. */ - -struct constructor_range_stack -{ - struct constructor_range_stack *next, *prev; - struct constructor_stack *stack; - tree range_start; - tree index; - tree range_end; - tree fields; -}; - -static struct constructor_range_stack *constructor_range_stack; - -/* This stack records separate initializers that are nested. - Nested initializers can't happen in ANSI C, but GNU C allows them - in cases like { ... (struct foo) { ... } ... }. */ - -struct initializer_stack -{ - struct initializer_stack *next; - tree decl; - struct constructor_stack *constructor_stack; - struct constructor_range_stack *constructor_range_stack; - vec *elements; - struct spelling *spelling; - struct spelling *spelling_base; - int spelling_size; - char top_level; - char require_constant_value; - char require_constant_elements; - rich_location *missing_brace_richloc; -}; - -static struct initializer_stack *initializer_stack; - -/* Prepare to parse and output the initializer for variable DECL. */ - -void -start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level, - rich_location *richloc) -{ - const char *locus; - struct initializer_stack *p = XNEW (struct initializer_stack); - - p->decl = constructor_decl; - p->require_constant_value = require_constant_value; - p->require_constant_elements = require_constant_elements; - p->constructor_stack = constructor_stack; - p->constructor_range_stack = constructor_range_stack; - p->elements = constructor_elements; - p->spelling = spelling; - p->spelling_base = spelling_base; - p->spelling_size = spelling_size; - p->top_level = constructor_top_level; - p->next = initializer_stack; - p->missing_brace_richloc = richloc; - initializer_stack = p; - - constructor_decl = decl; - constructor_designated = 0; - constructor_top_level = top_level; - - if (decl != NULL_TREE && decl != error_mark_node) - { - require_constant_value = TREE_STATIC (decl); - require_constant_elements - = ((TREE_STATIC (decl) || (pedantic && !flag_isoc99)) - /* For a scalar, you can always use any value to initialize, - even within braces. */ - && AGGREGATE_TYPE_P (TREE_TYPE (decl))); - locus = identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (decl))); - } - else - { - require_constant_value = 0; - require_constant_elements = 0; - locus = _("(anonymous)"); - } - - constructor_stack = 0; - constructor_range_stack = 0; - - found_missing_braces = 0; - - spelling_base = 0; - spelling_size = 0; - RESTORE_SPELLING_DEPTH (0); - - if (locus) - push_string (locus); -} - -void -finish_init (void) -{ - struct initializer_stack *p = initializer_stack; - - /* Free the whole constructor stack of this initializer. */ - while (constructor_stack) - { - struct constructor_stack *q = constructor_stack; - constructor_stack = q->next; - XDELETE (q); - } - - gcc_assert (!constructor_range_stack); - - /* Pop back to the data of the outer initializer (if any). */ - XDELETE (spelling_base); - - constructor_decl = p->decl; - require_constant_value = p->require_constant_value; - require_constant_elements = p->require_constant_elements; - constructor_stack = p->constructor_stack; - constructor_range_stack = p->constructor_range_stack; - constructor_elements = p->elements; - spelling = p->spelling; - spelling_base = p->spelling_base; - spelling_size = p->spelling_size; - constructor_top_level = p->top_level; - initializer_stack = p->next; - XDELETE (p); -} - -/* Call here when we see the initializer is surrounded by braces. - This is instead of a call to push_init_level; - it is matched by a call to pop_init_level. - - TYPE is the type to initialize, for a constructor expression. - For an initializer for a decl, TYPE is zero. */ - -void -really_start_incremental_init (tree type) -{ - struct constructor_stack *p = XNEW (struct constructor_stack); - - if (type == NULL_TREE) - type = TREE_TYPE (constructor_decl); - - if (VECTOR_TYPE_P (type) - && TYPE_VECTOR_OPAQUE (type)) - error ("opaque vector types cannot be initialized"); - - p->type = constructor_type; - p->fields = constructor_fields; - p->index = constructor_index; - p->max_index = constructor_max_index; - p->unfilled_index = constructor_unfilled_index; - p->unfilled_fields = constructor_unfilled_fields; - p->bit_index = constructor_bit_index; - p->elements = constructor_elements; - p->constant = constructor_constant; - p->simple = constructor_simple; - p->nonconst = constructor_nonconst; - p->erroneous = constructor_erroneous; - p->pending_elts = constructor_pending_elts; - p->depth = constructor_depth; - p->replacement_value.value = 0; - p->replacement_value.original_code = ERROR_MARK; - p->replacement_value.original_type = NULL; - p->implicit = 0; - p->range_stack = 0; - p->outer = 0; - p->incremental = constructor_incremental; - p->designated = constructor_designated; - p->designator_depth = designator_depth; - p->next = 0; - constructor_stack = p; - - constructor_constant = 1; - constructor_simple = 1; - constructor_nonconst = 0; - constructor_depth = SPELLING_DEPTH (); - constructor_elements = NULL; - constructor_pending_elts = 0; - constructor_type = type; - constructor_incremental = 1; - constructor_designated = 0; - constructor_zeroinit = 1; - designator_depth = 0; - designator_erroneous = 0; - - if (RECORD_OR_UNION_TYPE_P (constructor_type)) - { - constructor_fields = TYPE_FIELDS (constructor_type); - /* Skip any nameless bit fields at the beginning. */ - while (constructor_fields != NULL_TREE - && DECL_UNNAMED_BIT_FIELD (constructor_fields)) - constructor_fields = DECL_CHAIN (constructor_fields); - - constructor_unfilled_fields = constructor_fields; - constructor_bit_index = bitsize_zero_node; - } - else if (TREE_CODE (constructor_type) == ARRAY_TYPE) - { - if (TYPE_DOMAIN (constructor_type)) - { - constructor_max_index - = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); - - /* Detect non-empty initializations of zero-length arrays. */ - if (constructor_max_index == NULL_TREE - && TYPE_SIZE (constructor_type)) - constructor_max_index = integer_minus_one_node; - - /* constructor_max_index needs to be an INTEGER_CST. Attempts - to initialize VLAs will cause a proper error; avoid tree - checking errors as well by setting a safe value. */ - if (constructor_max_index - && TREE_CODE (constructor_max_index) != INTEGER_CST) - constructor_max_index = integer_minus_one_node; - - constructor_index - = convert (bitsizetype, - TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); - } - else - { - constructor_index = bitsize_zero_node; - constructor_max_index = NULL_TREE; - } - - constructor_unfilled_index = constructor_index; - } - else if (gnu_vector_type_p (constructor_type)) - { - /* Vectors are like simple fixed-size arrays. */ - constructor_max_index = - bitsize_int (TYPE_VECTOR_SUBPARTS (constructor_type) - 1); - constructor_index = bitsize_zero_node; - constructor_unfilled_index = constructor_index; - } - else - { - /* Handle the case of int x = {5}; */ - constructor_fields = constructor_type; - constructor_unfilled_fields = constructor_type; - } -} - -extern location_t last_init_list_comma; - -/* Called when we see an open brace for a nested initializer. Finish - off any pending levels with implicit braces. */ -void -finish_implicit_inits (location_t loc, struct obstack *braced_init_obstack) -{ - while (constructor_stack->implicit) - { - if (RECORD_OR_UNION_TYPE_P (constructor_type) - && constructor_fields == NULL_TREE) - process_init_element (input_location, - pop_init_level (loc, 1, braced_init_obstack, - last_init_list_comma), - true, braced_init_obstack); - else if (TREE_CODE (constructor_type) == ARRAY_TYPE - && constructor_max_index - && tree_int_cst_lt (constructor_max_index, - constructor_index)) - process_init_element (input_location, - pop_init_level (loc, 1, braced_init_obstack, - last_init_list_comma), - true, braced_init_obstack); - else - break; - } -} - -/* Push down into a subobject, for initialization. - If this is for an explicit set of braces, IMPLICIT is 0. - If it is because the next element belongs at a lower level, - IMPLICIT is 1 (or 2 if the push is because of designator list). */ - -void -push_init_level (location_t loc, int implicit, - struct obstack *braced_init_obstack) -{ - struct constructor_stack *p; - tree value = NULL_TREE; - - /* Unless this is an explicit brace, we need to preserve previous - content if any. */ - if (implicit) - { - if (RECORD_OR_UNION_TYPE_P (constructor_type) && constructor_fields) - value = find_init_member (constructor_fields, braced_init_obstack); - else if (TREE_CODE (constructor_type) == ARRAY_TYPE) - value = find_init_member (constructor_index, braced_init_obstack); - } - - p = XNEW (struct constructor_stack); - p->type = constructor_type; - p->fields = constructor_fields; - p->index = constructor_index; - p->max_index = constructor_max_index; - p->unfilled_index = constructor_unfilled_index; - p->unfilled_fields = constructor_unfilled_fields; - p->bit_index = constructor_bit_index; - p->elements = constructor_elements; - p->constant = constructor_constant; - p->simple = constructor_simple; - p->nonconst = constructor_nonconst; - p->erroneous = constructor_erroneous; - p->pending_elts = constructor_pending_elts; - p->depth = constructor_depth; - p->replacement_value.value = NULL_TREE; - p->replacement_value.original_code = ERROR_MARK; - p->replacement_value.original_type = NULL; - p->implicit = implicit; - p->outer = 0; - p->incremental = constructor_incremental; - p->designated = constructor_designated; - p->designator_depth = designator_depth; - p->next = constructor_stack; - p->range_stack = 0; - constructor_stack = p; - - constructor_constant = 1; - constructor_simple = 1; - constructor_nonconst = 0; - constructor_depth = SPELLING_DEPTH (); - constructor_elements = NULL; - constructor_incremental = 1; - constructor_designated = 0; - constructor_pending_elts = 0; - if (!implicit) - { - p->range_stack = constructor_range_stack; - constructor_range_stack = 0; - designator_depth = 0; - designator_erroneous = 0; - } - - /* Don't die if an entire brace-pair level is superfluous - in the containing level. */ - if (constructor_type == NULL_TREE) - ; - else if (RECORD_OR_UNION_TYPE_P (constructor_type)) - { - /* Don't die if there are extra init elts at the end. */ - if (constructor_fields == NULL_TREE) - constructor_type = NULL_TREE; - else - { - constructor_type = TREE_TYPE (constructor_fields); - push_member_name (constructor_fields); - constructor_depth++; - } - /* If upper initializer is designated, then mark this as - designated too to prevent bogus warnings. */ - constructor_designated = p->designated; - } - else if (TREE_CODE (constructor_type) == ARRAY_TYPE) - { - constructor_type = TREE_TYPE (constructor_type); - push_array_bounds (tree_to_uhwi (constructor_index)); - constructor_depth++; - } - - if (constructor_type == NULL_TREE) - { - error_init (loc, "extra brace group at end of initializer"); - constructor_fields = NULL_TREE; - constructor_unfilled_fields = NULL_TREE; - return; - } - - if (value && TREE_CODE (value) == CONSTRUCTOR) - { - constructor_constant = TREE_CONSTANT (value); - constructor_simple = TREE_STATIC (value); - constructor_nonconst = CONSTRUCTOR_NON_CONST (value); - constructor_elements = CONSTRUCTOR_ELTS (value); - if (!vec_safe_is_empty (constructor_elements) - && (TREE_CODE (constructor_type) == RECORD_TYPE - || TREE_CODE (constructor_type) == ARRAY_TYPE)) - set_nonincremental_init (braced_init_obstack); - } - - if (implicit == 1) - { - found_missing_braces = 1; - if (initializer_stack->missing_brace_richloc) - initializer_stack->missing_brace_richloc->add_fixit_insert_before - (loc, "{"); - } - - if (RECORD_OR_UNION_TYPE_P (constructor_type)) - { - constructor_fields = TYPE_FIELDS (constructor_type); - /* Skip any nameless bit fields at the beginning. */ - while (constructor_fields != NULL_TREE - && DECL_UNNAMED_BIT_FIELD (constructor_fields)) - constructor_fields = DECL_CHAIN (constructor_fields); - - constructor_unfilled_fields = constructor_fields; - constructor_bit_index = bitsize_zero_node; - } - else if (gnu_vector_type_p (constructor_type)) - { - /* Vectors are like simple fixed-size arrays. */ - constructor_max_index = - bitsize_int (TYPE_VECTOR_SUBPARTS (constructor_type) - 1); - constructor_index = bitsize_int (0); - constructor_unfilled_index = constructor_index; - } - else if (TREE_CODE (constructor_type) == ARRAY_TYPE) - { - if (TYPE_DOMAIN (constructor_type)) - { - constructor_max_index - = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); - - /* Detect non-empty initializations of zero-length arrays. */ - if (constructor_max_index == NULL_TREE - && TYPE_SIZE (constructor_type)) - constructor_max_index = integer_minus_one_node; - - /* constructor_max_index needs to be an INTEGER_CST. Attempts - to initialize VLAs will cause a proper error; avoid tree - checking errors as well by setting a safe value. */ - if (constructor_max_index - && TREE_CODE (constructor_max_index) != INTEGER_CST) - constructor_max_index = integer_minus_one_node; - - constructor_index - = convert (bitsizetype, - TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); - } - else - constructor_index = bitsize_zero_node; - - constructor_unfilled_index = constructor_index; - if (value && TREE_CODE (value) == STRING_CST) - { - /* We need to split the char/wchar array into individual - characters, so that we don't have to special case it - everywhere. */ - set_nonincremental_init_from_string (value, braced_init_obstack); - } - } - else - { - if (constructor_type != error_mark_node) - warning_init (input_location, 0, "braces around scalar initializer"); - constructor_fields = constructor_type; - constructor_unfilled_fields = constructor_type; - } -} - -/* At the end of an implicit or explicit brace level, - finish up that level of constructor. If a single expression - with redundant braces initialized that level, return the - c_expr structure for that expression. Otherwise, the original_code - element is set to ERROR_MARK. - If we were outputting the elements as they are read, return 0 as the value - from inner levels (process_init_element ignores that), - but return error_mark_node as the value from the outermost level - (that's what we want to put in DECL_INITIAL). - Otherwise, return a CONSTRUCTOR expression as the value. */ - -struct c_expr -pop_init_level (location_t loc, int implicit, - struct obstack *braced_init_obstack, - location_t insert_before) -{ - struct constructor_stack *p; - struct c_expr ret; - ret.value = NULL_TREE; - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - - if (implicit == 0) - { - /* When we come to an explicit close brace, - pop any inner levels that didn't have explicit braces. */ - while (constructor_stack->implicit) - process_init_element (input_location, - pop_init_level (loc, 1, braced_init_obstack, - insert_before), - true, braced_init_obstack); - gcc_assert (!constructor_range_stack); - } - else - if (initializer_stack->missing_brace_richloc) - initializer_stack->missing_brace_richloc->add_fixit_insert_before - (insert_before, "}"); - - /* Now output all pending elements. */ - constructor_incremental = 1; - output_pending_init_elements (1, braced_init_obstack); - - p = constructor_stack; - - /* Error for initializing a flexible array member, or a zero-length - array member in an inappropriate context. */ - if (constructor_type && constructor_fields - && TREE_CODE (constructor_type) == ARRAY_TYPE - && TYPE_DOMAIN (constructor_type) - && !TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type))) - { - /* Silently discard empty initializations. The parser will - already have pedwarned for empty brackets. */ - if (integer_zerop (constructor_unfilled_index)) - constructor_type = NULL_TREE; - else - { - gcc_assert (!TYPE_SIZE (constructor_type)); - - if (constructor_depth > 2) - error_init (loc, "initialization of flexible array member in a nested context"); - else - pedwarn_init (loc, OPT_Wpedantic, - "initialization of a flexible array member"); - - /* We have already issued an error message for the existence - of a flexible array member not at the end of the structure. - Discard the initializer so that we do not die later. */ - if (DECL_CHAIN (constructor_fields) != NULL_TREE) - constructor_type = NULL_TREE; - } - } - - switch (vec_safe_length (constructor_elements)) - { - case 0: - /* Initialization with { } counts as zeroinit. */ - constructor_zeroinit = 1; - break; - case 1: - /* This might be zeroinit as well. */ - if (integer_zerop ((*constructor_elements)[0].value)) - constructor_zeroinit = 1; - break; - default: - /* If the constructor has more than one element, it can't be { 0 }. */ - constructor_zeroinit = 0; - break; - } - - /* Warn when some structs are initialized with direct aggregation. */ - if (!implicit && found_missing_braces && warn_missing_braces - && !constructor_zeroinit) - { - gcc_assert (initializer_stack->missing_brace_richloc); - warning_at (initializer_stack->missing_brace_richloc, - OPT_Wmissing_braces, - "missing braces around initializer"); - } - - /* Warn when some struct elements are implicitly initialized to zero. */ - if (warn_missing_field_initializers - && constructor_type - && TREE_CODE (constructor_type) == RECORD_TYPE - && constructor_unfilled_fields) - { - /* Do not warn for flexible array members or zero-length arrays. */ - while (constructor_unfilled_fields - && (!DECL_SIZE (constructor_unfilled_fields) - || integer_zerop (DECL_SIZE (constructor_unfilled_fields)))) - constructor_unfilled_fields = DECL_CHAIN (constructor_unfilled_fields); - - if (constructor_unfilled_fields - /* Do not warn if this level of the initializer uses member - designators; it is likely to be deliberate. */ - && !constructor_designated - /* Do not warn about initializing with { 0 } or with { }. */ - && !constructor_zeroinit) - { - if (warning_at (input_location, OPT_Wmissing_field_initializers, - "missing initializer for field %qD of %qT", - constructor_unfilled_fields, - constructor_type)) - inform (DECL_SOURCE_LOCATION (constructor_unfilled_fields), - "%qD declared here", constructor_unfilled_fields); - } - } - - /* Pad out the end of the structure. */ - if (p->replacement_value.value) - /* If this closes a superfluous brace pair, - just pass out the element between them. */ - ret = p->replacement_value; - else if (constructor_type == NULL_TREE) - ; - else if (!RECORD_OR_UNION_TYPE_P (constructor_type) - && TREE_CODE (constructor_type) != ARRAY_TYPE - && !gnu_vector_type_p (constructor_type)) - { - /* A nonincremental scalar initializer--just return - the element, after verifying there is just one. */ - if (vec_safe_is_empty (constructor_elements)) - { - if (!constructor_erroneous && constructor_type != error_mark_node) - error_init (loc, "empty scalar initializer"); - ret.value = error_mark_node; - } - else if (vec_safe_length (constructor_elements) != 1) - { - error_init (loc, "extra elements in scalar initializer"); - ret.value = (*constructor_elements)[0].value; - } - else - ret.value = (*constructor_elements)[0].value; - } - else - { - if (constructor_erroneous) - ret.value = error_mark_node; - else - { - ret.value = build_constructor (constructor_type, - constructor_elements); - if (constructor_constant) - TREE_CONSTANT (ret.value) = 1; - if (constructor_constant && constructor_simple) - TREE_STATIC (ret.value) = 1; - if (constructor_nonconst) - CONSTRUCTOR_NON_CONST (ret.value) = 1; - } - } - - if (ret.value && TREE_CODE (ret.value) != CONSTRUCTOR) - { - if (constructor_nonconst) - ret.original_code = C_MAYBE_CONST_EXPR; - else if (ret.original_code == C_MAYBE_CONST_EXPR) - ret.original_code = ERROR_MARK; - } - - constructor_type = p->type; - constructor_fields = p->fields; - constructor_index = p->index; - constructor_max_index = p->max_index; - constructor_unfilled_index = p->unfilled_index; - constructor_unfilled_fields = p->unfilled_fields; - constructor_bit_index = p->bit_index; - constructor_elements = p->elements; - constructor_constant = p->constant; - constructor_simple = p->simple; - constructor_nonconst = p->nonconst; - constructor_erroneous = p->erroneous; - constructor_incremental = p->incremental; - constructor_designated = p->designated; - designator_depth = p->designator_depth; - constructor_pending_elts = p->pending_elts; - constructor_depth = p->depth; - if (!p->implicit) - constructor_range_stack = p->range_stack; - RESTORE_SPELLING_DEPTH (constructor_depth); - - constructor_stack = p->next; - XDELETE (p); - - if (ret.value == NULL_TREE && constructor_stack == 0) - ret.value = error_mark_node; - return ret; -} - -/* Common handling for both array range and field name designators. - ARRAY argument is nonzero for array ranges. Returns false for success. */ - -static bool -set_designator (location_t loc, bool array, - struct obstack *braced_init_obstack) -{ - tree subtype; - enum tree_code subcode; - - /* Don't die if an entire brace-pair level is superfluous - in the containing level, or for an erroneous type. */ - if (constructor_type == NULL_TREE || constructor_type == error_mark_node) - return true; - - /* If there were errors in this designator list already, bail out - silently. */ - if (designator_erroneous) - return true; - - /* Likewise for an initializer for a variable-size type. Those are - diagnosed in digest_init. */ - if (COMPLETE_TYPE_P (constructor_type) - && TREE_CODE (TYPE_SIZE (constructor_type)) != INTEGER_CST) - return true; - - if (!designator_depth) - { - gcc_assert (!constructor_range_stack); - - /* Designator list starts at the level of closest explicit - braces. */ - while (constructor_stack->implicit) - process_init_element (input_location, - pop_init_level (loc, 1, braced_init_obstack, - last_init_list_comma), - true, braced_init_obstack); - constructor_designated = 1; - return false; - } - - switch (TREE_CODE (constructor_type)) - { - case RECORD_TYPE: - case UNION_TYPE: - subtype = TREE_TYPE (constructor_fields); - if (subtype != error_mark_node) - subtype = TYPE_MAIN_VARIANT (subtype); - break; - case ARRAY_TYPE: - subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type)); - break; - default: - gcc_unreachable (); - } - - subcode = TREE_CODE (subtype); - if (array && subcode != ARRAY_TYPE) - { - error_init (loc, "array index in non-array initializer"); - return true; - } - else if (!array && subcode != RECORD_TYPE && subcode != UNION_TYPE) - { - error_init (loc, "field name not in record or union initializer"); - return true; - } - - constructor_designated = 1; - finish_implicit_inits (loc, braced_init_obstack); - push_init_level (loc, 2, braced_init_obstack); - return false; -} - -/* If there are range designators in designator list, push a new designator - to constructor_range_stack. RANGE_END is end of such stack range or - NULL_TREE if there is no range designator at this level. */ - -static void -push_range_stack (tree range_end, struct obstack * braced_init_obstack) -{ - struct constructor_range_stack *p; - - p = (struct constructor_range_stack *) - obstack_alloc (braced_init_obstack, - sizeof (struct constructor_range_stack)); - p->prev = constructor_range_stack; - p->next = 0; - p->fields = constructor_fields; - p->range_start = constructor_index; - p->index = constructor_index; - p->stack = constructor_stack; - p->range_end = range_end; - if (constructor_range_stack) - constructor_range_stack->next = p; - constructor_range_stack = p; -} - -/* Within an array initializer, specify the next index to be initialized. - FIRST is that index. If LAST is nonzero, then initialize a range - of indices, running from FIRST through LAST. */ - -void -set_init_index (location_t loc, tree first, tree last, - struct obstack *braced_init_obstack) -{ - if (set_designator (loc, true, braced_init_obstack)) - return; - - designator_erroneous = 1; - - if (!INTEGRAL_TYPE_P (TREE_TYPE (first)) - || (last && !INTEGRAL_TYPE_P (TREE_TYPE (last)))) - { - error_init (loc, "array index in initializer not of integer type"); - return; - } - - if (TREE_CODE (first) != INTEGER_CST) - { - first = c_fully_fold (first, false, NULL); - if (TREE_CODE (first) == INTEGER_CST) - pedwarn_init (loc, OPT_Wpedantic, - "array index in initializer is not " - "an integer constant expression"); - } - - if (last && TREE_CODE (last) != INTEGER_CST) - { - last = c_fully_fold (last, false, NULL); - if (TREE_CODE (last) == INTEGER_CST) - pedwarn_init (loc, OPT_Wpedantic, - "array index in initializer is not " - "an integer constant expression"); - } - - if (TREE_CODE (first) != INTEGER_CST) - error_init (loc, "nonconstant array index in initializer"); - else if (last != NULL_TREE && TREE_CODE (last) != INTEGER_CST) - error_init (loc, "nonconstant array index in initializer"); - else if (TREE_CODE (constructor_type) != ARRAY_TYPE) - error_init (loc, "array index in non-array initializer"); - else if (tree_int_cst_sgn (first) == -1) - error_init (loc, "array index in initializer exceeds array bounds"); - else if (constructor_max_index - && tree_int_cst_lt (constructor_max_index, first)) - error_init (loc, "array index in initializer exceeds array bounds"); - else - { - constant_expression_warning (first); - if (last) - constant_expression_warning (last); - constructor_index = convert (bitsizetype, first); - if (tree_int_cst_lt (constructor_index, first)) - { - constructor_index = copy_node (constructor_index); - TREE_OVERFLOW (constructor_index) = 1; - } - - if (last) - { - if (tree_int_cst_equal (first, last)) - last = NULL_TREE; - else if (tree_int_cst_lt (last, first)) - { - error_init (loc, "empty index range in initializer"); - last = NULL_TREE; - } - else - { - last = convert (bitsizetype, last); - if (constructor_max_index != NULL_TREE - && tree_int_cst_lt (constructor_max_index, last)) - { - error_init (loc, "array index range in initializer exceeds " - "array bounds"); - last = NULL_TREE; - } - } - } - - designator_depth++; - designator_erroneous = 0; - if (constructor_range_stack || last) - push_range_stack (last, braced_init_obstack); - } -} - -/* Within a struct initializer, specify the next field to be initialized. */ - -void -set_init_label (location_t loc, tree fieldname, location_t fieldname_loc, - struct obstack *braced_init_obstack) -{ - tree field; - - if (set_designator (loc, false, braced_init_obstack)) - return; - - designator_erroneous = 1; - - if (!RECORD_OR_UNION_TYPE_P (constructor_type)) - { - error_init (loc, "field name not in record or union initializer"); - return; - } - - field = lookup_field (constructor_type, fieldname); - - if (field == NULL_TREE) - { - tree guessed_id = lookup_field_fuzzy (constructor_type, fieldname); - if (guessed_id) - { - gcc_rich_location rich_loc (fieldname_loc); - rich_loc.add_fixit_misspelled_id (fieldname_loc, guessed_id); - error_at (&rich_loc, - "%qT has no member named %qE; did you mean %qE?", - constructor_type, fieldname, guessed_id); - } - else - error_at (fieldname_loc, "%qT has no member named %qE", - constructor_type, fieldname); - } - else - do - { - constructor_fields = TREE_VALUE (field); - designator_depth++; - designator_erroneous = 0; - if (constructor_range_stack) - push_range_stack (NULL_TREE, braced_init_obstack); - field = TREE_CHAIN (field); - if (field) - { - if (set_designator (loc, false, braced_init_obstack)) - return; - } - } - while (field != NULL_TREE); -} - -/* Add a new initializer to the tree of pending initializers. PURPOSE - identifies the initializer, either array index or field in a structure. - VALUE is the value of that index or field. If ORIGTYPE is not - NULL_TREE, it is the original type of VALUE. - - IMPLICIT is true if value comes from pop_init_level (1), - the new initializer has been merged with the existing one - and thus no warnings should be emitted about overriding an - existing initializer. */ - -static void -add_pending_init (location_t loc, tree purpose, tree value, tree origtype, - bool implicit, struct obstack *braced_init_obstack) -{ - struct init_node *p, **q, *r; - - q = &constructor_pending_elts; - p = 0; - - if (TREE_CODE (constructor_type) == ARRAY_TYPE) - { - while (*q != 0) - { - p = *q; - if (tree_int_cst_lt (purpose, p->purpose)) - q = &p->left; - else if (tree_int_cst_lt (p->purpose, purpose)) - q = &p->right; - else - { - if (!implicit) - { - if (TREE_SIDE_EFFECTS (p->value)) - warning_init (loc, OPT_Woverride_init_side_effects, - "initialized field with side-effects " - "overwritten"); - else if (warn_override_init) - warning_init (loc, OPT_Woverride_init, - "initialized field overwritten"); - } - p->value = value; - p->origtype = origtype; - return; - } - } - } - else - { - tree bitpos; - - bitpos = bit_position (purpose); - while (*q != NULL) - { - p = *q; - if (tree_int_cst_lt (bitpos, bit_position (p->purpose))) - q = &p->left; - else if (p->purpose != purpose) - q = &p->right; - else - { - if (!implicit) - { - if (TREE_SIDE_EFFECTS (p->value)) - warning_init (loc, OPT_Woverride_init_side_effects, - "initialized field with side-effects " - "overwritten"); - else if (warn_override_init) - warning_init (loc, OPT_Woverride_init, - "initialized field overwritten"); - } - p->value = value; - p->origtype = origtype; - return; - } - } - } - - r = (struct init_node *) obstack_alloc (braced_init_obstack, - sizeof (struct init_node)); - r->purpose = purpose; - r->value = value; - r->origtype = origtype; - - *q = r; - r->parent = p; - r->left = 0; - r->right = 0; - r->balance = 0; - - while (p) - { - struct init_node *s; - - if (r == p->left) - { - if (p->balance == 0) - p->balance = -1; - else if (p->balance < 0) - { - if (r->balance < 0) - { - /* L rotation. */ - p->left = r->right; - if (p->left) - p->left->parent = p; - r->right = p; - - p->balance = 0; - r->balance = 0; - - s = p->parent; - p->parent = r; - r->parent = s; - if (s) - { - if (s->left == p) - s->left = r; - else - s->right = r; - } - else - constructor_pending_elts = r; - } - else - { - /* LR rotation. */ - struct init_node *t = r->right; - - r->right = t->left; - if (r->right) - r->right->parent = r; - t->left = r; - - p->left = t->right; - if (p->left) - p->left->parent = p; - t->right = p; - - p->balance = t->balance < 0; - r->balance = -(t->balance > 0); - t->balance = 0; - - s = p->parent; - p->parent = t; - r->parent = t; - t->parent = s; - if (s) - { - if (s->left == p) - s->left = t; - else - s->right = t; - } - else - constructor_pending_elts = t; - } - break; - } - else - { - /* p->balance == +1; growth of left side balances the node. */ - p->balance = 0; - break; - } - } - else /* r == p->right */ - { - if (p->balance == 0) - /* Growth propagation from right side. */ - p->balance++; - else if (p->balance > 0) - { - if (r->balance > 0) - { - /* R rotation. */ - p->right = r->left; - if (p->right) - p->right->parent = p; - r->left = p; - - p->balance = 0; - r->balance = 0; - - s = p->parent; - p->parent = r; - r->parent = s; - if (s) - { - if (s->left == p) - s->left = r; - else - s->right = r; - } - else - constructor_pending_elts = r; - } - else /* r->balance == -1 */ - { - /* RL rotation */ - struct init_node *t = r->left; - - r->left = t->right; - if (r->left) - r->left->parent = r; - t->right = r; - - p->right = t->left; - if (p->right) - p->right->parent = p; - t->left = p; - - r->balance = (t->balance < 0); - p->balance = -(t->balance > 0); - t->balance = 0; - - s = p->parent; - p->parent = t; - r->parent = t; - t->parent = s; - if (s) - { - if (s->left == p) - s->left = t; - else - s->right = t; - } - else - constructor_pending_elts = t; - } - break; - } - else - { - /* p->balance == -1; growth of right side balances the node. */ - p->balance = 0; - break; - } - } - - r = p; - p = p->parent; - } -} - -/* Build AVL tree from a sorted chain. */ - -static void -set_nonincremental_init (struct obstack * braced_init_obstack) -{ - unsigned HOST_WIDE_INT ix; - tree index, value; - - if (TREE_CODE (constructor_type) != RECORD_TYPE - && TREE_CODE (constructor_type) != ARRAY_TYPE) - return; - - FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value) - add_pending_init (input_location, index, value, NULL_TREE, true, - braced_init_obstack); - constructor_elements = NULL; - if (TREE_CODE (constructor_type) == RECORD_TYPE) - { - constructor_unfilled_fields = TYPE_FIELDS (constructor_type); - /* Skip any nameless bit fields at the beginning. */ - while (constructor_unfilled_fields != NULL_TREE - && DECL_UNNAMED_BIT_FIELD (constructor_unfilled_fields)) - constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields); - - } - else if (TREE_CODE (constructor_type) == ARRAY_TYPE) - { - if (TYPE_DOMAIN (constructor_type)) - constructor_unfilled_index - = convert (bitsizetype, - TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); - else - constructor_unfilled_index = bitsize_zero_node; - } - constructor_incremental = 0; -} - -/* Build AVL tree from a string constant. */ - -static void -set_nonincremental_init_from_string (tree str, - struct obstack * braced_init_obstack) -{ - tree value, purpose, type; - HOST_WIDE_INT val[2]; - const char *p, *end; - int byte, wchar_bytes, charwidth, bitpos; - - gcc_assert (TREE_CODE (constructor_type) == ARRAY_TYPE); - - wchar_bytes = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str))) / BITS_PER_UNIT; - charwidth = TYPE_PRECISION (char_type_node); - gcc_assert ((size_t) wchar_bytes * charwidth - <= ARRAY_SIZE (val) * HOST_BITS_PER_WIDE_INT); - type = TREE_TYPE (constructor_type); - p = TREE_STRING_POINTER (str); - end = p + TREE_STRING_LENGTH (str); - - for (purpose = bitsize_zero_node; - p < end - && !(constructor_max_index - && tree_int_cst_lt (constructor_max_index, purpose)); - purpose = size_binop (PLUS_EXPR, purpose, bitsize_one_node)) - { - if (wchar_bytes == 1) - { - val[0] = (unsigned char) *p++; - val[1] = 0; - } - else - { - val[1] = 0; - val[0] = 0; - for (byte = 0; byte < wchar_bytes; byte++) - { - if (BYTES_BIG_ENDIAN) - bitpos = (wchar_bytes - byte - 1) * charwidth; - else - bitpos = byte * charwidth; - val[bitpos / HOST_BITS_PER_WIDE_INT] - |= ((unsigned HOST_WIDE_INT) ((unsigned char) *p++)) - << (bitpos % HOST_BITS_PER_WIDE_INT); - } - } - - if (!TYPE_UNSIGNED (type)) - { - bitpos = ((wchar_bytes - 1) * charwidth) + HOST_BITS_PER_CHAR; - if (bitpos < HOST_BITS_PER_WIDE_INT) - { - if (val[0] & (HOST_WIDE_INT_1 << (bitpos - 1))) - { - val[0] |= HOST_WIDE_INT_M1U << bitpos; - val[1] = -1; - } - } - else if (bitpos == HOST_BITS_PER_WIDE_INT) - { - if (val[0] < 0) - val[1] = -1; - } - else if (val[1] & (HOST_WIDE_INT_1 - << (bitpos - 1 - HOST_BITS_PER_WIDE_INT))) - val[1] |= HOST_WIDE_INT_M1U << (bitpos - HOST_BITS_PER_WIDE_INT); - } - - value = wide_int_to_tree (type, - wide_int::from_array (val, 2, - HOST_BITS_PER_WIDE_INT * 2)); - add_pending_init (input_location, purpose, value, NULL_TREE, true, - braced_init_obstack); - } - - constructor_incremental = 0; -} - -/* Return value of FIELD in pending initializer or NULL_TREE if the field was - not initialized yet. */ - -static tree -find_init_member (tree field, struct obstack * braced_init_obstack) -{ - struct init_node *p; - - if (TREE_CODE (constructor_type) == ARRAY_TYPE) - { - if (constructor_incremental - && tree_int_cst_lt (field, constructor_unfilled_index)) - set_nonincremental_init (braced_init_obstack); - - p = constructor_pending_elts; - while (p) - { - if (tree_int_cst_lt (field, p->purpose)) - p = p->left; - else if (tree_int_cst_lt (p->purpose, field)) - p = p->right; - else - return p->value; - } - } - else if (TREE_CODE (constructor_type) == RECORD_TYPE) - { - tree bitpos = bit_position (field); - - if (constructor_incremental - && (!constructor_unfilled_fields - || tree_int_cst_lt (bitpos, - bit_position (constructor_unfilled_fields)))) - set_nonincremental_init (braced_init_obstack); - - p = constructor_pending_elts; - while (p) - { - if (field == p->purpose) - return p->value; - else if (tree_int_cst_lt (bitpos, bit_position (p->purpose))) - p = p->left; - else - p = p->right; - } - } - else if (TREE_CODE (constructor_type) == UNION_TYPE) - { - if (!vec_safe_is_empty (constructor_elements) - && (constructor_elements->last ().index == field)) - return constructor_elements->last ().value; - } - return NULL_TREE; -} - -/* "Output" the next constructor element. - At top level, really output it to assembler code now. - Otherwise, collect it in a list from which we will make a CONSTRUCTOR. - If ORIGTYPE is not NULL_TREE, it is the original type of VALUE. - TYPE is the data type that the containing data type wants here. - FIELD is the field (a FIELD_DECL) or the index that this element fills. - If VALUE is a string constant, STRICT_STRING is true if it is - unparenthesized or we should not warn here for it being parenthesized. - For other types of VALUE, STRICT_STRING is not used. - - PENDING if true means output pending elements that belong - right after this element. (PENDING is normally true; - it is false while outputting pending elements, to avoid recursion.) - - IMPLICIT is true if value comes from pop_init_level (1), - the new initializer has been merged with the existing one - and thus no warnings should be emitted about overriding an - existing initializer. */ - -static void -output_init_element (location_t loc, tree value, tree origtype, - bool strict_string, tree type, tree field, bool pending, - bool implicit, struct obstack * braced_init_obstack) -{ - tree semantic_type = NULL_TREE; - bool maybe_const = true; - bool npc; - - if (type == error_mark_node || value == error_mark_node) - { - constructor_erroneous = 1; - return; - } - if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE - && (TREE_CODE (value) == STRING_CST - || TREE_CODE (value) == COMPOUND_LITERAL_EXPR) - && !(TREE_CODE (value) == STRING_CST - && TREE_CODE (type) == ARRAY_TYPE - && INTEGRAL_TYPE_P (TREE_TYPE (type))) - && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)), - TYPE_MAIN_VARIANT (type))) - value = array_to_pointer_conversion (input_location, value); - - if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR - && require_constant_value && pending) - { - /* As an extension, allow initializing objects with static storage - duration with compound literals (which are then treated just as - the brace enclosed list they contain). */ - if (flag_isoc99) - pedwarn_init (loc, OPT_Wpedantic, "initializer element is not " - "constant"); - tree decl = COMPOUND_LITERAL_EXPR_DECL (value); - value = DECL_INITIAL (decl); - } - - npc = null_pointer_constant_p (value); - if (TREE_CODE (value) == EXCESS_PRECISION_EXPR) - { - semantic_type = TREE_TYPE (value); - value = TREE_OPERAND (value, 0); - } - value = c_fully_fold (value, require_constant_value, &maybe_const); - - if (value == error_mark_node) - constructor_erroneous = 1; - else if (!TREE_CONSTANT (value)) - constructor_constant = 0; - else if (!initializer_constant_valid_p (value, - TREE_TYPE (value), - AGGREGATE_TYPE_P (constructor_type) - && TYPE_REVERSE_STORAGE_ORDER - (constructor_type)) - || (RECORD_OR_UNION_TYPE_P (constructor_type) - && DECL_C_BIT_FIELD (field) - && TREE_CODE (value) != INTEGER_CST)) - constructor_simple = 0; - if (!maybe_const) - constructor_nonconst = 1; - - /* Digest the initializer and issue any errors about incompatible - types before issuing errors about non-constant initializers. */ - tree new_value = value; - if (semantic_type) - new_value = build1 (EXCESS_PRECISION_EXPR, semantic_type, value); - new_value = digest_init (loc, type, new_value, origtype, npc, strict_string, - require_constant_value); - if (new_value == error_mark_node) - { - constructor_erroneous = 1; - return; - } - if (require_constant_value || require_constant_elements) - constant_expression_warning (new_value); - - /* Proceed to check the constness of the original initializer. */ - if (!initializer_constant_valid_p (value, TREE_TYPE (value))) - { - if (require_constant_value) - { - error_init (loc, "initializer element is not constant"); - value = error_mark_node; - } - else if (require_constant_elements) - pedwarn (loc, OPT_Wpedantic, - "initializer element is not computable at load time"); - } - else if (!maybe_const - && (require_constant_value || require_constant_elements)) - pedwarn_init (loc, OPT_Wpedantic, - "initializer element is not a constant expression"); - - /* Issue -Wc++-compat warnings about initializing a bitfield with - enum type. */ - if (warn_cxx_compat - && field != NULL_TREE - && TREE_CODE (field) == FIELD_DECL - && DECL_BIT_FIELD_TYPE (field) != NULL_TREE - && (TYPE_MAIN_VARIANT (DECL_BIT_FIELD_TYPE (field)) - != TYPE_MAIN_VARIANT (type)) - && TREE_CODE (DECL_BIT_FIELD_TYPE (field)) == ENUMERAL_TYPE) - { - tree checktype = origtype != NULL_TREE ? origtype : TREE_TYPE (value); - if (checktype != error_mark_node - && (TYPE_MAIN_VARIANT (checktype) - != TYPE_MAIN_VARIANT (DECL_BIT_FIELD_TYPE (field)))) - warning_init (loc, OPT_Wc___compat, - "enum conversion in initialization is invalid in C++"); - } - - /* If this field is empty and does not have side effects (and is not at - the end of structure), don't do anything other than checking the - initializer. */ - if (field - && (TREE_TYPE (field) == error_mark_node - || (COMPLETE_TYPE_P (TREE_TYPE (field)) - && integer_zerop (TYPE_SIZE (TREE_TYPE (field))) - && !TREE_SIDE_EFFECTS (new_value) - && (TREE_CODE (constructor_type) == ARRAY_TYPE - || DECL_CHAIN (field))))) - return; - - /* Finally, set VALUE to the initializer value digested above. */ - value = new_value; - - /* If this element doesn't come next in sequence, - put it on constructor_pending_elts. */ - if (TREE_CODE (constructor_type) == ARRAY_TYPE - && (!constructor_incremental - || !tree_int_cst_equal (field, constructor_unfilled_index))) - { - if (constructor_incremental - && tree_int_cst_lt (field, constructor_unfilled_index)) - set_nonincremental_init (braced_init_obstack); - - add_pending_init (loc, field, value, origtype, implicit, - braced_init_obstack); - return; - } - else if (TREE_CODE (constructor_type) == RECORD_TYPE - && (!constructor_incremental - || field != constructor_unfilled_fields)) - { - /* We do this for records but not for unions. In a union, - no matter which field is specified, it can be initialized - right away since it starts at the beginning of the union. */ - if (constructor_incremental) - { - if (!constructor_unfilled_fields) - set_nonincremental_init (braced_init_obstack); - else - { - tree bitpos, unfillpos; - - bitpos = bit_position (field); - unfillpos = bit_position (constructor_unfilled_fields); - - if (tree_int_cst_lt (bitpos, unfillpos)) - set_nonincremental_init (braced_init_obstack); - } - } - - add_pending_init (loc, field, value, origtype, implicit, - braced_init_obstack); - return; - } - else if (TREE_CODE (constructor_type) == UNION_TYPE - && !vec_safe_is_empty (constructor_elements)) - { - if (!implicit) - { - if (TREE_SIDE_EFFECTS (constructor_elements->last ().value)) - warning_init (loc, OPT_Woverride_init_side_effects, - "initialized field with side-effects overwritten"); - else if (warn_override_init) - warning_init (loc, OPT_Woverride_init, - "initialized field overwritten"); - } - - /* We can have just one union field set. */ - constructor_elements = NULL; - } - - /* Otherwise, output this element either to - constructor_elements or to the assembler file. */ - - constructor_elt celt = {field, value}; - vec_safe_push (constructor_elements, celt); - - /* Advance the variable that indicates sequential elements output. */ - if (TREE_CODE (constructor_type) == ARRAY_TYPE) - constructor_unfilled_index - = size_binop_loc (input_location, PLUS_EXPR, constructor_unfilled_index, - bitsize_one_node); - else if (TREE_CODE (constructor_type) == RECORD_TYPE) - { - constructor_unfilled_fields - = DECL_CHAIN (constructor_unfilled_fields); - - /* Skip any nameless bit fields. */ - while (constructor_unfilled_fields != NULL_TREE - && DECL_UNNAMED_BIT_FIELD (constructor_unfilled_fields)) - constructor_unfilled_fields = - DECL_CHAIN (constructor_unfilled_fields); - } - else if (TREE_CODE (constructor_type) == UNION_TYPE) - constructor_unfilled_fields = NULL_TREE; - - /* Now output any pending elements which have become next. */ - if (pending) - output_pending_init_elements (0, braced_init_obstack); -} - -/* For two FIELD_DECLs in the same chain, return -1 if field1 - comes before field2, 1 if field1 comes after field2 and - 0 if field1 == field2. */ - -static int -init_field_decl_cmp (tree field1, tree field2) -{ - if (field1 == field2) - return 0; - - tree bitpos1 = bit_position (field1); - tree bitpos2 = bit_position (field2); - if (tree_int_cst_equal (bitpos1, bitpos2)) - { - /* If one of the fields has non-zero bitsize, then that - field must be the last one in a sequence of zero - sized fields, fields after it will have bigger - bit_position. */ - if (TREE_TYPE (field1) != error_mark_node - && COMPLETE_TYPE_P (TREE_TYPE (field1)) - && integer_nonzerop (TREE_TYPE (field1))) - return 1; - if (TREE_TYPE (field2) != error_mark_node - && COMPLETE_TYPE_P (TREE_TYPE (field2)) - && integer_nonzerop (TREE_TYPE (field2))) - return -1; - /* Otherwise, fallback to DECL_CHAIN walk to find out - which field comes earlier. Walk chains of both - fields, so that if field1 and field2 are close to each - other in either order, it is found soon even for large - sequences of zero sized fields. */ - tree f1 = field1, f2 = field2; - while (1) - { - f1 = DECL_CHAIN (f1); - f2 = DECL_CHAIN (f2); - if (f1 == NULL_TREE) - { - gcc_assert (f2); - return 1; - } - if (f2 == NULL_TREE) - return -1; - if (f1 == field2) - return -1; - if (f2 == field1) - return 1; - if (!tree_int_cst_equal (bit_position (f1), bitpos1)) - return 1; - if (!tree_int_cst_equal (bit_position (f2), bitpos1)) - return -1; - } - } - else if (tree_int_cst_lt (bitpos1, bitpos2)) - return -1; - else - return 1; -} - -/* Output any pending elements which have become next. - As we output elements, constructor_unfilled_{fields,index} - advances, which may cause other elements to become next; - if so, they too are output. - - If ALL is 0, we return when there are - no more pending elements to output now. - - If ALL is 1, we output space as necessary so that - we can output all the pending elements. */ -static void -output_pending_init_elements (int all, struct obstack * braced_init_obstack) -{ - struct init_node *elt = constructor_pending_elts; - tree next; - - retry: - - /* Look through the whole pending tree. - If we find an element that should be output now, - output it. Otherwise, set NEXT to the element - that comes first among those still pending. */ - - next = NULL_TREE; - while (elt) - { - if (TREE_CODE (constructor_type) == ARRAY_TYPE) - { - if (tree_int_cst_equal (elt->purpose, - constructor_unfilled_index)) - output_init_element (input_location, elt->value, elt->origtype, - true, TREE_TYPE (constructor_type), - constructor_unfilled_index, false, false, - braced_init_obstack); - else if (tree_int_cst_lt (constructor_unfilled_index, - elt->purpose)) - { - /* Advance to the next smaller node. */ - if (elt->left) - elt = elt->left; - else - { - /* We have reached the smallest node bigger than the - current unfilled index. Fill the space first. */ - next = elt->purpose; - break; - } - } - else - { - /* Advance to the next bigger node. */ - if (elt->right) - elt = elt->right; - else - { - /* We have reached the biggest node in a subtree. Find - the parent of it, which is the next bigger node. */ - while (elt->parent && elt->parent->right == elt) - elt = elt->parent; - elt = elt->parent; - if (elt && tree_int_cst_lt (constructor_unfilled_index, - elt->purpose)) - { - next = elt->purpose; - break; - } - } - } - } - else if (RECORD_OR_UNION_TYPE_P (constructor_type)) - { - /* If the current record is complete we are done. */ - if (constructor_unfilled_fields == NULL_TREE) - break; - - int cmp = init_field_decl_cmp (constructor_unfilled_fields, - elt->purpose); - if (cmp == 0) - output_init_element (input_location, elt->value, elt->origtype, - true, TREE_TYPE (elt->purpose), - elt->purpose, false, false, - braced_init_obstack); - else if (cmp < 0) - { - /* Advance to the next smaller node. */ - if (elt->left) - elt = elt->left; - else - { - /* We have reached the smallest node bigger than the - current unfilled field. Fill the space first. */ - next = elt->purpose; - break; - } - } - else - { - /* Advance to the next bigger node. */ - if (elt->right) - elt = elt->right; - else - { - /* We have reached the biggest node in a subtree. Find - the parent of it, which is the next bigger node. */ - while (elt->parent && elt->parent->right == elt) - elt = elt->parent; - elt = elt->parent; - if (elt - && init_field_decl_cmp (constructor_unfilled_fields, - elt->purpose) < 0) - { - next = elt->purpose; - break; - } - } - } - } - } - - /* Ordinarily return, but not if we want to output all - and there are elements left. */ - if (!(all && next != NULL_TREE)) - return; - - /* If it's not incremental, just skip over the gap, so that after - jumping to retry we will output the next successive element. */ - if (RECORD_OR_UNION_TYPE_P (constructor_type)) - constructor_unfilled_fields = next; - else if (TREE_CODE (constructor_type) == ARRAY_TYPE) - constructor_unfilled_index = next; - - /* ELT now points to the node in the pending tree with the next - initializer to output. */ - goto retry; -} - -/* Expression VALUE coincides with the start of type TYPE in a braced - initializer. Return true if we should treat VALUE as initializing - the first element of TYPE, false if we should treat it as initializing - TYPE as a whole. - - If the initializer is clearly invalid, the question becomes: - which choice gives the best error message? */ - -static bool -initialize_elementwise_p (tree type, tree value) -{ - if (type == error_mark_node || value == error_mark_node) - return false; - - gcc_checking_assert (TYPE_MAIN_VARIANT (type) == type); - - tree value_type = TREE_TYPE (value); - if (value_type == error_mark_node) - return false; - - /* GNU vectors can be initialized elementwise. However, treat any - kind of vector value as initializing the vector type as a whole, - regardless of whether the value is a GNU vector. Such initializers - are valid if and only if they would have been valid in a non-braced - initializer like: - - TYPE foo = VALUE; - - so recursing into the vector type would be at best confusing or at - worst wrong. For example, when -flax-vector-conversions is in effect, - it's possible to initialize a V8HI from a V4SI, even though the vectors - have different element types and different numbers of elements. */ - if (gnu_vector_type_p (type)) - return !VECTOR_TYPE_P (value_type); - - if (AGGREGATE_TYPE_P (type)) - return type != TYPE_MAIN_VARIANT (value_type); - - return false; -} - -/* Add one non-braced element to the current constructor level. - This adjusts the current position within the constructor's type. - This may also start or terminate implicit levels - to handle a partly-braced initializer. - - Once this has found the correct level for the new element, - it calls output_init_element. - - IMPLICIT is true if value comes from pop_init_level (1), - the new initializer has been merged with the existing one - and thus no warnings should be emitted about overriding an - existing initializer. */ - -void -process_init_element (location_t loc, struct c_expr value, bool implicit, - struct obstack * braced_init_obstack) -{ - tree orig_value = value.value; - int string_flag - = (orig_value != NULL_TREE && TREE_CODE (orig_value) == STRING_CST); - bool strict_string = value.original_code == STRING_CST; - bool was_designated = designator_depth != 0; - - designator_depth = 0; - designator_erroneous = 0; - - if (!implicit && value.value && !integer_zerop (value.value)) - constructor_zeroinit = 0; - - /* Handle superfluous braces around string cst as in - char x[] = {"foo"}; */ - if (string_flag - && constructor_type - && !was_designated - && TREE_CODE (constructor_type) == ARRAY_TYPE - && INTEGRAL_TYPE_P (TREE_TYPE (constructor_type)) - && integer_zerop (constructor_unfilled_index)) - { - if (constructor_stack->replacement_value.value) - error_init (loc, "excess elements in % array initializer"); - constructor_stack->replacement_value = value; - return; - } - - if (constructor_stack->replacement_value.value != NULL_TREE) - { - error_init (loc, "excess elements in struct initializer"); - return; - } - - /* Ignore elements of a brace group if it is entirely superfluous - and has already been diagnosed, or if the type is erroneous. */ - if (constructor_type == NULL_TREE || constructor_type == error_mark_node) - return; - - /* Ignore elements of an initializer for a variable-size type. - Those are diagnosed in digest_init. */ - if (COMPLETE_TYPE_P (constructor_type) - && !poly_int_tree_p (TYPE_SIZE (constructor_type))) - return; - - if (!implicit && warn_designated_init && !was_designated - && TREE_CODE (constructor_type) == RECORD_TYPE - && lookup_attribute ("designated_init", - TYPE_ATTRIBUTES (constructor_type))) - warning_init (loc, - OPT_Wdesignated_init, - "positional initialization of field " - "in % declared with % attribute"); - - /* If we've exhausted any levels that didn't have braces, - pop them now. */ - while (constructor_stack->implicit) - { - if (RECORD_OR_UNION_TYPE_P (constructor_type) - && constructor_fields == NULL_TREE) - process_init_element (loc, - pop_init_level (loc, 1, braced_init_obstack, - last_init_list_comma), - true, braced_init_obstack); - else if ((TREE_CODE (constructor_type) == ARRAY_TYPE - || gnu_vector_type_p (constructor_type)) - && constructor_max_index - && tree_int_cst_lt (constructor_max_index, - constructor_index)) - process_init_element (loc, - pop_init_level (loc, 1, braced_init_obstack, - last_init_list_comma), - true, braced_init_obstack); - else - break; - } - - /* In the case of [LO ... HI] = VALUE, only evaluate VALUE once. */ - if (constructor_range_stack) - { - /* If value is a compound literal and we'll be just using its - content, don't put it into a SAVE_EXPR. */ - if (TREE_CODE (value.value) != COMPOUND_LITERAL_EXPR - || !require_constant_value) - { - tree semantic_type = NULL_TREE; - if (TREE_CODE (value.value) == EXCESS_PRECISION_EXPR) - { - semantic_type = TREE_TYPE (value.value); - value.value = TREE_OPERAND (value.value, 0); - } - value.value = save_expr (value.value); - if (semantic_type) - value.value = build1 (EXCESS_PRECISION_EXPR, semantic_type, - value.value); - } - } - - while (1) - { - if (TREE_CODE (constructor_type) == RECORD_TYPE) - { - tree fieldtype; - enum tree_code fieldcode; - - if (constructor_fields == NULL_TREE) - { - pedwarn_init (loc, 0, "excess elements in struct initializer"); - break; - } - - fieldtype = TREE_TYPE (constructor_fields); - if (fieldtype != error_mark_node) - fieldtype = TYPE_MAIN_VARIANT (fieldtype); - fieldcode = TREE_CODE (fieldtype); - - /* Error for non-static initialization of a flexible array member. */ - if (fieldcode == ARRAY_TYPE - && !require_constant_value - && TYPE_SIZE (fieldtype) == NULL_TREE - && DECL_CHAIN (constructor_fields) == NULL_TREE) - { - error_init (loc, "non-static initialization of a flexible " - "array member"); - break; - } - - /* Error for initialization of a flexible array member with - a string constant if the structure is in an array. E.g.: - struct S { int x; char y[]; }; - struct S s[] = { { 1, "foo" } }; - is invalid. */ - if (string_flag - && fieldcode == ARRAY_TYPE - && constructor_depth > 1 - && TYPE_SIZE (fieldtype) == NULL_TREE - && DECL_CHAIN (constructor_fields) == NULL_TREE) - { - bool in_array_p = false; - for (struct constructor_stack *p = constructor_stack; - p && p->type; p = p->next) - if (TREE_CODE (p->type) == ARRAY_TYPE) - { - in_array_p = true; - break; - } - if (in_array_p) - { - error_init (loc, "initialization of flexible array " - "member in a nested context"); - break; - } - } - - /* Accept a string constant to initialize a subarray. */ - if (value.value != NULL_TREE - && fieldcode == ARRAY_TYPE - && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype)) - && string_flag) - value.value = orig_value; - /* Otherwise, if we have come to a subaggregate, - and we don't have an element of its type, push into it. */ - else if (value.value != NULL_TREE - && initialize_elementwise_p (fieldtype, value.value)) - { - push_init_level (loc, 1, braced_init_obstack); - continue; - } - - if (value.value) - { - push_member_name (constructor_fields); - output_init_element (loc, value.value, value.original_type, - strict_string, fieldtype, - constructor_fields, true, implicit, - braced_init_obstack); - RESTORE_SPELLING_DEPTH (constructor_depth); - } - else - /* Do the bookkeeping for an element that was - directly output as a constructor. */ - { - /* For a record, keep track of end position of last field. */ - if (DECL_SIZE (constructor_fields)) - constructor_bit_index - = size_binop_loc (input_location, PLUS_EXPR, - bit_position (constructor_fields), - DECL_SIZE (constructor_fields)); - - /* If the current field was the first one not yet written out, - it isn't now, so update. */ - if (constructor_unfilled_fields == constructor_fields) - { - constructor_unfilled_fields = DECL_CHAIN (constructor_fields); - /* Skip any nameless bit fields. */ - while (constructor_unfilled_fields != 0 - && (DECL_UNNAMED_BIT_FIELD - (constructor_unfilled_fields))) - constructor_unfilled_fields = - DECL_CHAIN (constructor_unfilled_fields); - } - } - - constructor_fields = DECL_CHAIN (constructor_fields); - /* Skip any nameless bit fields at the beginning. */ - while (constructor_fields != NULL_TREE - && DECL_UNNAMED_BIT_FIELD (constructor_fields)) - constructor_fields = DECL_CHAIN (constructor_fields); - } - else if (TREE_CODE (constructor_type) == UNION_TYPE) - { - tree fieldtype; - enum tree_code fieldcode; - - if (constructor_fields == NULL_TREE) - { - pedwarn_init (loc, 0, - "excess elements in union initializer"); - break; - } - - fieldtype = TREE_TYPE (constructor_fields); - if (fieldtype != error_mark_node) - fieldtype = TYPE_MAIN_VARIANT (fieldtype); - fieldcode = TREE_CODE (fieldtype); - - /* Warn that traditional C rejects initialization of unions. - We skip the warning if the value is zero. This is done - under the assumption that the zero initializer in user - code appears conditioned on e.g. __STDC__ to avoid - "missing initializer" warnings and relies on default - initialization to zero in the traditional C case. - We also skip the warning if the initializer is designated, - again on the assumption that this must be conditional on - __STDC__ anyway (and we've already complained about the - member-designator already). */ - if (!in_system_header_at (input_location) && !constructor_designated - && !(value.value && (integer_zerop (value.value) - || real_zerop (value.value)))) - warning (OPT_Wtraditional, "traditional C rejects initialization " - "of unions"); - - /* Accept a string constant to initialize a subarray. */ - if (value.value != NULL_TREE - && fieldcode == ARRAY_TYPE - && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype)) - && string_flag) - value.value = orig_value; - /* Otherwise, if we have come to a subaggregate, - and we don't have an element of its type, push into it. */ - else if (value.value != NULL_TREE - && initialize_elementwise_p (fieldtype, value.value)) - { - push_init_level (loc, 1, braced_init_obstack); - continue; - } - - if (value.value) - { - push_member_name (constructor_fields); - output_init_element (loc, value.value, value.original_type, - strict_string, fieldtype, - constructor_fields, true, implicit, - braced_init_obstack); - RESTORE_SPELLING_DEPTH (constructor_depth); - } - else - /* Do the bookkeeping for an element that was - directly output as a constructor. */ - { - constructor_bit_index = DECL_SIZE (constructor_fields); - constructor_unfilled_fields = DECL_CHAIN (constructor_fields); - } - - constructor_fields = NULL_TREE; - } - else if (TREE_CODE (constructor_type) == ARRAY_TYPE) - { - tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type)); - enum tree_code eltcode = TREE_CODE (elttype); - - /* Accept a string constant to initialize a subarray. */ - if (value.value != NULL_TREE - && eltcode == ARRAY_TYPE - && INTEGRAL_TYPE_P (TREE_TYPE (elttype)) - && string_flag) - value.value = orig_value; - /* Otherwise, if we have come to a subaggregate, - and we don't have an element of its type, push into it. */ - else if (value.value != NULL_TREE - && initialize_elementwise_p (elttype, value.value)) - { - push_init_level (loc, 1, braced_init_obstack); - continue; - } - - if (constructor_max_index != NULL_TREE - && (tree_int_cst_lt (constructor_max_index, constructor_index) - || integer_all_onesp (constructor_max_index))) - { - pedwarn_init (loc, 0, - "excess elements in array initializer"); - break; - } - - /* Now output the actual element. */ - if (value.value) - { - push_array_bounds (tree_to_uhwi (constructor_index)); - output_init_element (loc, value.value, value.original_type, - strict_string, elttype, - constructor_index, true, implicit, - braced_init_obstack); - RESTORE_SPELLING_DEPTH (constructor_depth); - } - - constructor_index - = size_binop_loc (input_location, PLUS_EXPR, - constructor_index, bitsize_one_node); - - if (!value.value) - /* If we are doing the bookkeeping for an element that was - directly output as a constructor, we must update - constructor_unfilled_index. */ - constructor_unfilled_index = constructor_index; - } - else if (gnu_vector_type_p (constructor_type)) - { - tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type)); - - /* Do a basic check of initializer size. Note that vectors - always have a fixed size derived from their type. */ - if (tree_int_cst_lt (constructor_max_index, constructor_index)) - { - pedwarn_init (loc, 0, - "excess elements in vector initializer"); - break; - } - - /* Now output the actual element. */ - if (value.value) - { - if (TREE_CODE (value.value) == VECTOR_CST) - elttype = TYPE_MAIN_VARIANT (constructor_type); - output_init_element (loc, value.value, value.original_type, - strict_string, elttype, - constructor_index, true, implicit, - braced_init_obstack); - } - - constructor_index - = size_binop_loc (input_location, - PLUS_EXPR, constructor_index, bitsize_one_node); - - if (!value.value) - /* If we are doing the bookkeeping for an element that was - directly output as a constructor, we must update - constructor_unfilled_index. */ - constructor_unfilled_index = constructor_index; - } - - /* Handle the sole element allowed in a braced initializer - for a scalar variable. */ - else if (constructor_type != error_mark_node - && constructor_fields == NULL_TREE) - { - pedwarn_init (loc, 0, - "excess elements in scalar initializer"); - break; - } - else - { - if (value.value) - output_init_element (loc, value.value, value.original_type, - strict_string, constructor_type, - NULL_TREE, true, implicit, - braced_init_obstack); - constructor_fields = NULL_TREE; - } - - /* Handle range initializers either at this level or anywhere higher - in the designator stack. */ - if (constructor_range_stack) - { - struct constructor_range_stack *p, *range_stack; - int finish = 0; - - range_stack = constructor_range_stack; - constructor_range_stack = 0; - while (constructor_stack != range_stack->stack) - { - gcc_assert (constructor_stack->implicit); - process_init_element (loc, - pop_init_level (loc, 1, - braced_init_obstack, - last_init_list_comma), - true, braced_init_obstack); - } - for (p = range_stack; - !p->range_end || tree_int_cst_equal (p->index, p->range_end); - p = p->prev) - { - gcc_assert (constructor_stack->implicit); - process_init_element (loc, - pop_init_level (loc, 1, - braced_init_obstack, - last_init_list_comma), - true, braced_init_obstack); - } - - p->index = size_binop_loc (input_location, - PLUS_EXPR, p->index, bitsize_one_node); - if (tree_int_cst_equal (p->index, p->range_end) && !p->prev) - finish = 1; - - while (1) - { - constructor_index = p->index; - constructor_fields = p->fields; - if (finish && p->range_end && p->index == p->range_start) - { - finish = 0; - p->prev = 0; - } - p = p->next; - if (!p) - break; - finish_implicit_inits (loc, braced_init_obstack); - push_init_level (loc, 2, braced_init_obstack); - p->stack = constructor_stack; - if (p->range_end && tree_int_cst_equal (p->index, p->range_end)) - p->index = p->range_start; - } - - if (!finish) - constructor_range_stack = range_stack; - continue; - } - - break; - } - - constructor_range_stack = 0; -} - -/* Build a complete asm-statement, whose components are a CV_QUALIFIER - (guaranteed to be 'volatile' or null) and ARGS (represented using - an ASM_EXPR node). */ -tree -build_asm_stmt (bool is_volatile, tree args) -{ - if (is_volatile) - ASM_VOLATILE_P (args) = 1; - return add_stmt (args); -} - -/* Build an asm-expr, whose components are a STRING, some OUTPUTS, - some INPUTS, and some CLOBBERS. The latter three may be NULL. - SIMPLE indicates whether there was anything at all after the - string in the asm expression -- asm("blah") and asm("blah" : ) - are subtly different. We use a ASM_EXPR node to represent this. - LOC is the location of the asm, and IS_INLINE says whether this - is asm inline. */ -tree -build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, - tree clobbers, tree labels, bool simple, bool is_inline) -{ - tree tail; - tree args; - int i; - const char *constraint; - const char **oconstraints; - bool allows_mem, allows_reg, is_inout; - int ninputs, noutputs; - - ninputs = list_length (inputs); - noutputs = list_length (outputs); - oconstraints = (const char **) alloca (noutputs * sizeof (const char *)); - - string = resolve_asm_operand_names (string, outputs, inputs, labels); - - /* Remove output conversions that change the type but not the mode. */ - for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail)) - { - tree output = TREE_VALUE (tail); - - output = c_fully_fold (output, false, NULL, true); - - /* ??? Really, this should not be here. Users should be using a - proper lvalue, dammit. But there's a long history of using casts - in the output operands. In cases like longlong.h, this becomes a - primitive form of typechecking -- if the cast can be removed, then - the output operand had a type of the proper width; otherwise we'll - get an error. Gross, but ... */ - STRIP_NOPS (output); - - if (!lvalue_or_else (loc, output, lv_asm)) - output = error_mark_node; - - if (output != error_mark_node - && (TREE_READONLY (output) - || TYPE_READONLY (TREE_TYPE (output)) - || (RECORD_OR_UNION_TYPE_P (TREE_TYPE (output)) - && C_TYPE_FIELDS_READONLY (TREE_TYPE (output))))) - readonly_error (loc, output, lv_asm); - - constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); - oconstraints[i] = constraint; - - if (parse_output_constraint (&constraint, i, ninputs, noutputs, - &allows_mem, &allows_reg, &is_inout)) - { - /* If the operand is going to end up in memory, - mark it addressable. */ - if (!allows_reg && !c_mark_addressable (output)) - output = error_mark_node; - if (!(!allows_reg && allows_mem) - && output != error_mark_node - && VOID_TYPE_P (TREE_TYPE (output))) - { - error_at (loc, "invalid use of void expression"); - output = error_mark_node; - } - } - else - output = error_mark_node; - - TREE_VALUE (tail) = output; - } - - for (i = 0, tail = inputs; tail; ++i, tail = TREE_CHAIN (tail)) - { - tree input; - - constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); - input = TREE_VALUE (tail); - - if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0, - oconstraints, &allows_mem, &allows_reg)) - { - /* If the operand is going to end up in memory, - mark it addressable. */ - if (!allows_reg && allows_mem) - { - input = c_fully_fold (input, false, NULL, true); - - /* Strip the nops as we allow this case. FIXME, this really - should be rejected or made deprecated. */ - STRIP_NOPS (input); - if (!c_mark_addressable (input)) - input = error_mark_node; - } - else - { - struct c_expr expr; - memset (&expr, 0, sizeof (expr)); - expr.value = input; - expr = convert_lvalue_to_rvalue (loc, expr, true, false); - input = c_fully_fold (expr.value, false, NULL); - - if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input))) - { - error_at (loc, "invalid use of void expression"); - input = error_mark_node; - } - } - } - else - input = error_mark_node; - - TREE_VALUE (tail) = input; - } - - args = build_stmt (loc, ASM_EXPR, string, outputs, inputs, clobbers, labels); - - /* asm statements without outputs, including simple ones, are treated - as volatile. */ - ASM_INPUT_P (args) = simple; - ASM_VOLATILE_P (args) = (noutputs == 0); - ASM_INLINE_P (args) = is_inline; - - return args; -} - -/* Generate a goto statement to LABEL. LOC is the location of the - GOTO. */ - -tree -c_finish_goto_label (location_t loc, tree label) -{ - tree decl = lookup_label_for_goto (loc, label); - if (!decl) - return NULL_TREE; - TREE_USED (decl) = 1; - { - add_stmt (build_predict_expr (PRED_GOTO, NOT_TAKEN)); - tree t = build1 (GOTO_EXPR, void_type_node, decl); - SET_EXPR_LOCATION (t, loc); - return add_stmt (t); - } -} - -/* Generate a computed goto statement to EXPR. LOC is the location of - the GOTO. */ - -tree -c_finish_goto_ptr (location_t loc, c_expr val) -{ - tree expr = val.value; - tree t; - pedwarn (loc, OPT_Wpedantic, "ISO C forbids %"); - if (expr != error_mark_node - && !POINTER_TYPE_P (TREE_TYPE (expr)) - && !null_pointer_constant_p (expr)) - { - error_at (val.get_location (), - "computed goto must be pointer type"); - expr = build_zero_cst (ptr_type_node); - } - expr = c_fully_fold (expr, false, NULL); - expr = convert (ptr_type_node, expr); - t = build1 (GOTO_EXPR, void_type_node, expr); - SET_EXPR_LOCATION (t, loc); - return add_stmt (t); -} - -/* Generate a C `return' statement. RETVAL is the expression for what - to return, or a null pointer for `return;' with no value. LOC is - the location of the return statement, or the location of the expression, - if the statement has any. If ORIGTYPE is not NULL_TREE, it - is the original type of RETVAL. */ - -tree -c_finish_return (location_t loc, tree retval, tree origtype) -{ - tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)), ret_stmt; - bool no_warning = false; - bool npc = false; - - /* Use the expansion point to handle cases such as returning NULL - in a function returning void. */ - location_t xloc = expansion_point_location_if_in_system_header (loc); - - if (TREE_THIS_VOLATILE (current_function_decl)) - warning_at (xloc, 0, - "function declared % has a % statement"); - - if (retval) - { - tree semantic_type = NULL_TREE; - npc = null_pointer_constant_p (retval); - if (TREE_CODE (retval) == EXCESS_PRECISION_EXPR) - { - semantic_type = TREE_TYPE (retval); - retval = TREE_OPERAND (retval, 0); - } - retval = c_fully_fold (retval, false, NULL); - if (semantic_type - && valtype != NULL_TREE - && TREE_CODE (valtype) != VOID_TYPE) - retval = build1 (EXCESS_PRECISION_EXPR, semantic_type, retval); - } - - if (!retval) - { - current_function_returns_null = 1; - if ((warn_return_type >= 0 || flag_isoc99) - && valtype != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE) - { - bool warned_here; - if (flag_isoc99) - warned_here = pedwarn - (loc, warn_return_type >= 0 ? OPT_Wreturn_type : 0, - "% with no value, in function returning non-void"); - else - warned_here = warning_at - (loc, OPT_Wreturn_type, - "% with no value, in function returning non-void"); - no_warning = true; - if (warned_here) - inform (DECL_SOURCE_LOCATION (current_function_decl), - "declared here"); - } - } - else if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE) - { - current_function_returns_null = 1; - bool warned_here; - if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) - warned_here = pedwarn - (xloc, warn_return_type >= 0 ? OPT_Wreturn_type : 0, - "% with a value, in function returning void"); - else - warned_here = pedwarn - (xloc, OPT_Wpedantic, "ISO C forbids " - "% with expression, in function returning void"); - if (warned_here) - inform (DECL_SOURCE_LOCATION (current_function_decl), - "declared here"); - } - else - { - tree t = convert_for_assignment (loc, UNKNOWN_LOCATION, valtype, - retval, origtype, ic_return, - npc, NULL_TREE, NULL_TREE, 0); - tree res = DECL_RESULT (current_function_decl); - tree inner; - bool save; - - current_function_returns_value = 1; - if (t == error_mark_node) - return NULL_TREE; - - save = in_late_binary_op; - if (TREE_CODE (TREE_TYPE (res)) == BOOLEAN_TYPE - || TREE_CODE (TREE_TYPE (res)) == COMPLEX_TYPE - || (TREE_CODE (TREE_TYPE (t)) == REAL_TYPE - && (TREE_CODE (TREE_TYPE (res)) == INTEGER_TYPE - || TREE_CODE (TREE_TYPE (res)) == ENUMERAL_TYPE) - && sanitize_flags_p (SANITIZE_FLOAT_CAST))) - in_late_binary_op = true; - inner = t = convert (TREE_TYPE (res), t); - in_late_binary_op = save; - - /* Strip any conversions, additions, and subtractions, and see if - we are returning the address of a local variable. Warn if so. */ - while (1) - { - switch (TREE_CODE (inner)) - { - CASE_CONVERT: - case NON_LVALUE_EXPR: - case PLUS_EXPR: - case POINTER_PLUS_EXPR: - inner = TREE_OPERAND (inner, 0); - continue; - - case MINUS_EXPR: - /* If the second operand of the MINUS_EXPR has a pointer - type (or is converted from it), this may be valid, so - don't give a warning. */ - { - tree op1 = TREE_OPERAND (inner, 1); - - while (!POINTER_TYPE_P (TREE_TYPE (op1)) - && (CONVERT_EXPR_P (op1) - || TREE_CODE (op1) == NON_LVALUE_EXPR)) - op1 = TREE_OPERAND (op1, 0); - - if (POINTER_TYPE_P (TREE_TYPE (op1))) - break; - - inner = TREE_OPERAND (inner, 0); - continue; - } - - case ADDR_EXPR: - inner = TREE_OPERAND (inner, 0); - - while (REFERENCE_CLASS_P (inner) - && !INDIRECT_REF_P (inner)) - inner = TREE_OPERAND (inner, 0); - - if (DECL_P (inner) - && !DECL_EXTERNAL (inner) - && !TREE_STATIC (inner) - && DECL_CONTEXT (inner) == current_function_decl - && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))) - { - if (TREE_CODE (inner) == LABEL_DECL) - warning_at (loc, OPT_Wreturn_local_addr, - "function returns address of label"); - else - { - warning_at (loc, OPT_Wreturn_local_addr, - "function returns address of local variable"); - tree zero = build_zero_cst (TREE_TYPE (res)); - t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero); - } - } - break; - - default: - break; - } - - break; - } - - retval = build2 (MODIFY_EXPR, TREE_TYPE (res), res, t); - SET_EXPR_LOCATION (retval, loc); - - if (warn_sequence_point) - verify_sequence_points (retval); - } - - ret_stmt = build_stmt (loc, RETURN_EXPR, retval); - if (no_warning) - suppress_warning (ret_stmt, OPT_Wreturn_type); - return add_stmt (ret_stmt); -} - -struct c_switch { - /* The SWITCH_STMT being built. */ - tree switch_stmt; - - /* The original type of the testing expression, i.e. before the - default conversion is applied. */ - tree orig_type; - - /* A splay-tree mapping the low element of a case range to the high - element, or NULL_TREE if there is no high element. Used to - determine whether or not a new case label duplicates an old case - label. We need a tree, rather than simply a hash table, because - of the GNU case range extension. */ - splay_tree cases; - - /* The bindings at the point of the switch. This is used for - warnings crossing decls when branching to a case label. */ - struct c_spot_bindings *bindings; - - /* Whether the switch includes any break statements. */ - bool break_stmt_seen_p; - - /* The next node on the stack. */ - struct c_switch *next; - - /* Remember whether the controlling expression had boolean type - before integer promotions for the sake of -Wswitch-bool. */ - bool bool_cond_p; -}; - -/* A stack of the currently active switch statements. The innermost - switch statement is on the top of the stack. There is no need to - mark the stack for garbage collection because it is only active - during the processing of the body of a function, and we never - collect at that point. */ - -struct c_switch *c_switch_stack; - -/* Start a C switch statement, testing expression EXP. Return the new - SWITCH_STMT. SWITCH_LOC is the location of the `switch'. - SWITCH_COND_LOC is the location of the switch's condition. - EXPLICIT_CAST_P is true if the expression EXP has an explicit cast. */ - -tree -c_start_switch (location_t switch_loc, - location_t switch_cond_loc, - tree exp, bool explicit_cast_p) -{ - tree orig_type = error_mark_node; - bool bool_cond_p = false; - struct c_switch *cs; - - if (exp != error_mark_node) - { - orig_type = TREE_TYPE (exp); - - if (!INTEGRAL_TYPE_P (orig_type)) - { - if (orig_type != error_mark_node) - { - error_at (switch_cond_loc, "switch quantity not an integer"); - orig_type = error_mark_node; - } - exp = integer_zero_node; - } - else - { - tree type = TYPE_MAIN_VARIANT (orig_type); - tree e = exp; - - /* Warn if the condition has boolean value. */ - while (TREE_CODE (e) == COMPOUND_EXPR) - e = TREE_OPERAND (e, 1); - - if ((TREE_CODE (type) == BOOLEAN_TYPE - || truth_value_p (TREE_CODE (e))) - /* Explicit cast to int suppresses this warning. */ - && !(TREE_CODE (type) == INTEGER_TYPE - && explicit_cast_p)) - bool_cond_p = true; - - if (!in_system_header_at (input_location) - && (type == long_integer_type_node - || type == long_unsigned_type_node)) - warning_at (switch_cond_loc, - OPT_Wtraditional, "% switch expression not " - "converted to % in ISO C"); - - exp = c_fully_fold (exp, false, NULL); - exp = default_conversion (exp); - - if (warn_sequence_point) - verify_sequence_points (exp); - } - } - - /* Add this new SWITCH_STMT to the stack. */ - cs = XNEW (struct c_switch); - cs->switch_stmt = build_stmt (switch_loc, SWITCH_STMT, exp, - NULL_TREE, orig_type, NULL_TREE); - cs->orig_type = orig_type; - cs->cases = splay_tree_new (case_compare, NULL, NULL); - cs->bindings = c_get_switch_bindings (); - cs->break_stmt_seen_p = false; - cs->bool_cond_p = bool_cond_p; - cs->next = c_switch_stack; - c_switch_stack = cs; - - return add_stmt (cs->switch_stmt); -} - -/* Process a case label at location LOC. */ - -tree -do_case (location_t loc, tree low_value, tree high_value) -{ - tree label = NULL_TREE; - - if (low_value && TREE_CODE (low_value) != INTEGER_CST) - { - low_value = c_fully_fold (low_value, false, NULL); - if (TREE_CODE (low_value) == INTEGER_CST) - pedwarn (loc, OPT_Wpedantic, - "case label is not an integer constant expression"); - } - - if (high_value && TREE_CODE (high_value) != INTEGER_CST) - { - high_value = c_fully_fold (high_value, false, NULL); - if (TREE_CODE (high_value) == INTEGER_CST) - pedwarn (input_location, OPT_Wpedantic, - "case label is not an integer constant expression"); - } - - if (c_switch_stack == NULL) - { - if (low_value) - error_at (loc, "case label not within a switch statement"); - else - error_at (loc, "% label not within a switch statement"); - return NULL_TREE; - } - - if (c_check_switch_jump_warnings (c_switch_stack->bindings, - EXPR_LOCATION (c_switch_stack->switch_stmt), - loc)) - return NULL_TREE; - - label = c_add_case_label (loc, c_switch_stack->cases, - SWITCH_STMT_COND (c_switch_stack->switch_stmt), - low_value, high_value); - if (label == error_mark_node) - label = NULL_TREE; - return label; -} - -/* Finish the switch statement. TYPE is the original type of the - controlling expression of the switch, or NULL_TREE. */ - -void -c_finish_switch (tree body, tree type) -{ - struct c_switch *cs = c_switch_stack; - location_t switch_location; - - SWITCH_STMT_BODY (cs->switch_stmt) = body; - - /* Emit warnings as needed. */ - switch_location = EXPR_LOCATION (cs->switch_stmt); - c_do_switch_warnings (cs->cases, switch_location, - type ? type : SWITCH_STMT_TYPE (cs->switch_stmt), - SWITCH_STMT_COND (cs->switch_stmt), cs->bool_cond_p); - if (c_switch_covers_all_cases_p (cs->cases, - SWITCH_STMT_TYPE (cs->switch_stmt))) - SWITCH_STMT_ALL_CASES_P (cs->switch_stmt) = 1; - SWITCH_STMT_NO_BREAK_P (cs->switch_stmt) = !cs->break_stmt_seen_p; - - /* Pop the stack. */ - c_switch_stack = cs->next; - splay_tree_delete (cs->cases); - c_release_switch_bindings (cs->bindings); - XDELETE (cs); -} - -/* Emit an if statement. IF_LOCUS is the location of the 'if'. COND, - THEN_BLOCK and ELSE_BLOCK are expressions to be used; ELSE_BLOCK - may be null. */ - -void -c_finish_if_stmt (location_t if_locus, tree cond, tree then_block, - tree else_block) -{ - tree stmt; - - stmt = build3 (COND_EXPR, void_type_node, cond, then_block, else_block); - SET_EXPR_LOCATION (stmt, if_locus); - add_stmt (stmt); -} - -tree -c_finish_bc_stmt (location_t loc, tree label, bool is_break) -{ - /* In switch statements break is sometimes stylistically used after - a return statement. This can lead to spurious warnings about - control reaching the end of a non-void function when it is - inlined. Note that we are calling block_may_fallthru with - language specific tree nodes; this works because - block_may_fallthru returns true when given something it does not - understand. */ - bool skip = !block_may_fallthru (cur_stmt_list); - - if (is_break) - switch (in_statement) - { - case 0: - error_at (loc, "break statement not within loop or switch"); - return NULL_TREE; - case IN_OMP_BLOCK: - error_at (loc, "invalid exit from OpenMP structured block"); - return NULL_TREE; - case IN_OMP_FOR: - error_at (loc, "break statement used with OpenMP for loop"); - return NULL_TREE; - case IN_ITERATION_STMT: - case IN_OBJC_FOREACH: - break; - default: - gcc_assert (in_statement & IN_SWITCH_STMT); - c_switch_stack->break_stmt_seen_p = true; - break; - } - else - switch (in_statement & ~IN_SWITCH_STMT) - { - case 0: - error_at (loc, "continue statement not within a loop"); - return NULL_TREE; - case IN_OMP_BLOCK: - error_at (loc, "invalid exit from OpenMP structured block"); - return NULL_TREE; - case IN_ITERATION_STMT: - case IN_OMP_FOR: - case IN_OBJC_FOREACH: - break; - default: - gcc_unreachable (); - } - - if (skip) - return NULL_TREE; - else if ((in_statement & IN_OBJC_FOREACH) - && !(is_break && (in_statement & IN_SWITCH_STMT))) - { - /* The foreach expander produces low-level code using gotos instead - of a structured loop construct. */ - gcc_assert (label); - return add_stmt (build_stmt (loc, GOTO_EXPR, label)); - } - return add_stmt (build_stmt (loc, (is_break ? BREAK_STMT : CONTINUE_STMT))); -} - -/* A helper routine for c_process_expr_stmt and c_finish_stmt_expr. */ - -static void -emit_side_effect_warnings (location_t loc, tree expr) -{ - maybe_warn_nodiscard (loc, expr); - if (!warn_unused_value) - return; - if (expr == error_mark_node) - ; - else if (!TREE_SIDE_EFFECTS (expr)) - { - if (!VOID_TYPE_P (TREE_TYPE (expr)) - && !warning_suppressed_p (expr, OPT_Wunused_value)) - warning_at (loc, OPT_Wunused_value, "statement with no effect"); - } - else if (TREE_CODE (expr) == COMPOUND_EXPR) - { - tree r = expr; - location_t cloc = loc; - while (TREE_CODE (r) == COMPOUND_EXPR) - { - if (EXPR_HAS_LOCATION (r)) - cloc = EXPR_LOCATION (r); - r = TREE_OPERAND (r, 1); - } - if (!TREE_SIDE_EFFECTS (r) - && !VOID_TYPE_P (TREE_TYPE (r)) - && !CONVERT_EXPR_P (r) - && !warning_suppressed_p (r, OPT_Wunused_value) - && !warning_suppressed_p (expr, OPT_Wunused_value)) - warning_at (cloc, OPT_Wunused_value, - "right-hand operand of comma expression has no effect"); - } - else - warn_if_unused_value (expr, loc); -} - -/* Process an expression as if it were a complete statement. Emit - diagnostics, but do not call ADD_STMT. LOC is the location of the - statement. */ - -tree -c_process_expr_stmt (location_t loc, tree expr) -{ - tree exprv; - - if (!expr) - return NULL_TREE; - - expr = c_fully_fold (expr, false, NULL); - - if (warn_sequence_point) - verify_sequence_points (expr); - - if (TREE_TYPE (expr) != error_mark_node - && !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr)) - && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE) - error_at (loc, "expression statement has incomplete type"); - - /* If we're not processing a statement expression, warn about unused values. - Warnings for statement expressions will be emitted later, once we figure - out which is the result. */ - if (!STATEMENT_LIST_STMT_EXPR (cur_stmt_list) - && (warn_unused_value || warn_unused_result)) - emit_side_effect_warnings (EXPR_LOC_OR_LOC (expr, loc), expr); - - exprv = expr; - while (TREE_CODE (exprv) == COMPOUND_EXPR) - exprv = TREE_OPERAND (exprv, 1); - while (CONVERT_EXPR_P (exprv)) - exprv = TREE_OPERAND (exprv, 0); - if (DECL_P (exprv) - || handled_component_p (exprv) - || TREE_CODE (exprv) == ADDR_EXPR) - mark_exp_read (exprv); - - /* If the expression is not of a type to which we cannot assign a line - number, wrap the thing in a no-op NOP_EXPR. */ - if (DECL_P (expr) || CONSTANT_CLASS_P (expr)) - { - expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr); - SET_EXPR_LOCATION (expr, loc); - } - - return expr; -} - -/* Emit an expression as a statement. LOC is the location of the - expression. */ - -tree -c_finish_expr_stmt (location_t loc, tree expr) -{ - if (expr) - return add_stmt (c_process_expr_stmt (loc, expr)); - else - return NULL; -} - -/* Do the opposite and emit a statement as an expression. To begin, - create a new binding level and return it. */ - -tree -c_begin_stmt_expr (void) -{ - tree ret; - - /* We must force a BLOCK for this level so that, if it is not expanded - later, there is a way to turn off the entire subtree of blocks that - are contained in it. */ - keep_next_level (); - ret = c_begin_compound_stmt (true); - - c_bindings_start_stmt_expr (c_switch_stack == NULL - ? NULL - : c_switch_stack->bindings); - - /* Mark the current statement list as belonging to a statement list. */ - STATEMENT_LIST_STMT_EXPR (ret) = 1; - - return ret; -} - -/* LOC is the location of the compound statement to which this body - belongs. */ - -tree -c_finish_stmt_expr (location_t loc, tree body) -{ - tree last, type, tmp, val; - tree *last_p; - - body = c_end_compound_stmt (loc, body, true); - - c_bindings_end_stmt_expr (c_switch_stack == NULL - ? NULL - : c_switch_stack->bindings); - - /* Locate the last statement in BODY. See c_end_compound_stmt - about always returning a BIND_EXPR. */ - last_p = &BIND_EXPR_BODY (body); - last = BIND_EXPR_BODY (body); - - continue_searching: - if (TREE_CODE (last) == STATEMENT_LIST) - { - tree_stmt_iterator l = tsi_last (last); - - while (!tsi_end_p (l) && TREE_CODE (tsi_stmt (l)) == DEBUG_BEGIN_STMT) - tsi_prev (&l); - - /* This can happen with degenerate cases like ({ }). No value. */ - if (tsi_end_p (l)) - return body; - - /* If we're supposed to generate side effects warnings, process - all of the statements except the last. */ - if (warn_unused_value || warn_unused_result) - { - for (tree_stmt_iterator i = tsi_start (last); - tsi_stmt (i) != tsi_stmt (l); tsi_next (&i)) - { - location_t tloc; - tree t = tsi_stmt (i); - - tloc = EXPR_HAS_LOCATION (t) ? EXPR_LOCATION (t) : loc; - emit_side_effect_warnings (tloc, t); - } - } - last_p = tsi_stmt_ptr (l); - last = *last_p; - } - - /* If the end of the list is exception related, then the list was split - by a call to push_cleanup. Continue searching. */ - if (TREE_CODE (last) == TRY_FINALLY_EXPR - || TREE_CODE (last) == TRY_CATCH_EXPR) - { - last_p = &TREE_OPERAND (last, 0); - last = *last_p; - goto continue_searching; - } - - if (last == error_mark_node) - return last; - - /* In the case that the BIND_EXPR is not necessary, return the - expression out from inside it. */ - if ((last == BIND_EXPR_BODY (body) - /* Skip nested debug stmts. */ - || last == expr_first (BIND_EXPR_BODY (body))) - && BIND_EXPR_VARS (body) == NULL) - { - /* Even if this looks constant, do not allow it in a constant - expression. */ - last = c_wrap_maybe_const (last, true); - /* Do not warn if the return value of a statement expression is - unused. */ - suppress_warning (last, OPT_Wunused); - return last; - } - - /* Extract the type of said expression. */ - type = TREE_TYPE (last); - - /* If we're not returning a value at all, then the BIND_EXPR that - we already have is a fine expression to return. */ - if (!type || VOID_TYPE_P (type)) - return body; - - /* Now that we've located the expression containing the value, it seems - silly to make voidify_wrapper_expr repeat the process. Create a - temporary of the appropriate type and stick it in a TARGET_EXPR. */ - tmp = create_tmp_var_raw (type); - - /* Unwrap a no-op NOP_EXPR as added by c_finish_expr_stmt. This avoids - tree_expr_nonnegative_p giving up immediately. */ - val = last; - if (TREE_CODE (val) == NOP_EXPR - && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0))) - val = TREE_OPERAND (val, 0); - - *last_p = build2 (MODIFY_EXPR, void_type_node, tmp, val); - SET_EXPR_LOCATION (*last_p, EXPR_LOCATION (last)); - - { - tree t = build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE); - SET_EXPR_LOCATION (t, loc); - return t; - } -} - -/* Begin and end compound statements. This is as simple as pushing - and popping new statement lists from the tree. */ - -tree -c_begin_compound_stmt (bool do_scope) -{ - tree stmt = push_stmt_list (); - if (do_scope) - push_scope (); - return stmt; -} - -/* End a compound statement. STMT is the statement. LOC is the - location of the compound statement-- this is usually the location - of the opening brace. */ - -tree -c_end_compound_stmt (location_t loc, tree stmt, bool do_scope) -{ - tree block = NULL; - - if (do_scope) - { - if (c_dialect_objc ()) - objc_clear_super_receiver (); - block = pop_scope (); - } - - stmt = pop_stmt_list (stmt); - stmt = c_build_bind_expr (loc, block, stmt); - - /* If this compound statement is nested immediately inside a statement - expression, then force a BIND_EXPR to be created. Otherwise we'll - do the wrong thing for ({ { 1; } }) or ({ 1; { } }). In particular, - STATEMENT_LISTs merge, and thus we can lose track of what statement - was really last. */ - if (building_stmt_list_p () - && STATEMENT_LIST_STMT_EXPR (cur_stmt_list) - && TREE_CODE (stmt) != BIND_EXPR) - { - stmt = build3 (BIND_EXPR, void_type_node, NULL, stmt, NULL); - TREE_SIDE_EFFECTS (stmt) = 1; - SET_EXPR_LOCATION (stmt, loc); - } - - return stmt; -} - -/* Queue a cleanup. CLEANUP is an expression/statement to be executed - when the current scope is exited. EH_ONLY is true when this is not - meant to apply to normal control flow transfer. */ - -void -push_cleanup (tree decl, tree cleanup, bool eh_only) -{ - enum tree_code code; - tree stmt, list; - bool stmt_expr; - - code = eh_only ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR; - stmt = build_stmt (DECL_SOURCE_LOCATION (decl), code, NULL, cleanup); - add_stmt (stmt); - stmt_expr = STATEMENT_LIST_STMT_EXPR (cur_stmt_list); - list = push_stmt_list (); - TREE_OPERAND (stmt, 0) = list; - STATEMENT_LIST_STMT_EXPR (list) = stmt_expr; -} - -/* Build a vector comparison of ARG0 and ARG1 using CODE opcode - into a value of TYPE type. Comparison is done via VEC_COND_EXPR. */ - -static tree -build_vec_cmp (tree_code code, tree type, - tree arg0, tree arg1) -{ - tree zero_vec = build_zero_cst (type); - tree minus_one_vec = build_minus_one_cst (type); - tree cmp_type = truth_type_for (type); - tree cmp = build2 (code, cmp_type, arg0, arg1); - return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec); -} - -/* Possibly warn about an address of OP never being NULL in a comparison - operation CODE involving null. */ - -static void -maybe_warn_for_null_address (location_t loc, tree op, tree_code code) -{ - /* Prevent warnings issued for macro expansion. */ - if (!warn_address - || warning_suppressed_p (op, OPT_Waddress) - || from_macro_expansion_at (loc)) - return; - - if (TREE_CODE (op) == NOP_EXPR) - { - /* Allow casts to intptr_t to suppress the warning. */ - tree type = TREE_TYPE (op); - if (TREE_CODE (type) == INTEGER_TYPE) - return; - op = TREE_OPERAND (op, 0); - } - - if (TREE_CODE (op) == POINTER_PLUS_EXPR) - { - /* Allow a cast to void* to suppress the warning. */ - tree type = TREE_TYPE (TREE_TYPE (op)); - if (VOID_TYPE_P (type)) - return; - - /* Adding any value to a null pointer, including zero, is undefined - in C. This includes the expression &p[0] where p is the null - pointer, although &p[0] will have been folded to p by this point - and so not diagnosed. */ - if (code == EQ_EXPR) - warning_at (loc, OPT_Waddress, - "the comparison will always evaluate as % " - "for the pointer operand in %qE must not be NULL", - op); - else - warning_at (loc, OPT_Waddress, - "the comparison will always evaluate as % " - "for the pointer operand in %qE must not be NULL", - op); - - return; - } - - if (TREE_CODE (op) != ADDR_EXPR) - return; - - op = TREE_OPERAND (op, 0); - - if (TREE_CODE (op) == IMAGPART_EXPR - || TREE_CODE (op) == REALPART_EXPR) - { - /* The address of either complex part may not be null. */ - if (code == EQ_EXPR) - warning_at (loc, OPT_Waddress, - "the comparison will always evaluate as % " - "for the address of %qE will never be NULL", - op); - else - warning_at (loc, OPT_Waddress, - "the comparison will always evaluate as % " - "for the address of %qE will never be NULL", - op); - return; - } - - /* Set to true in the loop below if OP dereferences is operand. - In such a case the ultimate target need not be a decl for - the null [in]equality test to be constant. */ - bool deref = false; - - /* Get the outermost array or object, or member. */ - while (handled_component_p (op)) - { - if (TREE_CODE (op) == COMPONENT_REF) - { - /* Get the member (its address is never null). */ - op = TREE_OPERAND (op, 1); - break; - } - - /* Get the outer array/object to refer to in the warning. */ - op = TREE_OPERAND (op, 0); - deref = true; - } - - if ((!deref && !decl_with_nonnull_addr_p (op)) - || from_macro_expansion_at (loc)) - return; - - if (code == EQ_EXPR) - warning_at (loc, OPT_Waddress, - "the comparison will always evaluate as % " - "for the address of %qE will never be NULL", - op); - else - warning_at (loc, OPT_Waddress, - "the comparison will always evaluate as % " - "for the address of %qE will never be NULL", - op); - - if (DECL_P (op)) - inform (DECL_SOURCE_LOCATION (op), "%qD declared here", op); -} - -/* Build a binary-operation expression without default conversions. - CODE is the kind of expression to build. - LOCATION is the operator's location. - This function differs from `build' in several ways: - the data type of the result is computed and recorded in it, - warnings are generated if arg data types are invalid, - special handling for addition and subtraction of pointers is known, - and some optimization is done (operations on narrow ints - are done in the narrower type when that gives the same result). - Constant folding is also done before the result is returned. - - Note that the operands will never have enumeral types, or function - or array types, because either they will have the default conversions - performed or they have both just been converted to some other type in which - the arithmetic is to be done. */ - -tree -build_binary_op (location_t location, enum tree_code code, - tree orig_op0, tree orig_op1, bool convert_p) -{ - tree type0, type1, orig_type0, orig_type1; - tree eptype; - enum tree_code code0, code1; - tree op0, op1; - tree ret = error_mark_node; - const char *invalid_op_diag; - bool op0_int_operands, op1_int_operands; - bool int_const, int_const_or_overflow, int_operands; - - /* Expression code to give to the expression when it is built. - Normally this is CODE, which is what the caller asked for, - but in some special cases we change it. */ - enum tree_code resultcode = code; - - /* Data type in which the computation is to be performed. - In the simplest cases this is the common type of the arguments. */ - tree result_type = NULL; - - /* When the computation is in excess precision, the type of the - final EXCESS_PRECISION_EXPR. */ - tree semantic_result_type = NULL; - - /* Nonzero means operands have already been type-converted - in whatever way is necessary. - Zero means they need to be converted to RESULT_TYPE. */ - int converted = 0; - - /* Nonzero means create the expression with this type, rather than - RESULT_TYPE. */ - tree build_type = NULL_TREE; - - /* Nonzero means after finally constructing the expression - convert it to this type. */ - tree final_type = NULL_TREE; - - /* Nonzero if this is an operation like MIN or MAX which can - safely be computed in short if both args are promoted shorts. - Also implies COMMON. - -1 indicates a bitwise operation; this makes a difference - in the exact conditions for when it is safe to do the operation - in a narrower mode. */ - int shorten = 0; - - /* Nonzero if this is a comparison operation; - if both args are promoted shorts, compare the original shorts. - Also implies COMMON. */ - int short_compare = 0; - - /* Nonzero if this is a right-shift operation, which can be computed on the - original short and then promoted if the operand is a promoted short. */ - int short_shift = 0; - - /* Nonzero means set RESULT_TYPE to the common type of the args. */ - int common = 0; - - /* True means types are compatible as far as ObjC is concerned. */ - bool objc_ok; - - /* True means this is an arithmetic operation that may need excess - precision. */ - bool may_need_excess_precision; - - /* True means this is a boolean operation that converts both its - operands to truth-values. */ - bool boolean_op = false; - - /* Remember whether we're doing / or %. */ - bool doing_div_or_mod = false; - - /* Remember whether we're doing << or >>. */ - bool doing_shift = false; - - /* Tree holding instrumentation expression. */ - tree instrument_expr = NULL; - - if (location == UNKNOWN_LOCATION) - location = input_location; - - op0 = orig_op0; - op1 = orig_op1; - - op0_int_operands = EXPR_INT_CONST_OPERANDS (orig_op0); - if (op0_int_operands) - op0 = remove_c_maybe_const_expr (op0); - op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1); - if (op1_int_operands) - op1 = remove_c_maybe_const_expr (op1); - int_operands = (op0_int_operands && op1_int_operands); - if (int_operands) - { - int_const_or_overflow = (TREE_CODE (orig_op0) == INTEGER_CST - && TREE_CODE (orig_op1) == INTEGER_CST); - int_const = (int_const_or_overflow - && !TREE_OVERFLOW (orig_op0) - && !TREE_OVERFLOW (orig_op1)); - } - else - int_const = int_const_or_overflow = false; - - /* Do not apply default conversion in mixed vector/scalar expression. */ - if (convert_p - && VECTOR_TYPE_P (TREE_TYPE (op0)) == VECTOR_TYPE_P (TREE_TYPE (op1))) - { - op0 = default_conversion (op0); - op1 = default_conversion (op1); - } - - orig_type0 = type0 = TREE_TYPE (op0); - - orig_type1 = type1 = TREE_TYPE (op1); - - /* The expression codes of the data types of the arguments tell us - whether the arguments are integers, floating, pointers, etc. */ - code0 = TREE_CODE (type0); - code1 = TREE_CODE (type1); - - /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ - STRIP_TYPE_NOPS (op0); - STRIP_TYPE_NOPS (op1); - - /* If an error was already reported for one of the arguments, - avoid reporting another error. */ - - if (code0 == ERROR_MARK || code1 == ERROR_MARK) - return error_mark_node; - - if (code0 == POINTER_TYPE - && reject_gcc_builtin (op0, EXPR_LOCATION (orig_op0))) - return error_mark_node; - - if (code1 == POINTER_TYPE - && reject_gcc_builtin (op1, EXPR_LOCATION (orig_op1))) - return error_mark_node; - - if ((invalid_op_diag - = targetm.invalid_binary_op (code, type0, type1))) - { - error_at (location, invalid_op_diag); - return error_mark_node; - } - - switch (code) - { - case PLUS_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case EXACT_DIV_EXPR: - may_need_excess_precision = true; - break; - - case EQ_EXPR: - case NE_EXPR: - case LE_EXPR: - case GE_EXPR: - case LT_EXPR: - case GT_EXPR: - /* Excess precision for implicit conversions of integers to - floating point in C11 and later. */ - may_need_excess_precision = (flag_isoc11 - && (ANY_INTEGRAL_TYPE_P (type0) - || ANY_INTEGRAL_TYPE_P (type1))); - break; - - default: - may_need_excess_precision = false; - break; - } - if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR) - { - op0 = TREE_OPERAND (op0, 0); - type0 = TREE_TYPE (op0); - } - else if (may_need_excess_precision - && (eptype = excess_precision_type (type0)) != NULL_TREE) - { - type0 = eptype; - op0 = convert (eptype, op0); - } - if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR) - { - op1 = TREE_OPERAND (op1, 0); - type1 = TREE_TYPE (op1); - } - else if (may_need_excess_precision - && (eptype = excess_precision_type (type1)) != NULL_TREE) - { - type1 = eptype; - op1 = convert (eptype, op1); - } - - objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE); - - /* In case when one of the operands of the binary operation is - a vector and another is a scalar -- convert scalar to vector. */ - if ((gnu_vector_type_p (type0) && code1 != VECTOR_TYPE) - || (gnu_vector_type_p (type1) && code0 != VECTOR_TYPE)) - { - enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1, - true); - - switch (convert_flag) - { - case stv_error: - return error_mark_node; - case stv_firstarg: - { - bool maybe_const = true; - tree sc; - sc = c_fully_fold (op0, false, &maybe_const); - sc = save_expr (sc); - sc = convert (TREE_TYPE (type1), sc); - op0 = build_vector_from_val (type1, sc); - if (!maybe_const) - op0 = c_wrap_maybe_const (op0, true); - orig_type0 = type0 = TREE_TYPE (op0); - code0 = TREE_CODE (type0); - converted = 1; - break; - } - case stv_secondarg: - { - bool maybe_const = true; - tree sc; - sc = c_fully_fold (op1, false, &maybe_const); - sc = save_expr (sc); - sc = convert (TREE_TYPE (type0), sc); - op1 = build_vector_from_val (type0, sc); - if (!maybe_const) - op1 = c_wrap_maybe_const (op1, true); - orig_type1 = type1 = TREE_TYPE (op1); - code1 = TREE_CODE (type1); - converted = 1; - break; - } - default: - break; - } - } - - switch (code) - { - case PLUS_EXPR: - /* Handle the pointer + int case. */ - if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) - { - ret = pointer_int_sum (location, PLUS_EXPR, op0, op1); - goto return_build_binary_op; - } - else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE) - { - ret = pointer_int_sum (location, PLUS_EXPR, op1, op0); - goto return_build_binary_op; - } - else - common = 1; - break; - - case MINUS_EXPR: - /* Subtraction of two similar pointers. - We must subtract them as integers, then divide by object size. */ - if (code0 == POINTER_TYPE && code1 == POINTER_TYPE - && comp_target_types (location, type0, type1)) - { - ret = pointer_diff (location, op0, op1, &instrument_expr); - goto return_build_binary_op; - } - /* Handle pointer minus int. Just like pointer plus int. */ - else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) - { - ret = pointer_int_sum (location, MINUS_EXPR, op0, op1); - goto return_build_binary_op; - } - else - common = 1; - break; - - case MULT_EXPR: - common = 1; - break; - - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case EXACT_DIV_EXPR: - doing_div_or_mod = true; - warn_for_div_by_zero (location, op1); - - if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE - || code0 == FIXED_POINT_TYPE - || code0 == COMPLEX_TYPE - || gnu_vector_type_p (type0)) - && (code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == FIXED_POINT_TYPE - || code1 == COMPLEX_TYPE - || gnu_vector_type_p (type1))) - { - enum tree_code tcode0 = code0, tcode1 = code1; - - if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE) - tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0))); - if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE) - tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1))); - - if (!((tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE) - || (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE))) - resultcode = RDIV_EXPR; - else - /* Although it would be tempting to shorten always here, that - loses on some targets, since the modulo instruction is - undefined if the quotient can't be represented in the - computation mode. We shorten only if unsigned or if - dividing by something we know != -1. */ - shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0)) - || (TREE_CODE (op1) == INTEGER_CST - && !integer_all_onesp (op1))); - common = 1; - } - break; - - case BIT_AND_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) - shorten = -1; - /* Allow vector types which are not floating point types. */ - else if (gnu_vector_type_p (type0) - && gnu_vector_type_p (type1) - && !VECTOR_FLOAT_TYPE_P (type0) - && !VECTOR_FLOAT_TYPE_P (type1)) - common = 1; - break; - - case TRUNC_MOD_EXPR: - case FLOOR_MOD_EXPR: - doing_div_or_mod = true; - warn_for_div_by_zero (location, op1); - - if (gnu_vector_type_p (type0) - && gnu_vector_type_p (type1) - && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE - && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) - common = 1; - else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) - { - /* Although it would be tempting to shorten always here, that loses - on some targets, since the modulo instruction is undefined if the - quotient can't be represented in the computation mode. We shorten - only if unsigned or if dividing by something we know != -1. */ - shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0)) - || (TREE_CODE (op1) == INTEGER_CST - && !integer_all_onesp (op1))); - common = 1; - } - break; - - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE - || code0 == REAL_TYPE || code0 == COMPLEX_TYPE - || code0 == FIXED_POINT_TYPE) - && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE - || code1 == REAL_TYPE || code1 == COMPLEX_TYPE - || code1 == FIXED_POINT_TYPE)) - { - /* Result of these operations is always an int, - but that does not mean the operands should be - converted to ints! */ - result_type = integer_type_node; - if (op0_int_operands) - { - op0 = c_objc_common_truthvalue_conversion (location, orig_op0); - op0 = remove_c_maybe_const_expr (op0); - } - else - op0 = c_objc_common_truthvalue_conversion (location, op0); - if (op1_int_operands) - { - op1 = c_objc_common_truthvalue_conversion (location, orig_op1); - op1 = remove_c_maybe_const_expr (op1); - } - else - op1 = c_objc_common_truthvalue_conversion (location, op1); - converted = 1; - boolean_op = true; - } - if (code == TRUTH_ANDIF_EXPR) - { - int_const_or_overflow = (int_operands - && TREE_CODE (orig_op0) == INTEGER_CST - && (op0 == truthvalue_false_node - || TREE_CODE (orig_op1) == INTEGER_CST)); - int_const = (int_const_or_overflow - && !TREE_OVERFLOW (orig_op0) - && (op0 == truthvalue_false_node - || !TREE_OVERFLOW (orig_op1))); - } - else if (code == TRUTH_ORIF_EXPR) - { - int_const_or_overflow = (int_operands - && TREE_CODE (orig_op0) == INTEGER_CST - && (op0 == truthvalue_true_node - || TREE_CODE (orig_op1) == INTEGER_CST)); - int_const = (int_const_or_overflow - && !TREE_OVERFLOW (orig_op0) - && (op0 == truthvalue_true_node - || !TREE_OVERFLOW (orig_op1))); - } - break; - - /* Shift operations: result has same type as first operand; - always convert second operand to int. - Also set SHORT_SHIFT if shifting rightward. */ - - case RSHIFT_EXPR: - if (gnu_vector_type_p (type0) - && gnu_vector_type_p (type1) - && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE - && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE - && known_eq (TYPE_VECTOR_SUBPARTS (type0), - TYPE_VECTOR_SUBPARTS (type1))) - { - result_type = type0; - converted = 1; - } - else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE - || (gnu_vector_type_p (type0) - && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)) - && code1 == INTEGER_TYPE) - { - doing_shift = true; - if (TREE_CODE (op1) == INTEGER_CST) - { - if (tree_int_cst_sgn (op1) < 0) - { - int_const = false; - if (c_inhibit_evaluation_warnings == 0) - warning_at (location, OPT_Wshift_count_negative, - "right shift count is negative"); - } - else if (code0 == VECTOR_TYPE) - { - if (compare_tree_int (op1, - TYPE_PRECISION (TREE_TYPE (type0))) - >= 0) - { - int_const = false; - if (c_inhibit_evaluation_warnings == 0) - warning_at (location, OPT_Wshift_count_overflow, - "right shift count >= width of vector element"); - } - } - else - { - if (!integer_zerop (op1)) - short_shift = 1; - - if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0) - { - int_const = false; - if (c_inhibit_evaluation_warnings == 0) - warning_at (location, OPT_Wshift_count_overflow, - "right shift count >= width of type"); - } - } - } - - /* Use the type of the value to be shifted. */ - result_type = type0; - /* Avoid converting op1 to result_type later. */ - converted = 1; - } - break; - - case LSHIFT_EXPR: - if (gnu_vector_type_p (type0) - && gnu_vector_type_p (type1) - && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE - && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE - && known_eq (TYPE_VECTOR_SUBPARTS (type0), - TYPE_VECTOR_SUBPARTS (type1))) - { - result_type = type0; - converted = 1; - } - else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE - || (gnu_vector_type_p (type0) - && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)) - && code1 == INTEGER_TYPE) - { - doing_shift = true; - if (TREE_CODE (op0) == INTEGER_CST - && tree_int_cst_sgn (op0) < 0) - { - /* Don't reject a left shift of a negative value in a context - where a constant expression is needed in C90. */ - if (flag_isoc99) - int_const = false; - if (c_inhibit_evaluation_warnings == 0) - warning_at (location, OPT_Wshift_negative_value, - "left shift of negative value"); - } - if (TREE_CODE (op1) == INTEGER_CST) - { - if (tree_int_cst_sgn (op1) < 0) - { - int_const = false; - if (c_inhibit_evaluation_warnings == 0) - warning_at (location, OPT_Wshift_count_negative, - "left shift count is negative"); - } - else if (code0 == VECTOR_TYPE) - { - if (compare_tree_int (op1, - TYPE_PRECISION (TREE_TYPE (type0))) - >= 0) - { - int_const = false; - if (c_inhibit_evaluation_warnings == 0) - warning_at (location, OPT_Wshift_count_overflow, - "left shift count >= width of vector element"); - } - } - else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0) - { - int_const = false; - if (c_inhibit_evaluation_warnings == 0) - warning_at (location, OPT_Wshift_count_overflow, - "left shift count >= width of type"); - } - else if (TREE_CODE (op0) == INTEGER_CST - && maybe_warn_shift_overflow (location, op0, op1) - && flag_isoc99) - int_const = false; - } - - /* Use the type of the value to be shifted. */ - result_type = type0; - /* Avoid converting op1 to result_type later. */ - converted = 1; - } - break; - - case EQ_EXPR: - case NE_EXPR: - if (gnu_vector_type_p (type0) && gnu_vector_type_p (type1)) - { - tree intt; - if (!vector_types_compatible_elements_p (type0, type1)) - { - error_at (location, "comparing vectors with different " - "element types"); - return error_mark_node; - } - - if (maybe_ne (TYPE_VECTOR_SUBPARTS (type0), - TYPE_VECTOR_SUBPARTS (type1))) - { - error_at (location, "comparing vectors with different " - "number of elements"); - return error_mark_node; - } - - /* It's not precisely specified how the usual arithmetic - conversions apply to the vector types. Here, we use - the unsigned type if one of the operands is signed and - the other one is unsigned. */ - if (TYPE_UNSIGNED (type0) != TYPE_UNSIGNED (type1)) - { - if (!TYPE_UNSIGNED (type0)) - op0 = build1 (VIEW_CONVERT_EXPR, type1, op0); - else - op1 = build1 (VIEW_CONVERT_EXPR, type0, op1); - warning_at (location, OPT_Wsign_compare, "comparison between " - "types %qT and %qT", type0, type1); - } - - /* Always construct signed integer vector type. */ - intt = c_common_type_for_size (GET_MODE_BITSIZE - (SCALAR_TYPE_MODE - (TREE_TYPE (type0))), 0); - if (!intt) - { - error_at (location, "could not find an integer type " - "of the same size as %qT", - TREE_TYPE (type0)); - return error_mark_node; - } - result_type = build_opaque_vector_type (intt, - TYPE_VECTOR_SUBPARTS (type0)); - converted = 1; - ret = build_vec_cmp (resultcode, result_type, op0, op1); - goto return_build_binary_op; - } - if (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1)) - warning_at (location, - OPT_Wfloat_equal, - "comparing floating-point with %<==%> or % is unsafe"); - /* Result of comparison is always int, - but don't convert the args to int! */ - build_type = integer_type_node; - if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE - || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE) - && (code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE)) - short_compare = 1; - else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) - { - maybe_warn_for_null_address (location, op0, code); - result_type = type0; - } - else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0)) - { - maybe_warn_for_null_address (location, op1, code); - result_type = type1; - } - else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) - { - tree tt0 = TREE_TYPE (type0); - tree tt1 = TREE_TYPE (type1); - addr_space_t as0 = TYPE_ADDR_SPACE (tt0); - addr_space_t as1 = TYPE_ADDR_SPACE (tt1); - addr_space_t as_common = ADDR_SPACE_GENERIC; - - /* Anything compares with void *. void * compares with anything. - Otherwise, the targets must be compatible - and both must be object or both incomplete. */ - if (comp_target_types (location, type0, type1)) - result_type = common_pointer_type (type0, type1); - else if (!addr_space_superset (as0, as1, &as_common)) - { - error_at (location, "comparison of pointers to " - "disjoint address spaces"); - return error_mark_node; - } - else if (VOID_TYPE_P (tt0) && !TYPE_ATOMIC (tt0)) - { - if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE) - pedwarn (location, OPT_Wpedantic, "ISO C forbids " - "comparison of % with function pointer"); - } - else if (VOID_TYPE_P (tt1) && !TYPE_ATOMIC (tt1)) - { - if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE) - pedwarn (location, OPT_Wpedantic, "ISO C forbids " - "comparison of % with function pointer"); - } - else - /* Avoid warning about the volatile ObjC EH puts on decls. */ - if (!objc_ok) - pedwarn (location, 0, - "comparison of distinct pointer types lacks a cast"); - - if (result_type == NULL_TREE) - { - int qual = ENCODE_QUAL_ADDR_SPACE (as_common); - result_type = build_pointer_type - (build_qualified_type (void_type_node, qual)); - } - } - else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) - { - result_type = type0; - pedwarn (location, 0, "comparison between pointer and integer"); - } - else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) - { - result_type = type1; - pedwarn (location, 0, "comparison between pointer and integer"); - } - if ((TREE_CODE (TREE_TYPE (orig_op0)) == BOOLEAN_TYPE - || truth_value_p (TREE_CODE (orig_op0))) - ^ (TREE_CODE (TREE_TYPE (orig_op1)) == BOOLEAN_TYPE - || truth_value_p (TREE_CODE (orig_op1)))) - maybe_warn_bool_compare (location, code, orig_op0, orig_op1); - break; - - case LE_EXPR: - case GE_EXPR: - case LT_EXPR: - case GT_EXPR: - if (gnu_vector_type_p (type0) && gnu_vector_type_p (type1)) - { - tree intt; - if (!vector_types_compatible_elements_p (type0, type1)) - { - error_at (location, "comparing vectors with different " - "element types"); - return error_mark_node; - } - - if (maybe_ne (TYPE_VECTOR_SUBPARTS (type0), - TYPE_VECTOR_SUBPARTS (type1))) - { - error_at (location, "comparing vectors with different " - "number of elements"); - return error_mark_node; - } - - /* It's not precisely specified how the usual arithmetic - conversions apply to the vector types. Here, we use - the unsigned type if one of the operands is signed and - the other one is unsigned. */ - if (TYPE_UNSIGNED (type0) != TYPE_UNSIGNED (type1)) - { - if (!TYPE_UNSIGNED (type0)) - op0 = build1 (VIEW_CONVERT_EXPR, type1, op0); - else - op1 = build1 (VIEW_CONVERT_EXPR, type0, op1); - warning_at (location, OPT_Wsign_compare, "comparison between " - "types %qT and %qT", type0, type1); - } - - /* Always construct signed integer vector type. */ - intt = c_common_type_for_size (GET_MODE_BITSIZE - (SCALAR_TYPE_MODE - (TREE_TYPE (type0))), 0); - if (!intt) - { - error_at (location, "could not find an integer type " - "of the same size as %qT", - TREE_TYPE (type0)); - return error_mark_node; - } - result_type = build_opaque_vector_type (intt, - TYPE_VECTOR_SUBPARTS (type0)); - converted = 1; - ret = build_vec_cmp (resultcode, result_type, op0, op1); - goto return_build_binary_op; - } - build_type = integer_type_node; - if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE - || code0 == FIXED_POINT_TYPE) - && (code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == FIXED_POINT_TYPE)) - short_compare = 1; - else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) - { - addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0)); - addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); - addr_space_t as_common; - - if (comp_target_types (location, type0, type1)) - { - result_type = common_pointer_type (type0, type1); - if (!COMPLETE_TYPE_P (TREE_TYPE (type0)) - != !COMPLETE_TYPE_P (TREE_TYPE (type1))) - pedwarn_c99 (location, OPT_Wpedantic, - "comparison of complete and incomplete pointers"); - else if (TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE) - pedwarn (location, OPT_Wpedantic, "ISO C forbids " - "ordered comparisons of pointers to functions"); - else if (null_pointer_constant_p (orig_op0) - || null_pointer_constant_p (orig_op1)) - warning_at (location, OPT_Wextra, - "ordered comparison of pointer with null pointer"); - - } - else if (!addr_space_superset (as0, as1, &as_common)) - { - error_at (location, "comparison of pointers to " - "disjoint address spaces"); - return error_mark_node; - } - else - { - int qual = ENCODE_QUAL_ADDR_SPACE (as_common); - result_type = build_pointer_type - (build_qualified_type (void_type_node, qual)); - pedwarn (location, 0, - "comparison of distinct pointer types lacks a cast"); - } - } - else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) - { - result_type = type0; - if (pedantic) - pedwarn (location, OPT_Wpedantic, - "ordered comparison of pointer with integer zero"); - else if (extra_warnings) - warning_at (location, OPT_Wextra, - "ordered comparison of pointer with integer zero"); - } - else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0)) - { - result_type = type1; - if (pedantic) - pedwarn (location, OPT_Wpedantic, - "ordered comparison of pointer with integer zero"); - else if (extra_warnings) - warning_at (location, OPT_Wextra, - "ordered comparison of pointer with integer zero"); - } - else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) - { - result_type = type0; - pedwarn (location, 0, "comparison between pointer and integer"); - } - else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) - { - result_type = type1; - pedwarn (location, 0, "comparison between pointer and integer"); - } - - if ((code0 == POINTER_TYPE || code1 == POINTER_TYPE) - && current_function_decl != NULL_TREE - && sanitize_flags_p (SANITIZE_POINTER_COMPARE)) - { - op0 = save_expr (op0); - op1 = save_expr (op1); - - tree tt = builtin_decl_explicit (BUILT_IN_ASAN_POINTER_COMPARE); - instrument_expr = build_call_expr_loc (location, tt, 2, op0, op1); - } - - if ((TREE_CODE (TREE_TYPE (orig_op0)) == BOOLEAN_TYPE - || truth_value_p (TREE_CODE (orig_op0))) - ^ (TREE_CODE (TREE_TYPE (orig_op1)) == BOOLEAN_TYPE - || truth_value_p (TREE_CODE (orig_op1)))) - maybe_warn_bool_compare (location, code, orig_op0, orig_op1); - break; - - case MIN_EXPR: - case MAX_EXPR: - /* Used for OpenMP atomics. */ - gcc_assert (flag_openmp); - common = 1; - break; - - default: - gcc_unreachable (); - } - - if (code0 == ERROR_MARK || code1 == ERROR_MARK) - return error_mark_node; - - if (gnu_vector_type_p (type0) - && gnu_vector_type_p (type1) - && (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1)) - || !vector_types_compatible_elements_p (type0, type1))) - { - gcc_rich_location richloc (location); - maybe_range_label_for_tree_type_mismatch - label_for_op0 (orig_op0, orig_op1), - label_for_op1 (orig_op1, orig_op0); - richloc.maybe_add_expr (orig_op0, &label_for_op0); - richloc.maybe_add_expr (orig_op1, &label_for_op1); - binary_op_error (&richloc, code, type0, type1); - return error_mark_node; - } - - if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE - || code0 == FIXED_POINT_TYPE - || gnu_vector_type_p (type0)) - && - (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE - || code1 == FIXED_POINT_TYPE - || gnu_vector_type_p (type1))) - { - bool first_complex = (code0 == COMPLEX_TYPE); - bool second_complex = (code1 == COMPLEX_TYPE); - int none_complex = (!first_complex && !second_complex); - - if (shorten || common || short_compare) - { - result_type = c_common_type (type0, type1); - do_warn_double_promotion (result_type, type0, type1, - "implicit conversion from %qT to %qT " - "to match other operand of binary " - "expression", - location); - if (result_type == error_mark_node) - return error_mark_node; - } - - if (first_complex != second_complex - && (code == PLUS_EXPR - || code == MINUS_EXPR - || code == MULT_EXPR - || (code == TRUNC_DIV_EXPR && first_complex)) - && TREE_CODE (TREE_TYPE (result_type)) == REAL_TYPE - && flag_signed_zeros) - { - /* An operation on mixed real/complex operands must be - handled specially, but the language-independent code can - more easily optimize the plain complex arithmetic if - -fno-signed-zeros. */ - tree real_type = TREE_TYPE (result_type); - tree real, imag; - if (type0 != orig_type0 || type1 != orig_type1) - { - gcc_assert (may_need_excess_precision && common); - semantic_result_type = c_common_type (orig_type0, orig_type1); - } - if (first_complex) - { - if (TREE_TYPE (op0) != result_type) - op0 = convert_and_check (location, result_type, op0); - if (TREE_TYPE (op1) != real_type) - op1 = convert_and_check (location, real_type, op1); - } - else - { - if (TREE_TYPE (op0) != real_type) - op0 = convert_and_check (location, real_type, op0); - if (TREE_TYPE (op1) != result_type) - op1 = convert_and_check (location, result_type, op1); - } - if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK) - return error_mark_node; - if (first_complex) - { - op0 = save_expr (op0); - real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR, - op0, true); - imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR, - op0, true); - switch (code) - { - case MULT_EXPR: - case TRUNC_DIV_EXPR: - op1 = save_expr (op1); - imag = build2 (resultcode, real_type, imag, op1); - /* Fall through. */ - case PLUS_EXPR: - case MINUS_EXPR: - real = build2 (resultcode, real_type, real, op1); - break; - default: - gcc_unreachable(); - } - } - else - { - op1 = save_expr (op1); - real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR, - op1, true); - imag = build_unary_op (EXPR_LOCATION (orig_op1), IMAGPART_EXPR, - op1, true); - switch (code) - { - case MULT_EXPR: - op0 = save_expr (op0); - imag = build2 (resultcode, real_type, op0, imag); - /* Fall through. */ - case PLUS_EXPR: - real = build2 (resultcode, real_type, op0, real); - break; - case MINUS_EXPR: - real = build2 (resultcode, real_type, op0, real); - imag = build1 (NEGATE_EXPR, real_type, imag); - break; - default: - gcc_unreachable(); - } - } - ret = build2 (COMPLEX_EXPR, result_type, real, imag); - goto return_build_binary_op; - } - - /* For certain operations (which identify themselves by shorten != 0) - if both args were extended from the same smaller type, - do the arithmetic in that type and then extend. - - shorten !=0 and !=1 indicates a bitwise operation. - For them, this optimization is safe only if - both args are zero-extended or both are sign-extended. - Otherwise, we might change the result. - Eg, (short)-1 | (unsigned short)-1 is (int)-1 - but calculated in (unsigned short) it would be (unsigned short)-1. */ - - if (shorten && none_complex) - { - final_type = result_type; - result_type = shorten_binary_op (result_type, op0, op1, - shorten == -1); - } - - /* Shifts can be shortened if shifting right. */ - - if (short_shift) - { - int unsigned_arg; - tree arg0 = get_narrower (op0, &unsigned_arg); - - final_type = result_type; - - if (arg0 == op0 && final_type == TREE_TYPE (op0)) - unsigned_arg = TYPE_UNSIGNED (TREE_TYPE (op0)); - - if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type) - && tree_int_cst_sgn (op1) > 0 - /* We can shorten only if the shift count is less than the - number of bits in the smaller type size. */ - && compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0 - /* We cannot drop an unsigned shift after sign-extension. */ - && (!TYPE_UNSIGNED (final_type) || unsigned_arg)) - { - /* Do an unsigned shift if the operand was zero-extended. */ - result_type - = c_common_signed_or_unsigned_type (unsigned_arg, - TREE_TYPE (arg0)); - /* Convert value-to-be-shifted to that type. */ - if (TREE_TYPE (op0) != result_type) - op0 = convert (result_type, op0); - converted = 1; - } - } - - /* Comparison operations are shortened too but differently. - They identify themselves by setting short_compare = 1. */ - - if (short_compare) - { - /* Don't write &op0, etc., because that would prevent op0 - from being kept in a register. - Instead, make copies of the our local variables and - pass the copies by reference, then copy them back afterward. */ - tree xop0 = op0, xop1 = op1, xresult_type = result_type; - enum tree_code xresultcode = resultcode; - tree val - = shorten_compare (location, &xop0, &xop1, &xresult_type, - &xresultcode); - - if (val != NULL_TREE) - { - ret = val; - goto return_build_binary_op; - } - - op0 = xop0, op1 = xop1; - converted = 1; - resultcode = xresultcode; - - if (c_inhibit_evaluation_warnings == 0 && !c_in_omp_for) - { - bool op0_maybe_const = true; - bool op1_maybe_const = true; - tree orig_op0_folded, orig_op1_folded; - - if (in_late_binary_op) - { - orig_op0_folded = orig_op0; - orig_op1_folded = orig_op1; - } - else - { - /* Fold for the sake of possible warnings, as in - build_conditional_expr. This requires the - "original" values to be folded, not just op0 and - op1. */ - c_inhibit_evaluation_warnings++; - op0 = c_fully_fold (op0, require_constant_value, - &op0_maybe_const); - op1 = c_fully_fold (op1, require_constant_value, - &op1_maybe_const); - c_inhibit_evaluation_warnings--; - orig_op0_folded = c_fully_fold (orig_op0, - require_constant_value, - NULL); - orig_op1_folded = c_fully_fold (orig_op1, - require_constant_value, - NULL); - } - - if (warn_sign_compare) - warn_for_sign_compare (location, orig_op0_folded, - orig_op1_folded, op0, op1, - result_type, resultcode); - if (!in_late_binary_op && !int_operands) - { - if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST) - op0 = c_wrap_maybe_const (op0, !op0_maybe_const); - if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST) - op1 = c_wrap_maybe_const (op1, !op1_maybe_const); - } - } - } - } - - /* At this point, RESULT_TYPE must be nonzero to avoid an error message. - If CONVERTED is zero, both args will be converted to type RESULT_TYPE. - Then the expression will be built. - It will be given type FINAL_TYPE if that is nonzero; - otherwise, it will be given type RESULT_TYPE. */ - - if (!result_type) - { - /* Favor showing any expression locations that are available. */ - op_location_t oploc (location, UNKNOWN_LOCATION); - binary_op_rich_location richloc (oploc, orig_op0, orig_op1, true); - binary_op_error (&richloc, code, TREE_TYPE (op0), TREE_TYPE (op1)); - return error_mark_node; - } - - if (build_type == NULL_TREE) - { - build_type = result_type; - if ((type0 != orig_type0 || type1 != orig_type1) - && !boolean_op) - { - gcc_assert (may_need_excess_precision && common); - semantic_result_type = c_common_type (orig_type0, orig_type1); - } - } - - if (!converted) - { - op0 = ep_convert_and_check (location, result_type, op0, - semantic_result_type); - op1 = ep_convert_and_check (location, result_type, op1, - semantic_result_type); - - /* This can happen if one operand has a vector type, and the other - has a different type. */ - if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK) - return error_mark_node; - } - - if (sanitize_flags_p ((SANITIZE_SHIFT - | SANITIZE_DIVIDE - | SANITIZE_FLOAT_DIVIDE - | SANITIZE_SI_OVERFLOW)) - && current_function_decl != NULL_TREE - && (doing_div_or_mod || doing_shift) - && !require_constant_value) - { - /* OP0 and/or OP1 might have side-effects. */ - op0 = save_expr (op0); - op1 = save_expr (op1); - op0 = c_fully_fold (op0, false, NULL); - op1 = c_fully_fold (op1, false, NULL); - if (doing_div_or_mod && (sanitize_flags_p ((SANITIZE_DIVIDE - | SANITIZE_FLOAT_DIVIDE - | SANITIZE_SI_OVERFLOW)))) - instrument_expr = ubsan_instrument_division (location, op0, op1); - else if (doing_shift && sanitize_flags_p (SANITIZE_SHIFT)) - instrument_expr = ubsan_instrument_shift (location, code, op0, op1); - } - - /* Treat expressions in initializers specially as they can't trap. */ - if (int_const_or_overflow) - ret = (require_constant_value - ? fold_build2_initializer_loc (location, resultcode, build_type, - op0, op1) - : fold_build2_loc (location, resultcode, build_type, op0, op1)); - else - ret = build2 (resultcode, build_type, op0, op1); - if (final_type != NULL_TREE) - ret = convert (final_type, ret); - - return_build_binary_op: - gcc_assert (ret != error_mark_node); - if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret) && !int_const) - ret = (int_operands - ? note_integer_operands (ret) - : build1 (NOP_EXPR, TREE_TYPE (ret), ret)); - else if (TREE_CODE (ret) != INTEGER_CST && int_operands - && !in_late_binary_op) - ret = note_integer_operands (ret); - protected_set_expr_location (ret, location); - - if (instrument_expr != NULL) - ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret), - instrument_expr, ret); - - if (semantic_result_type) - ret = build1_loc (location, EXCESS_PRECISION_EXPR, - semantic_result_type, ret); - - return ret; -} - - -/* Convert EXPR to be a truth-value, validating its type for this - purpose. LOCATION is the source location for the expression. */ - -tree -c_objc_common_truthvalue_conversion (location_t location, tree expr) -{ - bool int_const, int_operands; - - switch (TREE_CODE (TREE_TYPE (expr))) - { - case ARRAY_TYPE: - error_at (location, "used array that cannot be converted to pointer where scalar is required"); - return error_mark_node; - - case RECORD_TYPE: - error_at (location, "used struct type value where scalar is required"); - return error_mark_node; - - case UNION_TYPE: - error_at (location, "used union type value where scalar is required"); - return error_mark_node; - - case VOID_TYPE: - error_at (location, "void value not ignored as it ought to be"); - return error_mark_node; - - case POINTER_TYPE: - if (reject_gcc_builtin (expr)) - return error_mark_node; - break; - - case FUNCTION_TYPE: - gcc_unreachable (); - - case VECTOR_TYPE: - error_at (location, "used vector type where scalar is required"); - return error_mark_node; - - default: - break; - } - - int_const = (TREE_CODE (expr) == INTEGER_CST && !TREE_OVERFLOW (expr)); - int_operands = EXPR_INT_CONST_OPERANDS (expr); - if (int_operands && TREE_CODE (expr) != INTEGER_CST) - { - expr = remove_c_maybe_const_expr (expr); - expr = build2 (NE_EXPR, integer_type_node, expr, - convert (TREE_TYPE (expr), integer_zero_node)); - expr = note_integer_operands (expr); - } - else - /* ??? Should we also give an error for vectors rather than leaving - those to give errors later? */ - expr = c_common_truthvalue_conversion (location, expr); - - if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const) - { - if (TREE_OVERFLOW (expr)) - return expr; - else - return note_integer_operands (expr); - } - if (TREE_CODE (expr) == INTEGER_CST && !int_const) - return build1 (NOP_EXPR, TREE_TYPE (expr), expr); - return expr; -} - - -/* Convert EXPR to a contained DECL, updating *TC, *TI and *SE as - required. */ - -tree -c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED, bool *se) -{ - if (TREE_CODE (expr) == COMPOUND_LITERAL_EXPR) - { - tree decl = COMPOUND_LITERAL_EXPR_DECL (expr); - /* Executing a compound literal inside a function reinitializes - it. */ - if (!TREE_STATIC (decl)) - *se = true; - return decl; - } - else - return expr; -} - -/* Generate OMP construct CODE, with BODY and CLAUSES as its compound - statement. LOC is the location of the construct. */ - -tree -c_finish_omp_construct (location_t loc, enum tree_code code, tree body, - tree clauses) -{ - body = c_end_compound_stmt (loc, body, true); - - tree stmt = make_node (code); - TREE_TYPE (stmt) = void_type_node; - OMP_BODY (stmt) = body; - OMP_CLAUSES (stmt) = clauses; - SET_EXPR_LOCATION (stmt, loc); - - return add_stmt (stmt); -} - -/* Generate OACC_DATA, with CLAUSES and BLOCK as its compound - statement. LOC is the location of the OACC_DATA. */ - -tree -c_finish_oacc_data (location_t loc, tree clauses, tree block) -{ - tree stmt; - - block = c_end_compound_stmt (loc, block, true); - - stmt = make_node (OACC_DATA); - TREE_TYPE (stmt) = void_type_node; - OACC_DATA_CLAUSES (stmt) = clauses; - OACC_DATA_BODY (stmt) = block; - SET_EXPR_LOCATION (stmt, loc); - - return add_stmt (stmt); -} - -/* Generate OACC_HOST_DATA, with CLAUSES and BLOCK as its compound - statement. LOC is the location of the OACC_HOST_DATA. */ - -tree -c_finish_oacc_host_data (location_t loc, tree clauses, tree block) -{ - tree stmt; - - block = c_end_compound_stmt (loc, block, true); - - stmt = make_node (OACC_HOST_DATA); - TREE_TYPE (stmt) = void_type_node; - OACC_HOST_DATA_CLAUSES (stmt) = clauses; - OACC_HOST_DATA_BODY (stmt) = block; - SET_EXPR_LOCATION (stmt, loc); - - return add_stmt (stmt); -} - -/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */ - -tree -c_begin_omp_parallel (void) -{ - tree block; - - keep_next_level (); - block = c_begin_compound_stmt (true); - - return block; -} - -/* Generate OMP_PARALLEL, with CLAUSES and BLOCK as its compound - statement. LOC is the location of the OMP_PARALLEL. */ - -tree -c_finish_omp_parallel (location_t loc, tree clauses, tree block) -{ - tree stmt; - - block = c_end_compound_stmt (loc, block, true); - - stmt = make_node (OMP_PARALLEL); - TREE_TYPE (stmt) = void_type_node; - OMP_PARALLEL_CLAUSES (stmt) = clauses; - OMP_PARALLEL_BODY (stmt) = block; - SET_EXPR_LOCATION (stmt, loc); - - return add_stmt (stmt); -} - -/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */ - -tree -c_begin_omp_task (void) -{ - tree block; - - keep_next_level (); - block = c_begin_compound_stmt (true); - - return block; -} - -/* Generate OMP_TASK, with CLAUSES and BLOCK as its compound - statement. LOC is the location of the #pragma. */ - -tree -c_finish_omp_task (location_t loc, tree clauses, tree block) -{ - tree stmt; - - block = c_end_compound_stmt (loc, block, true); - - stmt = make_node (OMP_TASK); - TREE_TYPE (stmt) = void_type_node; - OMP_TASK_CLAUSES (stmt) = clauses; - OMP_TASK_BODY (stmt) = block; - SET_EXPR_LOCATION (stmt, loc); - - return add_stmt (stmt); -} - -/* Generate GOMP_cancel call for #pragma omp cancel. */ - -void -c_finish_omp_cancel (location_t loc, tree clauses) -{ - tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL); - int mask = 0; - if (omp_find_clause (clauses, OMP_CLAUSE_PARALLEL)) - mask = 1; - else if (omp_find_clause (clauses, OMP_CLAUSE_FOR)) - mask = 2; - else if (omp_find_clause (clauses, OMP_CLAUSE_SECTIONS)) - mask = 4; - else if (omp_find_clause (clauses, OMP_CLAUSE_TASKGROUP)) - mask = 8; - else - { - error_at (loc, "%<#pragma omp cancel%> must specify one of " - "%, %, % or % " - "clauses"); - return; - } - tree ifc = omp_find_clause (clauses, OMP_CLAUSE_IF); - if (ifc != NULL_TREE) - { - if (OMP_CLAUSE_IF_MODIFIER (ifc) != ERROR_MARK - && OMP_CLAUSE_IF_MODIFIER (ifc) != VOID_CST) - error_at (OMP_CLAUSE_LOCATION (ifc), - "expected % % clause modifier"); - else - { - tree ifc2 = omp_find_clause (OMP_CLAUSE_CHAIN (ifc), OMP_CLAUSE_IF); - if (ifc2 != NULL_TREE) - { - gcc_assert (OMP_CLAUSE_IF_MODIFIER (ifc) == VOID_CST - && OMP_CLAUSE_IF_MODIFIER (ifc2) != ERROR_MARK - && OMP_CLAUSE_IF_MODIFIER (ifc2) != VOID_CST); - error_at (OMP_CLAUSE_LOCATION (ifc2), - "expected % % clause modifier"); - } - } - - tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc)); - ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR, - boolean_type_node, OMP_CLAUSE_IF_EXPR (ifc), - build_zero_cst (type)); - } - else - ifc = boolean_true_node; - tree stmt = build_call_expr_loc (loc, fn, 2, - build_int_cst (integer_type_node, mask), - ifc); - add_stmt (stmt); -} - -/* Generate GOMP_cancellation_point call for - #pragma omp cancellation point. */ - -void -c_finish_omp_cancellation_point (location_t loc, tree clauses) -{ - tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT); - int mask = 0; - if (omp_find_clause (clauses, OMP_CLAUSE_PARALLEL)) - mask = 1; - else if (omp_find_clause (clauses, OMP_CLAUSE_FOR)) - mask = 2; - else if (omp_find_clause (clauses, OMP_CLAUSE_SECTIONS)) - mask = 4; - else if (omp_find_clause (clauses, OMP_CLAUSE_TASKGROUP)) - mask = 8; - else - { - error_at (loc, "%<#pragma omp cancellation point%> must specify one of " - "%, %, % or % " - "clauses"); - return; - } - tree stmt = build_call_expr_loc (loc, fn, 1, - build_int_cst (integer_type_node, mask)); - add_stmt (stmt); -} - -/* Helper function for handle_omp_array_sections. Called recursively - to handle multiple array-section-subscripts. C is the clause, - T current expression (initially OMP_CLAUSE_DECL), which is either - a TREE_LIST for array-section-subscript (TREE_PURPOSE is low-bound - expression if specified, TREE_VALUE length expression if specified, - TREE_CHAIN is what it has been specified after, or some decl. - TYPES vector is populated with array section types, MAYBE_ZERO_LEN - set to true if any of the array-section-subscript could have length - of zero (explicit or implicit), FIRST_NON_ONE is the index of the - first array-section-subscript which is known not to have length - of one. Given say: - map(a[:b][2:1][:c][:2][:d][e:f][2:5]) - FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] - all are or may have length of 1, array-section-subscript [:2] is the - first one known not to have length 1. For array-section-subscript - <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't - 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we - can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above - case though, as some lengths could be zero. */ - -static tree -handle_omp_array_sections_1 (tree c, tree t, vec &types, - bool &maybe_zero_len, unsigned int &first_non_one, - enum c_omp_region_type ort) -{ - tree ret, low_bound, length, type; - if (TREE_CODE (t) != TREE_LIST) - { - if (error_operand_p (t)) - return error_mark_node; - ret = t; - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND - && TYPE_ATOMIC (strip_array_types (TREE_TYPE (t)))) - { - error_at (OMP_CLAUSE_LOCATION (c), "%<_Atomic%> %qE in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - while (TREE_CODE (t) == INDIRECT_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - while (TREE_CODE (t) == COMPOUND_EXPR) - { - t = TREE_OPERAND (t, 1); - STRIP_NOPS (t); - } - if (TREE_CODE (t) == COMPONENT_REF - && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM)) - { - if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "bit-field %qE in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - while (TREE_CODE (t) == COMPONENT_REF) - { - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is a member of a union", t); - return error_mark_node; - } - t = TREE_OPERAND (t, 0); - while (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - if (ort == C_ORT_ACC && TREE_CODE (t) == MEM_REF) - { - if (maybe_ne (mem_ref_offset (t), 0)) - error_at (OMP_CLAUSE_LOCATION (c), - "cannot dereference %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - else - t = TREE_OPERAND (t, 0); - } - } - } - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) - { - if (DECL_P (t)) - error_at (OMP_CLAUSE_LOCATION (c), - "%qD is not a variable in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - else - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND - && TYPE_ATOMIC (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), "%<_Atomic%> %qD in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND - && VAR_P (t) - && DECL_THREAD_LOCAL_P (t)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD is threadprivate variable in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) - && TYPE_ATOMIC (TREE_TYPE (t)) - && POINTER_TYPE_P (TREE_TYPE (t))) - { - /* If the array section is pointer based and the pointer - itself is _Atomic qualified, we need to atomically load - the pointer. */ - c_expr expr; - memset (&expr, 0, sizeof (expr)); - expr.value = ret; - expr = convert_lvalue_to_rvalue (OMP_CLAUSE_LOCATION (c), - expr, false, false); - ret = expr.value; - } - return ret; - } - - ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, - maybe_zero_len, first_non_one, ort); - if (ret == error_mark_node || ret == NULL_TREE) - return ret; - - type = TREE_TYPE (ret); - low_bound = TREE_PURPOSE (t); - length = TREE_VALUE (t); - - if (low_bound == error_mark_node || length == error_mark_node) - return error_mark_node; - - if (low_bound && !INTEGRAL_TYPE_P (TREE_TYPE (low_bound))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "low bound %qE of array section does not have integral type", - low_bound); - return error_mark_node; - } - if (length && !INTEGRAL_TYPE_P (TREE_TYPE (length))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "length %qE of array section does not have integral type", - length); - return error_mark_node; - } - if (low_bound - && TREE_CODE (low_bound) == INTEGER_CST - && TYPE_PRECISION (TREE_TYPE (low_bound)) - > TYPE_PRECISION (sizetype)) - low_bound = fold_convert (sizetype, low_bound); - if (length - && TREE_CODE (length) == INTEGER_CST - && TYPE_PRECISION (TREE_TYPE (length)) - > TYPE_PRECISION (sizetype)) - length = fold_convert (sizetype, length); - if (low_bound == NULL_TREE) - low_bound = integer_zero_node; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)) - { - if (length != integer_one_node) - { - error_at (OMP_CLAUSE_LOCATION (c), - "expected single pointer in %qs clause", - c_omp_map_clause_name (c, ort == C_ORT_ACC)); - return error_mark_node; - } - } - if (length != NULL_TREE) - { - if (!integer_nonzerop (length)) - { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) - { - if (integer_zerop (length)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "zero length array section in %qs clause", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - } - else - maybe_zero_len = true; - } - if (first_non_one == types.length () - && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) - first_non_one++; - } - if (TREE_CODE (type) == ARRAY_TYPE) - { - if (length == NULL_TREE - && (TYPE_DOMAIN (type) == NULL_TREE - || TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "for unknown bound array type length expression must " - "be specified"); - return error_mark_node; - } - if (TREE_CODE (low_bound) == INTEGER_CST - && tree_int_cst_sgn (low_bound) == -1) - { - error_at (OMP_CLAUSE_LOCATION (c), - "negative low bound in array section in %qs clause", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - if (length != NULL_TREE - && TREE_CODE (length) == INTEGER_CST - && tree_int_cst_sgn (length) == -1) - { - error_at (OMP_CLAUSE_LOCATION (c), - "negative length in array section in %qs clause", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - if (TYPE_DOMAIN (type) - && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) - && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) - == INTEGER_CST) - { - tree size - = fold_convert (sizetype, TYPE_MAX_VALUE (TYPE_DOMAIN (type))); - size = size_binop (PLUS_EXPR, size, size_one_node); - if (TREE_CODE (low_bound) == INTEGER_CST) - { - if (tree_int_cst_lt (size, low_bound)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "low bound %qE above array section size " - "in %qs clause", low_bound, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - if (tree_int_cst_equal (size, low_bound)) - { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) - { - error_at (OMP_CLAUSE_LOCATION (c), - "zero length array section in %qs clause", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - maybe_zero_len = true; - } - else if (length == NULL_TREE - && first_non_one == types.length () - && tree_int_cst_equal - (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), - low_bound)) - first_non_one++; - } - else if (length == NULL_TREE) - { - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_IN_REDUCTION - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TASK_REDUCTION) - maybe_zero_len = true; - if (first_non_one == types.length ()) - first_non_one++; - } - if (length && TREE_CODE (length) == INTEGER_CST) - { - if (tree_int_cst_lt (size, length)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "length %qE above array section size " - "in %qs clause", length, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - if (TREE_CODE (low_bound) == INTEGER_CST) - { - tree lbpluslen - = size_binop (PLUS_EXPR, - fold_convert (sizetype, low_bound), - fold_convert (sizetype, length)); - if (TREE_CODE (lbpluslen) == INTEGER_CST - && tree_int_cst_lt (size, lbpluslen)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "high bound %qE above array section size " - "in %qs clause", lbpluslen, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - } - } - } - else if (length == NULL_TREE) - { - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_IN_REDUCTION - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TASK_REDUCTION) - maybe_zero_len = true; - if (first_non_one == types.length ()) - first_non_one++; - } - - /* For [lb:] we will need to evaluate lb more than once. */ - if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) - { - tree lb = save_expr (low_bound); - if (lb != low_bound) - { - TREE_PURPOSE (t) = lb; - low_bound = lb; - } - } - } - else if (TREE_CODE (type) == POINTER_TYPE) - { - if (length == NULL_TREE) - { - if (TREE_CODE (ret) == PARM_DECL && C_ARRAY_PARAMETER (ret)) - error_at (OMP_CLAUSE_LOCATION (c), - "for array function parameter length expression " - "must be specified"); - else - error_at (OMP_CLAUSE_LOCATION (c), - "for pointer type length expression must be specified"); - return error_mark_node; - } - if (length != NULL_TREE - && TREE_CODE (length) == INTEGER_CST - && tree_int_cst_sgn (length) == -1) - { - error_at (OMP_CLAUSE_LOCATION (c), - "negative length in array section in %qs clause", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - /* If there is a pointer type anywhere but in the very first - array-section-subscript, the array section could be non-contiguous. */ - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY - && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST) - { - /* If any prior dimension has a non-one length, then deem this - array section as non-contiguous. */ - for (tree d = TREE_CHAIN (t); TREE_CODE (d) == TREE_LIST; - d = TREE_CHAIN (d)) - { - tree d_length = TREE_VALUE (d); - if (d_length == NULL_TREE || !integer_onep (d_length)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "array section is not contiguous in %qs clause", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - } - } - } - else - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE does not have pointer or array type", ret); - return error_mark_node; - } - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) - types.safe_push (TREE_TYPE (ret)); - /* We will need to evaluate lb more than once. */ - tree lb = save_expr (low_bound); - if (lb != low_bound) - { - TREE_PURPOSE (t) = lb; - low_bound = lb; - } - ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound); - return ret; -} - -/* Handle array sections for clause C. */ - -static bool -handle_omp_array_sections (tree c, enum c_omp_region_type ort) -{ - bool maybe_zero_len = false; - unsigned int first_non_one = 0; - auto_vec types; - tree *tp = &OMP_CLAUSE_DECL (c); - if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) - && TREE_CODE (*tp) == TREE_LIST - && TREE_PURPOSE (*tp) - && TREE_CODE (TREE_PURPOSE (*tp)) == TREE_VEC) - tp = &TREE_VALUE (*tp); - tree first = handle_omp_array_sections_1 (c, *tp, types, - maybe_zero_len, first_non_one, - ort); - if (first == error_mark_node) - return true; - if (first == NULL_TREE) - return false; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) - { - tree t = *tp; - tree tem = NULL_TREE; - /* Need to evaluate side effects in the length expressions - if any. */ - while (TREE_CODE (t) == TREE_LIST) - { - if (TREE_VALUE (t) && TREE_SIDE_EFFECTS (TREE_VALUE (t))) - { - if (tem == NULL_TREE) - tem = TREE_VALUE (t); - else - tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), - TREE_VALUE (t), tem); - } - t = TREE_CHAIN (t); - } - if (tem) - first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); - first = c_fully_fold (first, false, NULL, true); - *tp = first; - } - else - { - unsigned int num = types.length (), i; - tree t, side_effects = NULL_TREE, size = NULL_TREE; - tree condition = NULL_TREE; - - if (int_size_in_bytes (TREE_TYPE (first)) <= 0) - maybe_zero_len = true; - - for (i = num, t = OMP_CLAUSE_DECL (c); i > 0; - t = TREE_CHAIN (t)) - { - tree low_bound = TREE_PURPOSE (t); - tree length = TREE_VALUE (t); - - i--; - if (low_bound - && TREE_CODE (low_bound) == INTEGER_CST - && TYPE_PRECISION (TREE_TYPE (low_bound)) - > TYPE_PRECISION (sizetype)) - low_bound = fold_convert (sizetype, low_bound); - if (length - && TREE_CODE (length) == INTEGER_CST - && TYPE_PRECISION (TREE_TYPE (length)) - > TYPE_PRECISION (sizetype)) - length = fold_convert (sizetype, length); - if (low_bound == NULL_TREE) - low_bound = integer_zero_node; - if (!maybe_zero_len && i > first_non_one) - { - if (integer_nonzerop (low_bound)) - goto do_warn_noncontiguous; - if (length != NULL_TREE - && TREE_CODE (length) == INTEGER_CST - && TYPE_DOMAIN (types[i]) - && TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])) - && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (types[i]))) - == INTEGER_CST) - { - tree size; - size = size_binop (PLUS_EXPR, - TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), - size_one_node); - if (!tree_int_cst_equal (length, size)) - { - do_warn_noncontiguous: - error_at (OMP_CLAUSE_LOCATION (c), - "array section is not contiguous in %qs " - "clause", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return true; - } - } - if (length != NULL_TREE - && TREE_SIDE_EFFECTS (length)) - { - if (side_effects == NULL_TREE) - side_effects = length; - else - side_effects = build2 (COMPOUND_EXPR, - TREE_TYPE (side_effects), - length, side_effects); - } - } - else - { - tree l; - - if (i > first_non_one - && ((length && integer_nonzerop (length)) - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION)) - continue; - if (length) - l = fold_convert (sizetype, length); - else - { - l = size_binop (PLUS_EXPR, - TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), - size_one_node); - l = size_binop (MINUS_EXPR, l, - fold_convert (sizetype, low_bound)); - } - if (i > first_non_one) - { - l = fold_build2 (NE_EXPR, boolean_type_node, l, - size_zero_node); - if (condition == NULL_TREE) - condition = l; - else - condition = fold_build2 (BIT_AND_EXPR, boolean_type_node, - l, condition); - } - else if (size == NULL_TREE) - { - size = size_in_bytes (TREE_TYPE (types[i])); - tree eltype = TREE_TYPE (types[num - 1]); - while (TREE_CODE (eltype) == ARRAY_TYPE) - eltype = TREE_TYPE (eltype); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) - { - if (integer_zerop (size) - || integer_zerop (size_in_bytes (eltype))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "zero length array section in %qs clause", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - size = size_binop (EXACT_DIV_EXPR, size, - size_in_bytes (eltype)); - } - size = size_binop (MULT_EXPR, size, l); - if (condition) - size = fold_build3 (COND_EXPR, sizetype, condition, - size, size_zero_node); - } - else - size = size_binop (MULT_EXPR, size, l); - } - } - if (side_effects) - size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) - { - size = size_binop (MINUS_EXPR, size, size_one_node); - size = c_fully_fold (size, false, NULL); - size = save_expr (size); - tree index_type = build_index_type (size); - tree eltype = TREE_TYPE (first); - while (TREE_CODE (eltype) == ARRAY_TYPE) - eltype = TREE_TYPE (eltype); - tree type = build_array_type (eltype, index_type); - tree ptype = build_pointer_type (eltype); - if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) - t = build_fold_addr_expr (t); - tree t2 = build_fold_addr_expr (first); - t2 = fold_convert_loc (OMP_CLAUSE_LOCATION (c), - ptrdiff_type_node, t2); - t2 = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, - ptrdiff_type_node, t2, - fold_convert_loc (OMP_CLAUSE_LOCATION (c), - ptrdiff_type_node, t)); - t2 = c_fully_fold (t2, false, NULL); - if (tree_fits_shwi_p (t2)) - t = build2 (MEM_REF, type, t, - build_int_cst (ptype, tree_to_shwi (t2))); - else - { - t2 = fold_convert_loc (OMP_CLAUSE_LOCATION (c), sizetype, t2); - t = build2_loc (OMP_CLAUSE_LOCATION (c), POINTER_PLUS_EXPR, - TREE_TYPE (t), t, t2); - t = build2 (MEM_REF, type, t, build_int_cst (ptype, 0)); - } - OMP_CLAUSE_DECL (c) = t; - return false; - } - first = c_fully_fold (first, false, NULL); - OMP_CLAUSE_DECL (c) = first; - if (size) - size = c_fully_fold (size, false, NULL); - OMP_CLAUSE_SIZE (c) = size; - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP - || (TREE_CODE (t) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)) - return false; - gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR); - switch (OMP_CLAUSE_MAP_KIND (c)) - { - case GOMP_MAP_ALLOC: - case GOMP_MAP_IF_PRESENT: - case GOMP_MAP_TO: - case GOMP_MAP_FROM: - case GOMP_MAP_TOFROM: - case GOMP_MAP_ALWAYS_TO: - case GOMP_MAP_ALWAYS_FROM: - case GOMP_MAP_ALWAYS_TOFROM: - case GOMP_MAP_RELEASE: - case GOMP_MAP_DELETE: - case GOMP_MAP_FORCE_TO: - case GOMP_MAP_FORCE_FROM: - case GOMP_MAP_FORCE_TOFROM: - case GOMP_MAP_FORCE_PRESENT: - OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1; - break; - default: - break; - } - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - if (TREE_CODE (t) == COMPONENT_REF) - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH); - else - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER); - OMP_CLAUSE_MAP_IMPLICIT (c2) = OMP_CLAUSE_MAP_IMPLICIT (c); - if (OMP_CLAUSE_MAP_KIND (c2) != GOMP_MAP_FIRSTPRIVATE_POINTER - && !c_mark_addressable (t)) - return false; - OMP_CLAUSE_DECL (c2) = t; - t = build_fold_addr_expr (first); - t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), ptrdiff_type_node, t); - tree ptr = OMP_CLAUSE_DECL (c2); - if (!POINTER_TYPE_P (TREE_TYPE (ptr))) - ptr = build_fold_addr_expr (ptr); - t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, - ptrdiff_type_node, t, - fold_convert_loc (OMP_CLAUSE_LOCATION (c), - ptrdiff_type_node, ptr)); - t = c_fully_fold (t, false, NULL); - OMP_CLAUSE_SIZE (c2) = t; - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = c2; - } - return false; -} - -/* Helper function of finish_omp_clauses. Clone STMT as if we were making - an inline call. But, remap - the OMP_DECL1 VAR_DECL (omp_out resp. omp_orig) to PLACEHOLDER - and OMP_DECL2 VAR_DECL (omp_in resp. omp_priv) to DECL. */ - -static tree -c_clone_omp_udr (tree stmt, tree omp_decl1, tree omp_decl2, - tree decl, tree placeholder) -{ - copy_body_data id; - hash_map decl_map; - - decl_map.put (omp_decl1, placeholder); - decl_map.put (omp_decl2, decl); - memset (&id, 0, sizeof (id)); - id.src_fn = DECL_CONTEXT (omp_decl1); - id.dst_fn = current_function_decl; - id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn); - id.decl_map = &decl_map; - - id.copy_decl = copy_decl_no_change; - id.transform_call_graph_edges = CB_CGE_DUPLICATE; - id.transform_new_cfg = true; - id.transform_return_to_modify = false; - id.eh_lp_nr = 0; - walk_tree (&stmt, copy_tree_body_r, &id, NULL); - return stmt; -} - -/* Helper function of c_finish_omp_clauses, called via walk_tree. - Find OMP_CLAUSE_PLACEHOLDER (passed in DATA) in *TP. */ - -static tree -c_find_omp_placeholder_r (tree *tp, int *, void *data) -{ - if (*tp == (tree) data) - return *tp; - return NULL_TREE; -} - -/* Similarly, but also walk aggregate fields. */ - -struct c_find_omp_var_s { tree var; hash_set *pset; }; - -static tree -c_find_omp_var_r (tree *tp, int *, void *data) -{ - if (*tp == ((struct c_find_omp_var_s *) data)->var) - return *tp; - if (RECORD_OR_UNION_TYPE_P (*tp)) - { - tree field; - hash_set *pset = ((struct c_find_omp_var_s *) data)->pset; - - for (field = TYPE_FIELDS (*tp); field; - field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL) - { - tree ret = walk_tree (&DECL_FIELD_OFFSET (field), - c_find_omp_var_r, data, pset); - if (ret) - return ret; - ret = walk_tree (&DECL_SIZE (field), c_find_omp_var_r, data, pset); - if (ret) - return ret; - ret = walk_tree (&DECL_SIZE_UNIT (field), c_find_omp_var_r, data, - pset); - if (ret) - return ret; - ret = walk_tree (&TREE_TYPE (field), c_find_omp_var_r, data, pset); - if (ret) - return ret; - } - } - else if (INTEGRAL_TYPE_P (*tp)) - return walk_tree (&TYPE_MAX_VALUE (*tp), c_find_omp_var_r, data, - ((struct c_find_omp_var_s *) data)->pset); - return NULL_TREE; -} - -/* Finish OpenMP iterators ITER. Return true if they are errorneous - and clauses containing them should be removed. */ - -static bool -c_omp_finish_iterators (tree iter) -{ - bool ret = false; - for (tree it = iter; it; it = TREE_CHAIN (it)) - { - tree var = TREE_VEC_ELT (it, 0); - tree begin = TREE_VEC_ELT (it, 1); - tree end = TREE_VEC_ELT (it, 2); - tree step = TREE_VEC_ELT (it, 3); - tree orig_step; - tree type = TREE_TYPE (var); - location_t loc = DECL_SOURCE_LOCATION (var); - if (type == error_mark_node) - { - ret = true; - continue; - } - if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) - { - error_at (loc, "iterator %qD has neither integral nor pointer type", - var); - ret = true; - continue; - } - else if (TYPE_ATOMIC (type)) - { - error_at (loc, "iterator %qD has %<_Atomic%> qualified type", var); - ret = true; - continue; - } - else if (TYPE_READONLY (type)) - { - error_at (loc, "iterator %qD has const qualified type", var); - ret = true; - continue; - } - else if (step == error_mark_node - || TREE_TYPE (step) == error_mark_node) - { - ret = true; - continue; - } - else if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) - { - error_at (EXPR_LOC_OR_LOC (step, loc), - "iterator step with non-integral type"); - ret = true; - continue; - } - begin = c_fully_fold (build_c_cast (loc, type, begin), false, NULL); - end = c_fully_fold (build_c_cast (loc, type, end), false, NULL); - orig_step = save_expr (c_fully_fold (step, false, NULL)); - tree stype = POINTER_TYPE_P (type) ? sizetype : type; - step = c_fully_fold (build_c_cast (loc, stype, orig_step), false, NULL); - if (POINTER_TYPE_P (type)) - { - begin = save_expr (begin); - step = pointer_int_sum (loc, PLUS_EXPR, begin, step); - step = fold_build2_loc (loc, MINUS_EXPR, sizetype, - fold_convert (sizetype, step), - fold_convert (sizetype, begin)); - step = fold_convert (ssizetype, step); - } - if (integer_zerop (step)) - { - error_at (loc, "iterator %qD has zero step", var); - ret = true; - continue; - } - - if (begin == error_mark_node - || end == error_mark_node - || step == error_mark_node - || orig_step == error_mark_node) - { - ret = true; - continue; - } - hash_set pset; - tree it2; - for (it2 = TREE_CHAIN (it); it2; it2 = TREE_CHAIN (it2)) - { - tree var2 = TREE_VEC_ELT (it2, 0); - tree begin2 = TREE_VEC_ELT (it2, 1); - tree end2 = TREE_VEC_ELT (it2, 2); - tree step2 = TREE_VEC_ELT (it2, 3); - tree type2 = TREE_TYPE (var2); - location_t loc2 = DECL_SOURCE_LOCATION (var2); - struct c_find_omp_var_s data = { var, &pset }; - if (walk_tree (&type2, c_find_omp_var_r, &data, &pset)) - { - error_at (loc2, - "type of iterator %qD refers to outer iterator %qD", - var2, var); - break; - } - else if (walk_tree (&begin2, c_find_omp_var_r, &data, &pset)) - { - error_at (EXPR_LOC_OR_LOC (begin2, loc2), - "begin expression refers to outer iterator %qD", var); - break; - } - else if (walk_tree (&end2, c_find_omp_var_r, &data, &pset)) - { - error_at (EXPR_LOC_OR_LOC (end2, loc2), - "end expression refers to outer iterator %qD", var); - break; - } - else if (walk_tree (&step2, c_find_omp_var_r, &data, &pset)) - { - error_at (EXPR_LOC_OR_LOC (step2, loc2), - "step expression refers to outer iterator %qD", var); - break; - } - } - if (it2) - { - ret = true; - continue; - } - TREE_VEC_ELT (it, 1) = begin; - TREE_VEC_ELT (it, 2) = end; - TREE_VEC_ELT (it, 3) = step; - TREE_VEC_ELT (it, 4) = orig_step; - } - return ret; -} - -/* Ensure that pointers are used in OpenACC attach and detach clauses. - Return true if an error has been detected. */ - -static bool -c_oacc_check_attachments (tree c) -{ - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) - return false; - - /* OpenACC attach / detach clauses must be pointers. */ - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH) - { - tree t = OMP_CLAUSE_DECL (c); - - while (TREE_CODE (t) == TREE_LIST) - t = TREE_CHAIN (t); - - if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) - { - error_at (OMP_CLAUSE_LOCATION (c), "expected pointer in %qs clause", - c_omp_map_clause_name (c, true)); - return true; - } - } - - return false; -} - -/* For all elements of CLAUSES, validate them against their constraints. - Remove any elements from the list that are invalid. */ - -tree -c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) -{ - bitmap_head generic_head, firstprivate_head, lastprivate_head; - bitmap_head aligned_head, map_head, map_field_head, map_firstprivate_head; - bitmap_head oacc_reduction_head; - tree c, t, type, *pc; - tree simdlen = NULL_TREE, safelen = NULL_TREE; - bool branch_seen = false; - bool copyprivate_seen = false; - bool mergeable_seen = false; - tree *detach_seen = NULL; - bool linear_variable_step_check = false; - tree *nowait_clause = NULL; - tree ordered_clause = NULL_TREE; - tree schedule_clause = NULL_TREE; - bool oacc_async = false; - bool indir_component_ref_p = false; - tree last_iterators = NULL_TREE; - bool last_iterators_remove = false; - tree *nogroup_seen = NULL; - tree *order_clause = NULL; - /* 1 if normal/task reduction has been seen, -1 if inscan reduction - has been seen, -2 if mixed inscan/normal reduction diagnosed. */ - int reduction_seen = 0; - bool allocate_seen = false; - bool implicit_moved = false; - bool target_in_reduction_seen = false; - - bitmap_obstack_initialize (NULL); - bitmap_initialize (&generic_head, &bitmap_default_obstack); - bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); - bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); - bitmap_initialize (&aligned_head, &bitmap_default_obstack); - /* If ort == C_ORT_OMP_DECLARE_SIMD used as uniform_head instead. */ - bitmap_initialize (&map_head, &bitmap_default_obstack); - bitmap_initialize (&map_field_head, &bitmap_default_obstack); - bitmap_initialize (&map_firstprivate_head, &bitmap_default_obstack); - /* If ort == C_ORT_OMP used as nontemporal_head or use_device_xxx_head - instead and for ort == C_ORT_OMP_TARGET used as in_reduction_head. */ - bitmap_initialize (&oacc_reduction_head, &bitmap_default_obstack); - - if (ort & C_ORT_ACC) - for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ASYNC) - { - oacc_async = true; - break; - } - - for (pc = &clauses, c = clauses; c ; c = *pc) - { - bool remove = false; - bool need_complete = false; - bool need_implicitly_determined = false; - - switch (OMP_CLAUSE_CODE (c)) - { - case OMP_CLAUSE_SHARED: - need_implicitly_determined = true; - goto check_dup_generic; - - case OMP_CLAUSE_PRIVATE: - need_complete = true; - need_implicitly_determined = true; - goto check_dup_generic; - - case OMP_CLAUSE_REDUCTION: - if (reduction_seen == 0) - reduction_seen = OMP_CLAUSE_REDUCTION_INSCAN (c) ? -1 : 1; - else if (reduction_seen != -2 - && reduction_seen != (OMP_CLAUSE_REDUCTION_INSCAN (c) - ? -1 : 1)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% and non-% % clauses " - "on the same construct"); - reduction_seen = -2; - } - /* FALLTHRU */ - case OMP_CLAUSE_IN_REDUCTION: - case OMP_CLAUSE_TASK_REDUCTION: - need_implicitly_determined = true; - t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST) - { - if (handle_omp_array_sections (c, ort)) - { - remove = true; - break; - } - - t = OMP_CLAUSE_DECL (c); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - && OMP_CLAUSE_REDUCTION_INSCAN (c)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% % clause with array " - "section"); - remove = true; - break; - } - } - t = require_complete_type (OMP_CLAUSE_LOCATION (c), t); - if (t == error_mark_node) - { - remove = true; - break; - } - if (oacc_async) - c_mark_addressable (t); - type = TREE_TYPE (t); - if (TREE_CODE (t) == MEM_REF) - type = TREE_TYPE (type); - if (TREE_CODE (type) == ARRAY_TYPE) - { - tree oatype = type; - gcc_assert (TREE_CODE (t) != MEM_REF); - while (TREE_CODE (type) == ARRAY_TYPE) - type = TREE_TYPE (type); - if (integer_zerop (TYPE_SIZE_UNIT (type))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD in % clause is a zero size array", - t); - remove = true; - break; - } - tree size = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (oatype), - TYPE_SIZE_UNIT (type)); - if (integer_zerop (size)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD in % clause is a zero size array", - t); - remove = true; - break; - } - size = size_binop (MINUS_EXPR, size, size_one_node); - size = save_expr (size); - tree index_type = build_index_type (size); - tree atype = build_array_type (TYPE_MAIN_VARIANT (type), - index_type); - atype = c_build_qualified_type (atype, TYPE_QUALS (type)); - tree ptype = build_pointer_type (type); - if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) - t = build_fold_addr_expr (t); - t = build2 (MEM_REF, atype, t, build_int_cst (ptype, 0)); - OMP_CLAUSE_DECL (c) = t; - } - if (TYPE_ATOMIC (type)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<_Atomic%> %qE in % clause", t); - remove = true; - break; - } - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION - || OMP_CLAUSE_REDUCTION_TASK (c)) - { - /* Disallow zero sized or potentially zero sized task - reductions. */ - if (integer_zerop (TYPE_SIZE_UNIT (type))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "zero sized type %qT in %qs clause", type, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - break; - } - else if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) - { - error_at (OMP_CLAUSE_LOCATION (c), - "variable sized type %qT in %qs clause", type, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - break; - } - } - if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE - && (FLOAT_TYPE_P (type) - || TREE_CODE (type) == COMPLEX_TYPE)) - { - enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c); - const char *r_name = NULL; - - switch (r_code) - { - case PLUS_EXPR: - case MULT_EXPR: - case MINUS_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - break; - case MIN_EXPR: - if (TREE_CODE (type) == COMPLEX_TYPE) - r_name = "min"; - break; - case MAX_EXPR: - if (TREE_CODE (type) == COMPLEX_TYPE) - r_name = "max"; - break; - case BIT_AND_EXPR: - r_name = "&"; - break; - case BIT_XOR_EXPR: - r_name = "^"; - break; - case BIT_IOR_EXPR: - r_name = "|"; - break; - default: - gcc_unreachable (); - } - if (r_name) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE has invalid type for %", - t, r_name); - remove = true; - break; - } - } - else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node) - { - error_at (OMP_CLAUSE_LOCATION (c), - "user defined reduction not found for %qE", t); - remove = true; - break; - } - else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) - { - tree list = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); - type = TYPE_MAIN_VARIANT (type); - tree placeholder = build_decl (OMP_CLAUSE_LOCATION (c), - VAR_DECL, NULL_TREE, type); - tree decl_placeholder = NULL_TREE; - OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder; - DECL_ARTIFICIAL (placeholder) = 1; - DECL_IGNORED_P (placeholder) = 1; - if (TREE_CODE (t) == MEM_REF) - { - decl_placeholder = build_decl (OMP_CLAUSE_LOCATION (c), - VAR_DECL, NULL_TREE, type); - OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = decl_placeholder; - DECL_ARTIFICIAL (decl_placeholder) = 1; - DECL_IGNORED_P (decl_placeholder) = 1; - } - if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 0))) - c_mark_addressable (placeholder); - if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 1))) - c_mark_addressable (decl_placeholder ? decl_placeholder - : OMP_CLAUSE_DECL (c)); - OMP_CLAUSE_REDUCTION_MERGE (c) - = c_clone_omp_udr (TREE_VEC_ELT (list, 2), - TREE_VEC_ELT (list, 0), - TREE_VEC_ELT (list, 1), - decl_placeholder ? decl_placeholder - : OMP_CLAUSE_DECL (c), placeholder); - OMP_CLAUSE_REDUCTION_MERGE (c) - = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, - void_type_node, NULL_TREE, - OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE); - TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_MERGE (c)) = 1; - if (TREE_VEC_LENGTH (list) == 6) - { - if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 3))) - c_mark_addressable (decl_placeholder ? decl_placeholder - : OMP_CLAUSE_DECL (c)); - if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 4))) - c_mark_addressable (placeholder); - tree init = TREE_VEC_ELT (list, 5); - if (init == error_mark_node) - init = DECL_INITIAL (TREE_VEC_ELT (list, 3)); - OMP_CLAUSE_REDUCTION_INIT (c) - = c_clone_omp_udr (init, TREE_VEC_ELT (list, 4), - TREE_VEC_ELT (list, 3), - decl_placeholder ? decl_placeholder - : OMP_CLAUSE_DECL (c), placeholder); - if (TREE_VEC_ELT (list, 5) == error_mark_node) - { - tree v = decl_placeholder ? decl_placeholder : t; - OMP_CLAUSE_REDUCTION_INIT (c) - = build2 (INIT_EXPR, TREE_TYPE (v), v, - OMP_CLAUSE_REDUCTION_INIT (c)); - } - if (walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c), - c_find_omp_placeholder_r, - placeholder, NULL)) - OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1; - } - else - { - tree init; - tree v = decl_placeholder ? decl_placeholder : t; - if (AGGREGATE_TYPE_P (TREE_TYPE (v))) - init = build_constructor (TREE_TYPE (v), NULL); - else - init = fold_convert (TREE_TYPE (v), integer_zero_node); - OMP_CLAUSE_REDUCTION_INIT (c) - = build2 (INIT_EXPR, TREE_TYPE (v), v, init); - } - OMP_CLAUSE_REDUCTION_INIT (c) - = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, - void_type_node, NULL_TREE, - OMP_CLAUSE_REDUCTION_INIT (c), NULL_TREE); - TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_INIT (c)) = 1; - } - if (TREE_CODE (t) == MEM_REF) - { - if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t))) == NULL_TREE - || TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t)))) - != INTEGER_CST) - { - sorry ("variable length element type in array " - "% clause"); - remove = true; - break; - } - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == ADDR_EXPR) - t = TREE_OPERAND (t, 0); - } - goto check_dup_generic_t; - - case OMP_CLAUSE_COPYPRIVATE: - copyprivate_seen = true; - if (nowait_clause) - { - error_at (OMP_CLAUSE_LOCATION (*nowait_clause), - "% clause must not be used together " - "with %"); - *nowait_clause = OMP_CLAUSE_CHAIN (*nowait_clause); - nowait_clause = NULL; - } - goto check_dup_generic; - - case OMP_CLAUSE_COPYIN: - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) || !DECL_THREAD_LOCAL_P (t)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE must be % for %", t); - remove = true; - break; - } - goto check_dup_generic; - - case OMP_CLAUSE_LINEAR: - if (ort != C_ORT_OMP_DECLARE_SIMD) - need_implicitly_determined = true; - t = OMP_CLAUSE_DECL (c); - if (ort != C_ORT_OMP_DECLARE_SIMD - && OMP_CLAUSE_LINEAR_KIND (c) != OMP_CLAUSE_LINEAR_DEFAULT) - { - error_at (OMP_CLAUSE_LOCATION (c), - "modifier should not be specified in % " - "clause on % or % constructs"); - OMP_CLAUSE_LINEAR_KIND (c) = OMP_CLAUSE_LINEAR_DEFAULT; - } - if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) - && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) - { - error_at (OMP_CLAUSE_LOCATION (c), - "linear clause applied to non-integral non-pointer " - "variable with type %qT", TREE_TYPE (t)); - remove = true; - break; - } - if (TYPE_ATOMIC (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<_Atomic%> %qD in % clause", t); - remove = true; - break; - } - if (ort == C_ORT_OMP_DECLARE_SIMD) - { - tree s = OMP_CLAUSE_LINEAR_STEP (c); - if (TREE_CODE (s) == PARM_DECL) - { - OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c) = 1; - /* map_head bitmap is used as uniform_head if - declare_simd. */ - if (!bitmap_bit_p (&map_head, DECL_UID (s))) - linear_variable_step_check = true; - goto check_dup_generic; - } - if (TREE_CODE (s) != INTEGER_CST) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% clause step %qE is neither constant " - "nor a parameter", s); - remove = true; - break; - } - } - if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE) - { - tree s = OMP_CLAUSE_LINEAR_STEP (c); - s = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, - OMP_CLAUSE_DECL (c), s); - s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, - sizetype, fold_convert (sizetype, s), - fold_convert - (sizetype, OMP_CLAUSE_DECL (c))); - if (s == error_mark_node) - s = size_one_node; - OMP_CLAUSE_LINEAR_STEP (c) = s; - } - else - OMP_CLAUSE_LINEAR_STEP (c) - = fold_convert (TREE_TYPE (t), OMP_CLAUSE_LINEAR_STEP (c)); - goto check_dup_generic; - - check_dup_generic: - t = OMP_CLAUSE_DECL (c); - check_dup_generic_t: - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if ((ort == C_ORT_ACC - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) - || (ort == C_ORT_OMP - && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR - || (OMP_CLAUSE_CODE (c) - == OMP_CLAUSE_USE_DEVICE_ADDR))) - || (ort == C_ORT_OMP_TARGET - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)) - { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION - && (bitmap_bit_p (&generic_head, DECL_UID (t)) - || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in data-sharing " - "clauses", t); - remove = true; - break; - } - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) - target_in_reduction_seen = true; - if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - ort == C_ORT_ACC - ? "%qD appears more than once in reduction clauses" - : "%qD appears more than once in data clauses", - t); - remove = true; - } - else - bitmap_set_bit (&oacc_reduction_head, DECL_UID (t)); - } - else if (bitmap_bit_p (&generic_head, DECL_UID (t)) - || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) - || bitmap_bit_p (&lastprivate_head, DECL_UID (t)) - || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE appears more than once in data clauses", t); - remove = true; - } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE - && bitmap_bit_p (&map_head, DECL_UID (t))) - { - if (ort == C_ORT_ACC) - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in data clauses", t); - else - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears both in data and map clauses", t); - remove = true; - } - else - bitmap_set_bit (&generic_head, DECL_UID (t)); - break; - - case OMP_CLAUSE_FIRSTPRIVATE: - if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) && !implicit_moved) - { - move_implicit: - implicit_moved = true; - /* Move firstprivate and map clauses with - OMP_CLAUSE_{FIRSTPRIVATE,MAP}_IMPLICIT set to the end of - clauses chain. */ - tree cl1 = NULL_TREE, cl2 = NULL_TREE; - tree *pc1 = pc, *pc2 = &cl1, *pc3 = &cl2; - while (*pc1) - if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_FIRSTPRIVATE - && OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (*pc1)) - { - *pc3 = *pc1; - pc3 = &OMP_CLAUSE_CHAIN (*pc3); - *pc1 = OMP_CLAUSE_CHAIN (*pc1); - } - else if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_IMPLICIT (*pc1)) - { - *pc2 = *pc1; - pc2 = &OMP_CLAUSE_CHAIN (*pc2); - *pc1 = OMP_CLAUSE_CHAIN (*pc1); - } - else - pc1 = &OMP_CLAUSE_CHAIN (*pc1); - *pc3 = NULL; - *pc2 = cl2; - *pc1 = cl1; - continue; - } - t = OMP_CLAUSE_DECL (c); - need_complete = true; - need_implicitly_determined = true; - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in clause %", t); - remove = true; - } - else if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) - && !OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c) - && bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) - remove = true; - else if (bitmap_bit_p (&generic_head, DECL_UID (t)) - || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) - || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE appears more than once in data clauses", t); - remove = true; - } - else if (bitmap_bit_p (&map_head, DECL_UID (t))) - { - if (ort == C_ORT_ACC) - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in data clauses", t); - else if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) - && !OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c)) - /* Silently drop the clause. */; - else - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears both in data and map clauses", t); - remove = true; - } - else - bitmap_set_bit (&firstprivate_head, DECL_UID (t)); - break; - - case OMP_CLAUSE_LASTPRIVATE: - t = OMP_CLAUSE_DECL (c); - need_complete = true; - need_implicitly_determined = true; - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in clause %", t); - remove = true; - } - else if (bitmap_bit_p (&generic_head, DECL_UID (t)) - || bitmap_bit_p (&lastprivate_head, DECL_UID (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE appears more than once in data clauses", t); - remove = true; - } - else - bitmap_set_bit (&lastprivate_head, DECL_UID (t)); - break; - - case OMP_CLAUSE_ALIGNED: - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in % clause", t); - remove = true; - } - else if (!POINTER_TYPE_P (TREE_TYPE (t)) - && TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE in % clause is neither a pointer nor " - "an array", t); - remove = true; - } - else if (TYPE_ATOMIC (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<_Atomic%> %qD in % clause", t); - remove = true; - break; - } - else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE appears more than once in % clauses", - t); - remove = true; - } - else - bitmap_set_bit (&aligned_head, DECL_UID (t)); - break; - - case OMP_CLAUSE_NONTEMPORAL: - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in % clause", t); - remove = true; - } - else if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE appears more than once in % " - "clauses", t); - remove = true; - } - else - bitmap_set_bit (&oacc_reduction_head, DECL_UID (t)); - break; - - case OMP_CLAUSE_ALLOCATE: - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in % clause", t); - remove = true; - } - else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) - { - warning_at (OMP_CLAUSE_LOCATION (c), 0, - "%qE appears more than once in % clauses", - t); - remove = true; - } - else - { - bitmap_set_bit (&aligned_head, DECL_UID (t)); - if (!OMP_CLAUSE_ALLOCATE_COMBINED (c)) - allocate_seen = true; - } - break; - - case OMP_CLAUSE_DEPEND: - t = OMP_CLAUSE_DECL (c); - if (t == NULL_TREE) - { - gcc_assert (OMP_CLAUSE_DEPEND_KIND (c) - == OMP_CLAUSE_DEPEND_SOURCE); - break; - } - if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) - { - gcc_assert (TREE_CODE (t) == TREE_LIST); - for (; t; t = TREE_CHAIN (t)) - { - tree decl = TREE_VALUE (t); - if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) - { - tree offset = TREE_PURPOSE (t); - bool neg = wi::neg_p (wi::to_wide (offset)); - offset = fold_unary (ABS_EXPR, TREE_TYPE (offset), offset); - tree t2 = pointer_int_sum (OMP_CLAUSE_LOCATION (c), - neg ? MINUS_EXPR : PLUS_EXPR, - decl, offset); - t2 = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, - sizetype, - fold_convert (sizetype, t2), - fold_convert (sizetype, decl)); - if (t2 == error_mark_node) - { - remove = true; - break; - } - TREE_PURPOSE (t) = t2; - } - } - break; - } - /* FALLTHRU */ - case OMP_CLAUSE_AFFINITY: - t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) - { - if (TREE_PURPOSE (t) != last_iterators) - last_iterators_remove - = c_omp_finish_iterators (TREE_PURPOSE (t)); - last_iterators = TREE_PURPOSE (t); - t = TREE_VALUE (t); - if (last_iterators_remove) - t = error_mark_node; - } - else - last_iterators = NULL_TREE; - if (TREE_CODE (t) == TREE_LIST) - { - if (handle_omp_array_sections (c, ort)) - remove = true; - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% clause with % dependence " - "type on array section"); - remove = true; - } - break; - } - if (t == error_mark_node) - remove = true; - else if (!lvalue_p (t)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not lvalue expression nor array section in " - "%qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (TREE_CODE (t) == COMPONENT_REF - && DECL_C_BIT_FIELD (TREE_OPERAND (t, 1))) - { - gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY); - error_at (OMP_CLAUSE_LOCATION (c), - "bit-field %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) - { - if (!c_omp_depend_t_p (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE does not have % type in " - "% clause with % dependence " - "type", t); - remove = true; - } - } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && c_omp_depend_t_p (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE should not have % type in " - "% clause with dependence type other than " - "%", t); - remove = true; - } - if (!remove) - { - tree addr = build_unary_op (OMP_CLAUSE_LOCATION (c), ADDR_EXPR, - t, false); - if (addr == error_mark_node) - remove = true; - else - { - t = build_indirect_ref (OMP_CLAUSE_LOCATION (c), addr, - RO_UNARY_STAR); - if (t == error_mark_node) - remove = true; - else if (TREE_CODE (OMP_CLAUSE_DECL (c)) == TREE_LIST - && TREE_PURPOSE (OMP_CLAUSE_DECL (c)) - && (TREE_CODE (TREE_PURPOSE (OMP_CLAUSE_DECL (c))) - == TREE_VEC)) - TREE_VALUE (OMP_CLAUSE_DECL (c)) = t; - else - OMP_CLAUSE_DECL (c) = t; - } - } - break; - - case OMP_CLAUSE_MAP: - if (OMP_CLAUSE_MAP_IMPLICIT (c) && !implicit_moved) - goto move_implicit; - /* FALLTHRU */ - case OMP_CLAUSE_TO: - case OMP_CLAUSE_FROM: - case OMP_CLAUSE__CACHE_: - t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST) - { - if (handle_omp_array_sections (c, ort)) - remove = true; - else - { - t = OMP_CLAUSE_DECL (c); - if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "array section does not have mappable type " - "in %qs clause", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (TYPE_ATOMIC (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<_Atomic%> %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - while (TREE_CODE (t) == ARRAY_REF) - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) - { - do - { - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - } - while (TREE_CODE (t) == COMPONENT_REF - || TREE_CODE (t) == ARRAY_REF); - - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_IMPLICIT (c) - && (bitmap_bit_p (&map_head, DECL_UID (t)) - || bitmap_bit_p (&map_field_head, DECL_UID (t)) - || bitmap_bit_p (&map_firstprivate_head, - DECL_UID (t)))) - { - remove = true; - break; - } - if (bitmap_bit_p (&map_field_head, DECL_UID (t))) - break; - if (bitmap_bit_p (&map_head, DECL_UID (t))) - { - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in motion " - "clauses", t); - else if (ort == C_ORT_ACC) - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in data " - "clauses", t); - else - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in map " - "clauses", t); - remove = true; - } - else - { - bitmap_set_bit (&map_head, DECL_UID (t)); - bitmap_set_bit (&map_field_head, DECL_UID (t)); - } - } - } - if (c_oacc_check_attachments (c)) - remove = true; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)) - /* In this case, we have a single array element which is a - pointer, and we already set OMP_CLAUSE_SIZE in - handle_omp_array_sections above. For attach/detach clauses, - reset the OMP_CLAUSE_SIZE (representing a bias) to zero - here. */ - OMP_CLAUSE_SIZE (c) = size_zero_node; - break; - } - if (t == error_mark_node) - { - remove = true; - break; - } - /* OpenACC attach / detach clauses must be pointers. */ - if (c_oacc_check_attachments (c)) - { - remove = true; - break; - } - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)) - /* For attach/detach clauses, set OMP_CLAUSE_SIZE (representing a - bias) to zero here, so it is not set erroneously to the pointer - size later on in gimplify.c. */ - OMP_CLAUSE_SIZE (c) = size_zero_node; - while (TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - while (TREE_CODE (t) == COMPOUND_EXPR) - { - t = TREE_OPERAND (t, 1); - STRIP_NOPS (t); - } - indir_component_ref_p = false; - if (TREE_CODE (t) == COMPONENT_REF - && (TREE_CODE (TREE_OPERAND (t, 0)) == MEM_REF - || TREE_CODE (TREE_OPERAND (t, 0)) == INDIRECT_REF - || TREE_CODE (TREE_OPERAND (t, 0)) == ARRAY_REF)) - { - t = TREE_OPERAND (TREE_OPERAND (t, 0), 0); - indir_component_ref_p = true; - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - - if (TREE_CODE (t) == COMPONENT_REF - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) - { - if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "bit-field %qE in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE does not have a mappable type in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (TYPE_ATOMIC (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<_Atomic%> %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - while (TREE_CODE (t) == COMPONENT_REF) - { - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) - == UNION_TYPE) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is a member of a union", t); - remove = true; - break; - } - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == MEM_REF) - { - if (maybe_ne (mem_ref_offset (t), 0)) - error_at (OMP_CLAUSE_LOCATION (c), - "cannot dereference %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - else - t = TREE_OPERAND (t, 0); - } - while (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - } - if (remove) - break; - if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) - { - if (bitmap_bit_p (&map_field_head, DECL_UID (t)) - || (ort != C_ORT_ACC - && bitmap_bit_p (&map_head, DECL_UID (t)))) - break; - } - } - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (VAR_P (t) && DECL_THREAD_LOCAL_P (t)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD is threadprivate variable in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP - || (OMP_CLAUSE_MAP_KIND (c) - != GOMP_MAP_FIRSTPRIVATE_POINTER)) - && !indir_component_ref_p - && !c_mark_addressable (t)) - remove = true; - else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER - || (OMP_CLAUSE_MAP_KIND (c) - == GOMP_MAP_FIRSTPRIVATE_POINTER) - || (OMP_CLAUSE_MAP_KIND (c) - == GOMP_MAP_FORCE_DEVICEPTR))) - && t == OMP_CLAUSE_DECL (c) - && !lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD does not have a mappable type in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (TREE_TYPE (t) == error_mark_node) - remove = true; - else if (TYPE_ATOMIC (strip_array_types (TREE_TYPE (t)))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<_Atomic%> %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_IMPLICIT (c) - && (bitmap_bit_p (&map_head, DECL_UID (t)) - || bitmap_bit_p (&map_field_head, DECL_UID (t)) - || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))) - remove = true; - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) - { - if (bitmap_bit_p (&generic_head, DECL_UID (t)) - || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) - || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in data clauses", t); - remove = true; - } - else if (bitmap_bit_p (&map_head, DECL_UID (t)) - && !bitmap_bit_p (&map_field_head, DECL_UID (t))) - { - if (ort == C_ORT_ACC) - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in data clauses", t); - else - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears both in data and map clauses", t); - remove = true; - } - else - bitmap_set_bit (&map_firstprivate_head, DECL_UID (t)); - } - else if (bitmap_bit_p (&map_head, DECL_UID (t)) - && !bitmap_bit_p (&map_field_head, DECL_UID (t))) - { - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in motion clauses", t); - else if (ort == C_ORT_ACC) - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in data clauses", t); - else - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in map clauses", t); - remove = true; - } - else if (ort == C_ORT_ACC - && bitmap_bit_p (&generic_head, DECL_UID (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in data clauses", t); - remove = true; - } - else if (bitmap_bit_p (&firstprivate_head, DECL_UID (t))) - { - if (ort == C_ORT_ACC) - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears more than once in data clauses", t); - else - error_at (OMP_CLAUSE_LOCATION (c), - "%qD appears both in data and map clauses", t); - remove = true; - } - else - { - bitmap_set_bit (&map_head, DECL_UID (t)); - if (t != OMP_CLAUSE_DECL (c) - && TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPONENT_REF) - bitmap_set_bit (&map_field_head, DECL_UID (t)); - } - break; - - case OMP_CLAUSE_TO_DECLARE: - case OMP_CLAUSE_LINK: - t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == FUNCTION_DECL - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) - ; - else if (!VAR_P (t)) - { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is neither a variable nor a function name in " - "clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - else - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (DECL_THREAD_LOCAL_P (t)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD is threadprivate variable in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD does not have a mappable type in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - if (remove) - break; - if (bitmap_bit_p (&generic_head, DECL_UID (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE appears more than once on the same " - "% directive", t); - remove = true; - } - else - bitmap_set_bit (&generic_head, DECL_UID (t)); - break; - - case OMP_CLAUSE_UNIFORM: - t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) != PARM_DECL) - { - if (DECL_P (t)) - error_at (OMP_CLAUSE_LOCATION (c), - "%qD is not an argument in % clause", t); - else - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not an argument in % clause", t); - remove = true; - break; - } - /* map_head bitmap is used as uniform_head if declare_simd. */ - bitmap_set_bit (&map_head, DECL_UID (t)); - goto check_dup_generic; - - case OMP_CLAUSE_IS_DEVICE_PTR: - case OMP_CLAUSE_USE_DEVICE_PTR: - t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) - { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR - && ort != C_ORT_ACC) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qs variable is not a pointer", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qs variable is neither a pointer nor an array", - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - } - goto check_dup_generic; - - case OMP_CLAUSE_USE_DEVICE_ADDR: - t = OMP_CLAUSE_DECL (c); - if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) - c_mark_addressable (t); - goto check_dup_generic; - - case OMP_CLAUSE_NOWAIT: - if (copyprivate_seen) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% clause must not be used together " - "with %"); - remove = true; - break; - } - nowait_clause = pc; - pc = &OMP_CLAUSE_CHAIN (c); - continue; - - case OMP_CLAUSE_ORDER: - if (ordered_clause) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% clause must not be used together " - "with %"); - remove = true; - break; - } - else if (order_clause) - { - /* Silently remove duplicates. */ - remove = true; - break; - } - order_clause = pc; - pc = &OMP_CLAUSE_CHAIN (c); - continue; - - case OMP_CLAUSE_DETACH: - t = OMP_CLAUSE_DECL (c); - if (detach_seen) - { - error_at (OMP_CLAUSE_LOCATION (c), - "too many %qs clauses on a task construct", - "detach"); - remove = true; - break; - } - detach_seen = pc; - pc = &OMP_CLAUSE_CHAIN (c); - c_mark_addressable (t); - continue; - - case OMP_CLAUSE_IF: - case OMP_CLAUSE_NUM_THREADS: - case OMP_CLAUSE_NUM_TEAMS: - case OMP_CLAUSE_THREAD_LIMIT: - case OMP_CLAUSE_DEFAULT: - case OMP_CLAUSE_UNTIED: - case OMP_CLAUSE_COLLAPSE: - case OMP_CLAUSE_FINAL: - case OMP_CLAUSE_DEVICE: - case OMP_CLAUSE_DIST_SCHEDULE: - case OMP_CLAUSE_PARALLEL: - case OMP_CLAUSE_FOR: - case OMP_CLAUSE_SECTIONS: - case OMP_CLAUSE_TASKGROUP: - case OMP_CLAUSE_PROC_BIND: - case OMP_CLAUSE_DEVICE_TYPE: - case OMP_CLAUSE_PRIORITY: - case OMP_CLAUSE_GRAINSIZE: - case OMP_CLAUSE_NUM_TASKS: - case OMP_CLAUSE_THREADS: - case OMP_CLAUSE_SIMD: - case OMP_CLAUSE_HINT: - case OMP_CLAUSE_FILTER: - case OMP_CLAUSE_DEFAULTMAP: - case OMP_CLAUSE_BIND: - case OMP_CLAUSE_NUM_GANGS: - case OMP_CLAUSE_NUM_WORKERS: - case OMP_CLAUSE_VECTOR_LENGTH: - case OMP_CLAUSE_ASYNC: - case OMP_CLAUSE_WAIT: - case OMP_CLAUSE_AUTO: - case OMP_CLAUSE_INDEPENDENT: - case OMP_CLAUSE_SEQ: - case OMP_CLAUSE_GANG: - case OMP_CLAUSE_WORKER: - case OMP_CLAUSE_VECTOR: - case OMP_CLAUSE_TILE: - case OMP_CLAUSE_IF_PRESENT: - case OMP_CLAUSE_FINALIZE: - case OMP_CLAUSE_NOHOST: - pc = &OMP_CLAUSE_CHAIN (c); - continue; - - case OMP_CLAUSE_MERGEABLE: - mergeable_seen = true; - pc = &OMP_CLAUSE_CHAIN (c); - continue; - - case OMP_CLAUSE_NOGROUP: - nogroup_seen = pc; - pc = &OMP_CLAUSE_CHAIN (c); - continue; - - case OMP_CLAUSE_SCHEDULE: - schedule_clause = c; - pc = &OMP_CLAUSE_CHAIN (c); - continue; - - case OMP_CLAUSE_ORDERED: - ordered_clause = c; - if (order_clause) - { - error_at (OMP_CLAUSE_LOCATION (*order_clause), - "% clause must not be used together " - "with %"); - *order_clause = OMP_CLAUSE_CHAIN (*order_clause); - order_clause = NULL; - } - pc = &OMP_CLAUSE_CHAIN (c); - continue; - - case OMP_CLAUSE_SAFELEN: - safelen = c; - pc = &OMP_CLAUSE_CHAIN (c); - continue; - case OMP_CLAUSE_SIMDLEN: - simdlen = c; - pc = &OMP_CLAUSE_CHAIN (c); - continue; - - case OMP_CLAUSE_INBRANCH: - case OMP_CLAUSE_NOTINBRANCH: - if (branch_seen) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% clause is incompatible with " - "%"); - remove = true; - break; - } - branch_seen = true; - pc = &OMP_CLAUSE_CHAIN (c); - continue; - - case OMP_CLAUSE_INCLUSIVE: - case OMP_CLAUSE_EXCLUSIVE: - need_complete = true; - need_implicitly_determined = true; - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - break; - - default: - gcc_unreachable (); - } - - if (!remove) - { - t = OMP_CLAUSE_DECL (c); - - if (need_complete) - { - t = require_complete_type (OMP_CLAUSE_LOCATION (c), t); - if (t == error_mark_node) - remove = true; - } - - if (need_implicitly_determined) - { - const char *share_name = NULL; - - if (VAR_P (t) && DECL_THREAD_LOCAL_P (t)) - share_name = "threadprivate"; - else switch (c_omp_predetermined_sharing (t)) - { - case OMP_CLAUSE_DEFAULT_UNSPECIFIED: - break; - case OMP_CLAUSE_DEFAULT_SHARED: - if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) - && c_omp_predefined_variable (t)) - /* The __func__ variable and similar function-local - predefined variables may be listed in a shared or - firstprivate clause. */ - break; - share_name = "shared"; - break; - case OMP_CLAUSE_DEFAULT_PRIVATE: - share_name = "private"; - break; - default: - gcc_unreachable (); - } - if (share_name) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is predetermined %qs for %qs", - t, share_name, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (TREE_READONLY (t) - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SHARED - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FIRSTPRIVATE) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% qualified %qE may appear only in " - "% or % clauses", t); - remove = true; - } - } - } - - if (remove) - *pc = OMP_CLAUSE_CHAIN (c); - else - pc = &OMP_CLAUSE_CHAIN (c); - } - - if (simdlen - && safelen - && tree_int_cst_lt (OMP_CLAUSE_SAFELEN_EXPR (safelen), - OMP_CLAUSE_SIMDLEN_EXPR (simdlen))) - { - error_at (OMP_CLAUSE_LOCATION (simdlen), - "% clause value is bigger than " - "% clause value"); - OMP_CLAUSE_SIMDLEN_EXPR (simdlen) - = OMP_CLAUSE_SAFELEN_EXPR (safelen); - } - - if (ordered_clause - && schedule_clause - && (OMP_CLAUSE_SCHEDULE_KIND (schedule_clause) - & OMP_CLAUSE_SCHEDULE_NONMONOTONIC)) - { - error_at (OMP_CLAUSE_LOCATION (schedule_clause), - "% schedule modifier specified together " - "with % clause"); - OMP_CLAUSE_SCHEDULE_KIND (schedule_clause) - = (enum omp_clause_schedule_kind) - (OMP_CLAUSE_SCHEDULE_KIND (schedule_clause) - & ~OMP_CLAUSE_SCHEDULE_NONMONOTONIC); - } - - if (reduction_seen < 0 && ordered_clause) - { - error_at (OMP_CLAUSE_LOCATION (ordered_clause), - "%qs clause specified together with % " - "% clause", "ordered"); - reduction_seen = -2; - } - - if (reduction_seen < 0 && schedule_clause) - { - error_at (OMP_CLAUSE_LOCATION (schedule_clause), - "%qs clause specified together with % " - "% clause", "schedule"); - reduction_seen = -2; - } - - if (linear_variable_step_check - || reduction_seen == -2 - || allocate_seen - || target_in_reduction_seen) - for (pc = &clauses, c = clauses; c ; c = *pc) - { - bool remove = false; - if (allocate_seen) - switch (OMP_CLAUSE_CODE (c)) - { - case OMP_CLAUSE_REDUCTION: - case OMP_CLAUSE_IN_REDUCTION: - case OMP_CLAUSE_TASK_REDUCTION: - if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) - { - t = TREE_OPERAND (OMP_CLAUSE_DECL (c), 0); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == ADDR_EXPR - || TREE_CODE (t) == INDIRECT_REF) - t = TREE_OPERAND (t, 0); - if (DECL_P (t)) - bitmap_clear_bit (&aligned_head, DECL_UID (t)); - break; - } - /* FALLTHRU */ - case OMP_CLAUSE_PRIVATE: - case OMP_CLAUSE_FIRSTPRIVATE: - case OMP_CLAUSE_LASTPRIVATE: - case OMP_CLAUSE_LINEAR: - if (DECL_P (OMP_CLAUSE_DECL (c))) - bitmap_clear_bit (&aligned_head, - DECL_UID (OMP_CLAUSE_DECL (c))); - break; - default: - break; - } - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR - && OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c) - && !bitmap_bit_p (&map_head, - DECL_UID (OMP_CLAUSE_LINEAR_STEP (c)))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% clause step is a parameter %qD not " - "specified in % clause", - OMP_CLAUSE_LINEAR_STEP (c)); - remove = true; - } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - && reduction_seen == -2) - OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; - if (target_in_reduction_seen - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) - { - tree t = OMP_CLAUSE_DECL (c); - while (handled_component_p (t) - || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ADDR_EXPR - || TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == NON_LVALUE_EXPR) - t = TREE_OPERAND (t, 0); - if (DECL_P (t) - && bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) - OMP_CLAUSE_MAP_IN_REDUCTION (c) = 1; - } - - if (remove) - *pc = OMP_CLAUSE_CHAIN (c); - else - pc = &OMP_CLAUSE_CHAIN (c); - } - - if (allocate_seen) - for (pc = &clauses, c = clauses; c ; c = *pc) - { - bool remove = false; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ALLOCATE - && !OMP_CLAUSE_ALLOCATE_COMBINED (c) - && bitmap_bit_p (&aligned_head, DECL_UID (OMP_CLAUSE_DECL (c)))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD specified in % clause but not in " - "an explicit privatization clause", OMP_CLAUSE_DECL (c)); - remove = true; - } - if (remove) - *pc = OMP_CLAUSE_CHAIN (c); - else - pc = &OMP_CLAUSE_CHAIN (c); - } - - if (nogroup_seen && reduction_seen) - { - error_at (OMP_CLAUSE_LOCATION (*nogroup_seen), - "% clause must not be used together with " - "% clause"); - *nogroup_seen = OMP_CLAUSE_CHAIN (*nogroup_seen); - } - - if (detach_seen) - { - if (mergeable_seen) - { - error_at (OMP_CLAUSE_LOCATION (*detach_seen), - "% clause must not be used together with " - "% clause"); - *detach_seen = OMP_CLAUSE_CHAIN (*detach_seen); - } - else - { - tree detach_decl = OMP_CLAUSE_DECL (*detach_seen); - - for (pc = &clauses, c = clauses; c ; c = *pc) - { - bool remove = false; - if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) - && OMP_CLAUSE_DECL (c) == detach_decl) - { - error_at (OMP_CLAUSE_LOCATION (c), - "the event handle of a % clause " - "should not be in a data-sharing clause"); - remove = true; - } - if (remove) - *pc = OMP_CLAUSE_CHAIN (c); - else - pc = &OMP_CLAUSE_CHAIN (c); - } - } - } - - bitmap_obstack_release (NULL); - return clauses; -} - -/* Return code to initialize DST with a copy constructor from SRC. - C doesn't have copy constructors nor assignment operators, only for - _Atomic vars we need to perform __atomic_load from src into a temporary - followed by __atomic_store of the temporary to dst. */ - -tree -c_omp_clause_copy_ctor (tree clause, tree dst, tree src) -{ - if (!really_atomic_lvalue (dst) && !really_atomic_lvalue (src)) - return build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src); - - location_t loc = OMP_CLAUSE_LOCATION (clause); - tree type = TREE_TYPE (dst); - tree nonatomic_type = build_qualified_type (type, TYPE_UNQUALIFIED); - tree tmp = create_tmp_var (nonatomic_type); - tree tmp_addr = build_fold_addr_expr (tmp); - TREE_ADDRESSABLE (tmp) = 1; - suppress_warning (tmp); - tree src_addr = build_fold_addr_expr (src); - tree dst_addr = build_fold_addr_expr (dst); - tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); - vec *params; - /* Expansion of a generic atomic load may require an addition - element, so allocate enough to prevent a resize. */ - vec_alloc (params, 4); - - /* Build __atomic_load (&src, &tmp, SEQ_CST); */ - tree fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD); - params->quick_push (src_addr); - params->quick_push (tmp_addr); - params->quick_push (seq_cst); - tree load = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); - - vec_alloc (params, 4); - - /* Build __atomic_store (&dst, &tmp, SEQ_CST); */ - fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_STORE); - params->quick_push (dst_addr); - params->quick_push (tmp_addr); - params->quick_push (seq_cst); - tree store = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); - return build2 (COMPOUND_EXPR, void_type_node, load, store); -} - -/* Create a transaction node. */ - -tree -c_finish_transaction (location_t loc, tree block, int flags) -{ - tree stmt = build_stmt (loc, TRANSACTION_EXPR, block); - if (flags & TM_STMT_ATTR_OUTER) - TRANSACTION_EXPR_OUTER (stmt) = 1; - if (flags & TM_STMT_ATTR_RELAXED) - TRANSACTION_EXPR_RELAXED (stmt) = 1; - return add_stmt (stmt); -} - -/* Make a variant type in the proper way for C/C++, propagating qualifiers - down to the element type of an array. If ORIG_QUAL_TYPE is not - NULL, then it should be used as the qualified type - ORIG_QUAL_INDIRECT levels down in array type derivation (to - preserve information about the typedef name from which an array - type was derived). */ - -tree -c_build_qualified_type (tree type, int type_quals, tree orig_qual_type, - size_t orig_qual_indirect) -{ - if (type == error_mark_node) - return type; - - if (TREE_CODE (type) == ARRAY_TYPE) - { - tree t; - tree element_type = c_build_qualified_type (TREE_TYPE (type), - type_quals, orig_qual_type, - orig_qual_indirect - 1); - - /* See if we already have an identically qualified type. */ - if (orig_qual_type && orig_qual_indirect == 0) - t = orig_qual_type; - else - for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) - { - if (TYPE_QUALS (strip_array_types (t)) == type_quals - && TYPE_NAME (t) == TYPE_NAME (type) - && TYPE_CONTEXT (t) == TYPE_CONTEXT (type) - && attribute_list_equal (TYPE_ATTRIBUTES (t), - TYPE_ATTRIBUTES (type))) - break; - } - if (!t) - { - tree domain = TYPE_DOMAIN (type); - - t = build_variant_type_copy (type); - TREE_TYPE (t) = element_type; - - if (TYPE_STRUCTURAL_EQUALITY_P (element_type) - || (domain && TYPE_STRUCTURAL_EQUALITY_P (domain))) - SET_TYPE_STRUCTURAL_EQUALITY (t); - else if (TYPE_CANONICAL (element_type) != element_type - || (domain && TYPE_CANONICAL (domain) != domain)) - { - tree unqualified_canon - = build_array_type (TYPE_CANONICAL (element_type), - domain? TYPE_CANONICAL (domain) - : NULL_TREE); - if (TYPE_REVERSE_STORAGE_ORDER (type)) - { - unqualified_canon - = build_distinct_type_copy (unqualified_canon); - TYPE_REVERSE_STORAGE_ORDER (unqualified_canon) = 1; - } - TYPE_CANONICAL (t) - = c_build_qualified_type (unqualified_canon, type_quals); - } - else - TYPE_CANONICAL (t) = t; - } - return t; - } - - /* A restrict-qualified pointer type must be a pointer to object or - incomplete type. Note that the use of POINTER_TYPE_P also allows - REFERENCE_TYPEs, which is appropriate for C++. */ - if ((type_quals & TYPE_QUAL_RESTRICT) - && (!POINTER_TYPE_P (type) - || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))) - { - error ("invalid use of %"); - type_quals &= ~TYPE_QUAL_RESTRICT; - } - - tree var_type = (orig_qual_type && orig_qual_indirect == 0 - ? orig_qual_type - : build_qualified_type (type, type_quals)); - /* A variant type does not inherit the list of incomplete vars from the - type main variant. */ - if ((RECORD_OR_UNION_TYPE_P (var_type) - || TREE_CODE (var_type) == ENUMERAL_TYPE) - && TYPE_MAIN_VARIANT (var_type) != var_type) - C_TYPE_INCOMPLETE_VARS (var_type) = 0; - return var_type; -} - -/* Build a VA_ARG_EXPR for the C parser. */ - -tree -c_build_va_arg (location_t loc1, tree expr, location_t loc2, tree type) -{ - if (error_operand_p (type)) - return error_mark_node; - /* VA_ARG_EXPR cannot be used for a scalar va_list with reverse storage - order because it takes the address of the expression. */ - else if (handled_component_p (expr) - && reverse_storage_order_for_component_p (expr)) - { - error_at (loc1, "cannot use % with reverse storage order"); - return error_mark_node; - } - else if (!COMPLETE_TYPE_P (type)) - { - error_at (loc2, "second argument to % is of incomplete " - "type %qT", type); - return error_mark_node; - } - else if (warn_cxx_compat && TREE_CODE (type) == ENUMERAL_TYPE) - warning_at (loc2, OPT_Wc___compat, - "C++ requires promoted type, not enum type, in %"); - return build_va_arg (loc2, expr, type); -} - -/* Return truthvalue of whether T1 is the same tree structure as T2. - Return 1 if they are the same. Return false if they are different. */ - -bool -c_tree_equal (tree t1, tree t2) -{ - enum tree_code code1, code2; - - if (t1 == t2) - return true; - if (!t1 || !t2) - return false; - - for (code1 = TREE_CODE (t1); - CONVERT_EXPR_CODE_P (code1) - || code1 == NON_LVALUE_EXPR; - code1 = TREE_CODE (t1)) - t1 = TREE_OPERAND (t1, 0); - for (code2 = TREE_CODE (t2); - CONVERT_EXPR_CODE_P (code2) - || code2 == NON_LVALUE_EXPR; - code2 = TREE_CODE (t2)) - t2 = TREE_OPERAND (t2, 0); - - /* They might have become equal now. */ - if (t1 == t2) - return true; - - if (code1 != code2) - return false; - - switch (code1) - { - case INTEGER_CST: - return wi::to_wide (t1) == wi::to_wide (t2); - - case REAL_CST: - return real_equal (&TREE_REAL_CST (t1), &TREE_REAL_CST (t2)); - - case STRING_CST: - return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2) - && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2), - TREE_STRING_LENGTH (t1)); - - case FIXED_CST: - return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), - TREE_FIXED_CST (t2)); - - case COMPLEX_CST: - return c_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2)) - && c_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2)); - - case VECTOR_CST: - return operand_equal_p (t1, t2, OEP_ONLY_CONST); - - case CONSTRUCTOR: - /* We need to do this when determining whether or not two - non-type pointer to member function template arguments - are the same. */ - if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2)) - || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2)) - return false; - { - tree field, value; - unsigned int i; - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value) - { - constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i); - if (!c_tree_equal (field, elt2->index) - || !c_tree_equal (value, elt2->value)) - return false; - } - } - return true; - - case TREE_LIST: - if (!c_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))) - return false; - if (!c_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2))) - return false; - return c_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2)); - - case SAVE_EXPR: - return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); - - case CALL_EXPR: - { - tree arg1, arg2; - call_expr_arg_iterator iter1, iter2; - if (!c_tree_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2))) - return false; - for (arg1 = first_call_expr_arg (t1, &iter1), - arg2 = first_call_expr_arg (t2, &iter2); - arg1 && arg2; - arg1 = next_call_expr_arg (&iter1), - arg2 = next_call_expr_arg (&iter2)) - if (!c_tree_equal (arg1, arg2)) - return false; - if (arg1 || arg2) - return false; - return true; - } - - case TARGET_EXPR: - { - tree o1 = TREE_OPERAND (t1, 0); - tree o2 = TREE_OPERAND (t2, 0); - - /* Special case: if either target is an unallocated VAR_DECL, - it means that it's going to be unified with whatever the - TARGET_EXPR is really supposed to initialize, so treat it - as being equivalent to anything. */ - if (VAR_P (o1) && DECL_NAME (o1) == NULL_TREE - && !DECL_RTL_SET_P (o1)) - /*Nop*/; - else if (VAR_P (o2) && DECL_NAME (o2) == NULL_TREE - && !DECL_RTL_SET_P (o2)) - /*Nop*/; - else if (!c_tree_equal (o1, o2)) - return false; - - return c_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)); - } - - case COMPONENT_REF: - if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1)) - return false; - return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); - - case PARM_DECL: - case VAR_DECL: - case CONST_DECL: - case FIELD_DECL: - case FUNCTION_DECL: - case IDENTIFIER_NODE: - case SSA_NAME: - return false; - - case TREE_VEC: - { - unsigned ix; - if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2)) - return false; - for (ix = TREE_VEC_LENGTH (t1); ix--;) - if (!c_tree_equal (TREE_VEC_ELT (t1, ix), - TREE_VEC_ELT (t2, ix))) - return false; - return true; - } - - default: - break; - } - - switch (TREE_CODE_CLASS (code1)) - { - case tcc_unary: - case tcc_binary: - case tcc_comparison: - case tcc_expression: - case tcc_vl_exp: - case tcc_reference: - case tcc_statement: - { - int i, n = TREE_OPERAND_LENGTH (t1); - - switch (code1) - { - case PREINCREMENT_EXPR: - case PREDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - n = 1; - break; - case ARRAY_REF: - n = 2; - break; - default: - break; - } - - if (TREE_CODE_CLASS (code1) == tcc_vl_exp - && n != TREE_OPERAND_LENGTH (t2)) - return false; - - for (i = 0; i < n; ++i) - if (!c_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i))) - return false; - - return true; - } - - case tcc_type: - return comptypes (t1, t2); - default: - gcc_unreachable (); - } -} - -/* Returns true when the function declaration FNDECL is implicit, - introduced as a result of a call to an otherwise undeclared - function, and false otherwise. */ - -bool -c_decl_implicit (const_tree fndecl) -{ - return C_DECL_IMPLICIT (fndecl); -} diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc new file mode 100644 index 0000000..ac6618e --- /dev/null +++ b/gcc/c/c-typeck.cc @@ -0,0 +1,16079 @@ +/* Build expressions with type checking for C compiler. + Copyright (C) 1987-2022 Free Software Foundation, Inc. + +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 +. */ + + +/* This file is part of the C front end. + It contains routines to build C expressions given their operands, + including computing the types of the result, C-specific error checks, + and some optimization. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "memmodel.h" +#include "target.h" +#include "function.h" +#include "bitmap.h" +#include "c-tree.h" +#include "gimple-expr.h" +#include "predict.h" +#include "stor-layout.h" +#include "trans-mem.h" +#include "varasm.h" +#include "stmt.h" +#include "langhooks.h" +#include "c-lang.h" +#include "intl.h" +#include "tree-iterator.h" +#include "gimplify.h" +#include "tree-inline.h" +#include "omp-general.h" +#include "c-family/c-objc.h" +#include "c-family/c-ubsan.h" +#include "gomp-constants.h" +#include "spellcheck-tree.h" +#include "gcc-rich-location.h" +#include "stringpool.h" +#include "attribs.h" +#include "asan.h" + +/* Possible cases of implicit conversions. Used to select diagnostic messages + and control folding initializers in convert_for_assignment. */ +enum impl_conv { + ic_argpass, + ic_assign, + ic_init, + ic_init_const, + ic_return +}; + +/* The level of nesting inside "__alignof__". */ +int in_alignof; + +/* The level of nesting inside "sizeof". */ +int in_sizeof; + +/* The level of nesting inside "typeof". */ +int in_typeof; + +/* True when parsing OpenMP loop expressions. */ +bool c_in_omp_for; + +/* The argument of last parsed sizeof expression, only to be tested + if expr.original_code == SIZEOF_EXPR. */ +tree c_last_sizeof_arg; +location_t c_last_sizeof_loc; + +/* Nonzero if we might need to print a "missing braces around + initializer" message within this initializer. */ +static int found_missing_braces; + +static int require_constant_value; +static int require_constant_elements; + +static bool null_pointer_constant_p (const_tree); +static tree qualify_type (tree, tree); +static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *, + bool *); +static int comp_target_types (location_t, tree, tree); +static int function_types_compatible_p (const_tree, const_tree, bool *, + bool *); +static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *); +static tree lookup_field (tree, tree); +static int convert_arguments (location_t, vec, tree, + vec *, vec *, tree, + tree); +static tree pointer_diff (location_t, tree, tree, tree *); +static tree convert_for_assignment (location_t, location_t, tree, tree, tree, + enum impl_conv, bool, tree, tree, int, + int = 0); +static tree valid_compound_expr_initializer (tree, tree); +static void push_string (const char *); +static void push_member_name (tree); +static int spelling_length (void); +static char *print_spelling (char *); +static void warning_init (location_t, int, const char *); +static tree digest_init (location_t, tree, tree, tree, bool, bool, int); +static void output_init_element (location_t, tree, tree, bool, tree, tree, bool, + bool, struct obstack *); +static void output_pending_init_elements (int, struct obstack *); +static bool set_designator (location_t, bool, struct obstack *); +static void push_range_stack (tree, struct obstack *); +static void add_pending_init (location_t, tree, tree, tree, bool, + struct obstack *); +static void set_nonincremental_init (struct obstack *); +static void set_nonincremental_init_from_string (tree, struct obstack *); +static tree find_init_member (tree, struct obstack *); +static void readonly_warning (tree, enum lvalue_use); +static int lvalue_or_else (location_t, const_tree, enum lvalue_use); +static void record_maybe_used_decl (tree); +static int comptypes_internal (const_tree, const_tree, bool *, bool *); + +/* Return true if EXP is a null pointer constant, false otherwise. */ + +static bool +null_pointer_constant_p (const_tree expr) +{ + /* This should really operate on c_expr structures, but they aren't + yet available everywhere required. */ + tree type = TREE_TYPE (expr); + return (TREE_CODE (expr) == INTEGER_CST + && !TREE_OVERFLOW (expr) + && integer_zerop (expr) + && (INTEGRAL_TYPE_P (type) + || (TREE_CODE (type) == POINTER_TYPE + && VOID_TYPE_P (TREE_TYPE (type)) + && TYPE_QUALS (TREE_TYPE (type)) == TYPE_UNQUALIFIED))); +} + +/* EXPR may appear in an unevaluated part of an integer constant + expression, but not in an evaluated part. Wrap it in a + C_MAYBE_CONST_EXPR, or mark it with TREE_OVERFLOW if it is just an + INTEGER_CST and we cannot create a C_MAYBE_CONST_EXPR. */ + +static tree +note_integer_operands (tree expr) +{ + tree ret; + if (TREE_CODE (expr) == INTEGER_CST && in_late_binary_op) + { + ret = copy_node (expr); + TREE_OVERFLOW (ret) = 1; + } + else + { + ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL_TREE, expr); + C_MAYBE_CONST_EXPR_INT_OPERANDS (ret) = 1; + } + return ret; +} + +/* Having checked whether EXPR may appear in an unevaluated part of an + integer constant expression and found that it may, remove any + C_MAYBE_CONST_EXPR noting this fact and return the resulting + expression. */ + +static inline tree +remove_c_maybe_const_expr (tree expr) +{ + if (TREE_CODE (expr) == C_MAYBE_CONST_EXPR) + return C_MAYBE_CONST_EXPR_EXPR (expr); + else + return expr; +} + + /* This is a cache to hold if two types are compatible or not. */ + +struct tagged_tu_seen_cache { + const struct tagged_tu_seen_cache * next; + const_tree t1; + const_tree t2; + /* The return value of tagged_types_tu_compatible_p if we had seen + these two types already. */ + int val; +}; + +static const struct tagged_tu_seen_cache * tagged_tu_seen_base; +static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *); + +/* Do `exp = require_complete_type (loc, exp);' to make sure exp + does not have an incomplete type. (That includes void types.) + LOC is the location of the use. */ + +tree +require_complete_type (location_t loc, tree value) +{ + tree type = TREE_TYPE (value); + + if (error_operand_p (value)) + return error_mark_node; + + /* First, detect a valid value with a complete type. */ + if (COMPLETE_TYPE_P (type)) + return value; + + c_incomplete_type_error (loc, value, type); + return error_mark_node; +} + +/* Print an error message for invalid use of an incomplete type. + VALUE is the expression that was used (or 0 if that isn't known) + and TYPE is the type that was invalid. LOC is the location for + the error. */ + +void +c_incomplete_type_error (location_t loc, const_tree value, const_tree type) +{ + /* Avoid duplicate error message. */ + if (TREE_CODE (type) == ERROR_MARK) + return; + + if (value != NULL_TREE && (VAR_P (value) || TREE_CODE (value) == PARM_DECL)) + error_at (loc, "%qD has an incomplete type %qT", value, type); + else + { + retry: + /* We must print an error message. Be clever about what it says. */ + + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + case UNION_TYPE: + case ENUMERAL_TYPE: + break; + + case VOID_TYPE: + error_at (loc, "invalid use of void expression"); + return; + + case ARRAY_TYPE: + if (TYPE_DOMAIN (type)) + { + if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL) + { + error_at (loc, "invalid use of flexible array member"); + return; + } + type = TREE_TYPE (type); + goto retry; + } + error_at (loc, "invalid use of array with unspecified bounds"); + return; + + default: + gcc_unreachable (); + } + + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + error_at (loc, "invalid use of undefined type %qT", type); + else + /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */ + error_at (loc, "invalid use of incomplete typedef %qT", type); + } +} + +/* Given a type, apply default promotions wrt unnamed function + arguments and return the new type. */ + +tree +c_type_promotes_to (tree type) +{ + tree ret = NULL_TREE; + + if (TYPE_MAIN_VARIANT (type) == float_type_node) + ret = double_type_node; + else if (c_promoting_integer_type_p (type)) + { + /* Preserve unsignedness if not really getting any wider. */ + if (TYPE_UNSIGNED (type) + && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))) + ret = unsigned_type_node; + else + ret = integer_type_node; + } + + if (ret != NULL_TREE) + return (TYPE_ATOMIC (type) + ? c_build_qualified_type (ret, TYPE_QUAL_ATOMIC) + : ret); + + return type; +} + +/* Return true if between two named address spaces, whether there is a superset + named address space that encompasses both address spaces. If there is a + superset, return which address space is the superset. */ + +static bool +addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common) +{ + if (as1 == as2) + { + *common = as1; + return true; + } + else if (targetm.addr_space.subset_p (as1, as2)) + { + *common = as2; + return true; + } + else if (targetm.addr_space.subset_p (as2, as1)) + { + *common = as1; + return true; + } + else + return false; +} + +/* Return a variant of TYPE which has all the type qualifiers of LIKE + as well as those of TYPE. */ + +static tree +qualify_type (tree type, tree like) +{ + addr_space_t as_type = TYPE_ADDR_SPACE (type); + addr_space_t as_like = TYPE_ADDR_SPACE (like); + addr_space_t as_common; + + /* If the two named address spaces are different, determine the common + superset address space. If there isn't one, raise an error. */ + if (!addr_space_superset (as_type, as_like, &as_common)) + { + as_common = as_type; + error ("%qT and %qT are in disjoint named address spaces", + type, like); + } + + return c_build_qualified_type (type, + TYPE_QUALS_NO_ADDR_SPACE (type) + | TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (like) + | ENCODE_QUAL_ADDR_SPACE (as_common)); +} + +/* Return true iff the given tree T is a variable length array. */ + +bool +c_vla_type_p (const_tree t) +{ + if (TREE_CODE (t) == ARRAY_TYPE + && C_TYPE_VARIABLE_SIZE (t)) + return true; + return false; +} + +/* If NTYPE is a type of a non-variadic function with a prototype + and OTYPE is a type of a function without a prototype and ATTRS + contains attribute format, diagnosess and removes it from ATTRS. + Returns the result of build_type_attribute_variant of NTYPE and + the (possibly) modified ATTRS. */ + +static tree +build_functype_attribute_variant (tree ntype, tree otype, tree attrs) +{ + if (!prototype_p (otype) + && prototype_p (ntype) + && lookup_attribute ("format", attrs)) + { + warning_at (input_location, OPT_Wattributes, + "%qs attribute cannot be applied to a function that " + "does not take variable arguments", "format"); + attrs = remove_attribute ("format", attrs); + } + return build_type_attribute_variant (ntype, attrs); + +} +/* Return the composite type of two compatible types. + + We assume that comptypes has already been done and returned + nonzero; if that isn't so, this may crash. In particular, we + assume that qualifiers match. */ + +tree +composite_type (tree t1, tree t2) +{ + enum tree_code code1; + enum tree_code code2; + tree attributes; + + /* Save time if the two types are the same. */ + + if (t1 == t2) return t1; + + /* If one type is nonsense, use the other. */ + if (t1 == error_mark_node) + return t2; + if (t2 == error_mark_node) + return t1; + + code1 = TREE_CODE (t1); + code2 = TREE_CODE (t2); + + /* Merge the attributes. */ + attributes = targetm.merge_type_attributes (t1, t2); + + /* If one is an enumerated type and the other is the compatible + integer type, the composite type might be either of the two + (DR#013 question 3). For consistency, use the enumerated type as + the composite type. */ + + if (code1 == ENUMERAL_TYPE && code2 == INTEGER_TYPE) + return t1; + if (code2 == ENUMERAL_TYPE && code1 == INTEGER_TYPE) + return t2; + + gcc_assert (code1 == code2); + + switch (code1) + { + case POINTER_TYPE: + /* For two pointers, do this recursively on the target type. */ + { + tree pointed_to_1 = TREE_TYPE (t1); + tree pointed_to_2 = TREE_TYPE (t2); + tree target = composite_type (pointed_to_1, pointed_to_2); + t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false); + t1 = build_type_attribute_variant (t1, attributes); + return qualify_type (t1, t2); + } + + case ARRAY_TYPE: + { + tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2)); + int quals; + tree unqual_elt; + tree d1 = TYPE_DOMAIN (t1); + tree d2 = TYPE_DOMAIN (t2); + bool d1_variable, d2_variable; + bool d1_zero, d2_zero; + bool t1_complete, t2_complete; + + /* We should not have any type quals on arrays at all. */ + gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1) + && !TYPE_QUALS_NO_ADDR_SPACE (t2)); + + t1_complete = COMPLETE_TYPE_P (t1); + t2_complete = COMPLETE_TYPE_P (t2); + + d1_zero = d1 == NULL_TREE || !TYPE_MAX_VALUE (d1); + d2_zero = d2 == NULL_TREE || !TYPE_MAX_VALUE (d2); + + d1_variable = (!d1_zero + && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST)); + d2_variable = (!d2_zero + && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); + d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1)); + d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2)); + + /* Save space: see if the result is identical to one of the args. */ + if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1) + && (d2_variable || d2_zero || !d1_variable)) + return build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2) + && (d1_variable || d1_zero || !d2_variable)) + return build_type_attribute_variant (t2, attributes); + + if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) + return build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) + return build_type_attribute_variant (t2, attributes); + + /* Merge the element types, and have a size if either arg has + one. We may have qualifiers on the element types. To set + up TYPE_MAIN_VARIANT correctly, we need to form the + composite of the unqualified types and add the qualifiers + back at the end. */ + quals = TYPE_QUALS (strip_array_types (elt)); + unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); + t1 = build_array_type (unqual_elt, + TYPE_DOMAIN ((TYPE_DOMAIN (t1) + && (d2_variable + || d2_zero + || !d1_variable)) + ? t1 + : t2)); + /* Ensure a composite type involving a zero-length array type + is a zero-length type not an incomplete type. */ + if (d1_zero && d2_zero + && (t1_complete || t2_complete) + && !COMPLETE_TYPE_P (t1)) + { + TYPE_SIZE (t1) = bitsize_zero_node; + TYPE_SIZE_UNIT (t1) = size_zero_node; + } + t1 = c_build_qualified_type (t1, quals); + return build_type_attribute_variant (t1, attributes); + } + + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + if (attributes != NULL) + { + /* Try harder not to create a new aggregate type. */ + if (attribute_list_equal (TYPE_ATTRIBUTES (t1), attributes)) + return t1; + if (attribute_list_equal (TYPE_ATTRIBUTES (t2), attributes)) + return t2; + } + return build_type_attribute_variant (t1, attributes); + + case FUNCTION_TYPE: + /* Function types: prefer the one that specified arg types. + If both do, merge the arg types. Also merge the return types. */ + { + tree valtype = composite_type (TREE_TYPE (t1), TREE_TYPE (t2)); + tree p1 = TYPE_ARG_TYPES (t1); + tree p2 = TYPE_ARG_TYPES (t2); + int len; + tree newargs, n; + int i; + + /* Save space: see if the result is identical to one of the args. */ + if (valtype == TREE_TYPE (t1) && !TYPE_ARG_TYPES (t2)) + return build_functype_attribute_variant (t1, t2, attributes); + if (valtype == TREE_TYPE (t2) && !TYPE_ARG_TYPES (t1)) + return build_functype_attribute_variant (t2, t1, attributes); + + /* Simple way if one arg fails to specify argument types. */ + if (TYPE_ARG_TYPES (t1) == NULL_TREE) + { + t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2)); + t1 = build_type_attribute_variant (t1, attributes); + return qualify_type (t1, t2); + } + if (TYPE_ARG_TYPES (t2) == NULL_TREE) + { + t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1)); + t1 = build_type_attribute_variant (t1, attributes); + return qualify_type (t1, t2); + } + + /* If both args specify argument types, we must merge the two + lists, argument by argument. */ + + for (len = 0, newargs = p1; + newargs && newargs != void_list_node; + len++, newargs = TREE_CHAIN (newargs)) + ; + + for (i = 0; i < len; i++) + newargs = tree_cons (NULL_TREE, NULL_TREE, newargs); + + n = newargs; + + for (; p1 && p1 != void_list_node; + p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n)) + { + /* A null type means arg type is not specified. + Take whatever the other function type has. */ + if (TREE_VALUE (p1) == NULL_TREE) + { + TREE_VALUE (n) = TREE_VALUE (p2); + goto parm_done; + } + if (TREE_VALUE (p2) == NULL_TREE) + { + TREE_VALUE (n) = TREE_VALUE (p1); + goto parm_done; + } + + /* Given wait (union {union wait *u; int *i} *) + and wait (union wait *), + prefer union wait * as type of parm. */ + if (TREE_CODE (TREE_VALUE (p1)) == UNION_TYPE + && TREE_VALUE (p1) != TREE_VALUE (p2)) + { + tree memb; + tree mv2 = TREE_VALUE (p2); + if (mv2 && mv2 != error_mark_node + && TREE_CODE (mv2) != ARRAY_TYPE) + mv2 = TYPE_MAIN_VARIANT (mv2); + for (memb = TYPE_FIELDS (TREE_VALUE (p1)); + memb; memb = DECL_CHAIN (memb)) + { + tree mv3 = TREE_TYPE (memb); + if (mv3 && mv3 != error_mark_node + && TREE_CODE (mv3) != ARRAY_TYPE) + mv3 = TYPE_MAIN_VARIANT (mv3); + if (comptypes (mv3, mv2)) + { + TREE_VALUE (n) = composite_type (TREE_TYPE (memb), + TREE_VALUE (p2)); + pedwarn (input_location, OPT_Wpedantic, + "function types not truly compatible in ISO C"); + goto parm_done; + } + } + } + if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE + && TREE_VALUE (p2) != TREE_VALUE (p1)) + { + tree memb; + tree mv1 = TREE_VALUE (p1); + if (mv1 && mv1 != error_mark_node + && TREE_CODE (mv1) != ARRAY_TYPE) + mv1 = TYPE_MAIN_VARIANT (mv1); + for (memb = TYPE_FIELDS (TREE_VALUE (p2)); + memb; memb = DECL_CHAIN (memb)) + { + tree mv3 = TREE_TYPE (memb); + if (mv3 && mv3 != error_mark_node + && TREE_CODE (mv3) != ARRAY_TYPE) + mv3 = TYPE_MAIN_VARIANT (mv3); + if (comptypes (mv3, mv1)) + { + TREE_VALUE (n) = composite_type (TREE_TYPE (memb), + TREE_VALUE (p1)); + pedwarn (input_location, OPT_Wpedantic, + "function types not truly compatible in ISO C"); + goto parm_done; + } + } + } + TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2)); + parm_done: ; + } + + t1 = build_function_type (valtype, newargs); + t1 = qualify_type (t1, t2); + } + /* FALLTHRU */ + + default: + return build_type_attribute_variant (t1, attributes); + } + +} + +/* Return the type of a conditional expression between pointers to + possibly differently qualified versions of compatible types. + + We assume that comp_target_types has already been done and returned + nonzero; if that isn't so, this may crash. */ + +static tree +common_pointer_type (tree t1, tree t2) +{ + tree attributes; + tree pointed_to_1, mv1; + tree pointed_to_2, mv2; + tree target; + unsigned target_quals; + addr_space_t as1, as2, as_common; + int quals1, quals2; + + /* Save time if the two types are the same. */ + + if (t1 == t2) return t1; + + /* If one type is nonsense, use the other. */ + if (t1 == error_mark_node) + return t2; + if (t2 == error_mark_node) + return t1; + + gcc_assert (TREE_CODE (t1) == POINTER_TYPE + && TREE_CODE (t2) == POINTER_TYPE); + + /* Merge the attributes. */ + attributes = targetm.merge_type_attributes (t1, t2); + + /* Find the composite type of the target types, and combine the + qualifiers of the two types' targets. Do not lose qualifiers on + array element types by taking the TYPE_MAIN_VARIANT. */ + mv1 = pointed_to_1 = TREE_TYPE (t1); + mv2 = pointed_to_2 = TREE_TYPE (t2); + if (TREE_CODE (mv1) != ARRAY_TYPE) + mv1 = TYPE_MAIN_VARIANT (pointed_to_1); + if (TREE_CODE (mv2) != ARRAY_TYPE) + mv2 = TYPE_MAIN_VARIANT (pointed_to_2); + target = composite_type (mv1, mv2); + + /* Strip array types to get correct qualifier for pointers to arrays */ + quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1)); + quals2 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_2)); + + /* For function types do not merge const qualifiers, but drop them + if used inconsistently. The middle-end uses these to mark const + and noreturn functions. */ + if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE) + target_quals = (quals1 & quals2); + else + target_quals = (quals1 | quals2); + + /* If the two named address spaces are different, determine the common + superset address space. This is guaranteed to exist due to the + assumption that comp_target_type returned non-zero. */ + as1 = TYPE_ADDR_SPACE (pointed_to_1); + as2 = TYPE_ADDR_SPACE (pointed_to_2); + if (!addr_space_superset (as1, as2, &as_common)) + gcc_unreachable (); + + target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common); + + t1 = build_pointer_type (c_build_qualified_type (target, target_quals)); + return build_type_attribute_variant (t1, attributes); +} + +/* Return the common type for two arithmetic types under the usual + arithmetic conversions. The default conversions have already been + applied, and enumerated types converted to their compatible integer + types. The resulting type is unqualified and has no attributes. + + This is the type for the result of most arithmetic operations + if the operands have the given two types. */ + +static tree +c_common_type (tree t1, tree t2) +{ + enum tree_code code1; + enum tree_code code2; + + /* If one type is nonsense, use the other. */ + if (t1 == error_mark_node) + return t2; + if (t2 == error_mark_node) + return t1; + + if (TYPE_QUALS (t1) != TYPE_UNQUALIFIED) + t1 = TYPE_MAIN_VARIANT (t1); + + if (TYPE_QUALS (t2) != TYPE_UNQUALIFIED) + t2 = TYPE_MAIN_VARIANT (t2); + + if (TYPE_ATTRIBUTES (t1) != NULL_TREE) + { + tree attrs = affects_type_identity_attributes (TYPE_ATTRIBUTES (t1)); + t1 = build_type_attribute_variant (t1, attrs); + } + + if (TYPE_ATTRIBUTES (t2) != NULL_TREE) + { + tree attrs = affects_type_identity_attributes (TYPE_ATTRIBUTES (t2)); + t2 = build_type_attribute_variant (t2, attrs); + } + + /* Save time if the two types are the same. */ + + if (t1 == t2) return t1; + + code1 = TREE_CODE (t1); + code2 = TREE_CODE (t2); + + gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE + || code1 == FIXED_POINT_TYPE || code1 == REAL_TYPE + || code1 == INTEGER_TYPE); + gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE + || code2 == FIXED_POINT_TYPE || code2 == REAL_TYPE + || code2 == INTEGER_TYPE); + + /* When one operand is a decimal float type, the other operand cannot be + a generic float type or a complex type. We also disallow vector types + here. */ + if ((DECIMAL_FLOAT_TYPE_P (t1) || DECIMAL_FLOAT_TYPE_P (t2)) + && !(DECIMAL_FLOAT_TYPE_P (t1) && DECIMAL_FLOAT_TYPE_P (t2))) + { + if (code1 == VECTOR_TYPE || code2 == VECTOR_TYPE) + { + error ("cannot mix operands of decimal floating and vector types"); + return error_mark_node; + } + if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE) + { + error ("cannot mix operands of decimal floating and complex types"); + return error_mark_node; + } + if (code1 == REAL_TYPE && code2 == REAL_TYPE) + { + error ("cannot mix operands of decimal floating " + "and other floating types"); + return error_mark_node; + } + } + + /* If one type is a vector type, return that type. (How the usual + arithmetic conversions apply to the vector types extension is not + precisely specified.) */ + if (code1 == VECTOR_TYPE) + return t1; + + if (code2 == VECTOR_TYPE) + return t2; + + /* If one type is complex, form the common type of the non-complex + components, then make that complex. Use T1 or T2 if it is the + required type. */ + if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE) + { + tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1; + tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2; + tree subtype = c_common_type (subtype1, subtype2); + + if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype) + return t1; + else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype) + return t2; + else + return build_complex_type (subtype); + } + + /* If only one is real, use it as the result. */ + + if (code1 == REAL_TYPE && code2 != REAL_TYPE) + return t1; + + if (code2 == REAL_TYPE && code1 != REAL_TYPE) + return t2; + + /* If both are real and either are decimal floating point types, use + the decimal floating point type with the greater precision. */ + + if (code1 == REAL_TYPE && code2 == REAL_TYPE) + { + if (TYPE_MAIN_VARIANT (t1) == dfloat128_type_node + || TYPE_MAIN_VARIANT (t2) == dfloat128_type_node) + return dfloat128_type_node; + else if (TYPE_MAIN_VARIANT (t1) == dfloat64_type_node + || TYPE_MAIN_VARIANT (t2) == dfloat64_type_node) + return dfloat64_type_node; + else if (TYPE_MAIN_VARIANT (t1) == dfloat32_type_node + || TYPE_MAIN_VARIANT (t2) == dfloat32_type_node) + return dfloat32_type_node; + } + + /* Deal with fixed-point types. */ + if (code1 == FIXED_POINT_TYPE || code2 == FIXED_POINT_TYPE) + { + unsigned int unsignedp = 0, satp = 0; + scalar_mode m1, m2; + unsigned int fbit1, ibit1, fbit2, ibit2, max_fbit, max_ibit; + + m1 = SCALAR_TYPE_MODE (t1); + m2 = SCALAR_TYPE_MODE (t2); + + /* If one input type is saturating, the result type is saturating. */ + if (TYPE_SATURATING (t1) || TYPE_SATURATING (t2)) + satp = 1; + + /* If both fixed-point types are unsigned, the result type is unsigned. + When mixing fixed-point and integer types, follow the sign of the + fixed-point type. + Otherwise, the result type is signed. */ + if ((TYPE_UNSIGNED (t1) && TYPE_UNSIGNED (t2) + && code1 == FIXED_POINT_TYPE && code2 == FIXED_POINT_TYPE) + || (code1 == FIXED_POINT_TYPE && code2 != FIXED_POINT_TYPE + && TYPE_UNSIGNED (t1)) + || (code1 != FIXED_POINT_TYPE && code2 == FIXED_POINT_TYPE + && TYPE_UNSIGNED (t2))) + unsignedp = 1; + + /* The result type is signed. */ + if (unsignedp == 0) + { + /* If the input type is unsigned, we need to convert to the + signed type. */ + if (code1 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t1)) + { + enum mode_class mclass = (enum mode_class) 0; + if (GET_MODE_CLASS (m1) == MODE_UFRACT) + mclass = MODE_FRACT; + else if (GET_MODE_CLASS (m1) == MODE_UACCUM) + mclass = MODE_ACCUM; + else + gcc_unreachable (); + m1 = as_a + (mode_for_size (GET_MODE_PRECISION (m1), mclass, 0)); + } + if (code2 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t2)) + { + enum mode_class mclass = (enum mode_class) 0; + if (GET_MODE_CLASS (m2) == MODE_UFRACT) + mclass = MODE_FRACT; + else if (GET_MODE_CLASS (m2) == MODE_UACCUM) + mclass = MODE_ACCUM; + else + gcc_unreachable (); + m2 = as_a + (mode_for_size (GET_MODE_PRECISION (m2), mclass, 0)); + } + } + + if (code1 == FIXED_POINT_TYPE) + { + fbit1 = GET_MODE_FBIT (m1); + ibit1 = GET_MODE_IBIT (m1); + } + else + { + fbit1 = 0; + /* Signed integers need to subtract one sign bit. */ + ibit1 = TYPE_PRECISION (t1) - (!TYPE_UNSIGNED (t1)); + } + + if (code2 == FIXED_POINT_TYPE) + { + fbit2 = GET_MODE_FBIT (m2); + ibit2 = GET_MODE_IBIT (m2); + } + else + { + fbit2 = 0; + /* Signed integers need to subtract one sign bit. */ + ibit2 = TYPE_PRECISION (t2) - (!TYPE_UNSIGNED (t2)); + } + + max_ibit = ibit1 >= ibit2 ? ibit1 : ibit2; + max_fbit = fbit1 >= fbit2 ? fbit1 : fbit2; + return c_common_fixed_point_type_for_size (max_ibit, max_fbit, unsignedp, + satp); + } + + /* Both real or both integers; use the one with greater precision. */ + + if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) + return t1; + else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1)) + return t2; + + /* Same precision. Prefer long longs to longs to ints when the + same precision, following the C99 rules on integer type rank + (which are equivalent to the C90 rules for C90 types). */ + + if (TYPE_MAIN_VARIANT (t1) == long_long_unsigned_type_node + || TYPE_MAIN_VARIANT (t2) == long_long_unsigned_type_node) + return long_long_unsigned_type_node; + + if (TYPE_MAIN_VARIANT (t1) == long_long_integer_type_node + || TYPE_MAIN_VARIANT (t2) == long_long_integer_type_node) + { + if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2)) + return long_long_unsigned_type_node; + else + return long_long_integer_type_node; + } + + if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node + || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node) + return long_unsigned_type_node; + + if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node + || TYPE_MAIN_VARIANT (t2) == long_integer_type_node) + { + /* But preserve unsignedness from the other type, + since long cannot hold all the values of an unsigned int. */ + if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2)) + return long_unsigned_type_node; + else + return long_integer_type_node; + } + + /* For floating types of the same TYPE_PRECISION (which we here + assume means either the same set of values, or sets of values + neither a subset of the other, with behavior being undefined in + the latter case), follow the rules from TS 18661-3: prefer + interchange types _FloatN, then standard types long double, + double, float, then extended types _FloatNx. For extended types, + check them starting with _Float128x as that seems most consistent + in spirit with preferring long double to double; for interchange + types, also check in that order for consistency although it's not + possible for more than one of them to have the same + precision. */ + tree mv1 = TYPE_MAIN_VARIANT (t1); + tree mv2 = TYPE_MAIN_VARIANT (t2); + + for (int i = NUM_FLOATN_TYPES - 1; i >= 0; i--) + if (mv1 == FLOATN_TYPE_NODE (i) || mv2 == FLOATN_TYPE_NODE (i)) + return FLOATN_TYPE_NODE (i); + + /* Likewise, prefer long double to double even if same size. */ + if (mv1 == long_double_type_node || mv2 == long_double_type_node) + return long_double_type_node; + + /* Likewise, prefer double to float even if same size. + We got a couple of embedded targets with 32 bit doubles, and the + pdp11 might have 64 bit floats. */ + if (mv1 == double_type_node || mv2 == double_type_node) + return double_type_node; + + if (mv1 == float_type_node || mv2 == float_type_node) + return float_type_node; + + for (int i = NUM_FLOATNX_TYPES - 1; i >= 0; i--) + if (mv1 == FLOATNX_TYPE_NODE (i) || mv2 == FLOATNX_TYPE_NODE (i)) + return FLOATNX_TYPE_NODE (i); + + /* Otherwise prefer the unsigned one. */ + + if (TYPE_UNSIGNED (t1)) + return t1; + else + return t2; +} + +/* Wrapper around c_common_type that is used by c-common.c and other + front end optimizations that remove promotions. ENUMERAL_TYPEs + are allowed here and are converted to their compatible integer types. + BOOLEAN_TYPEs are allowed here and return either boolean_type_node or + preferably a non-Boolean type as the common type. */ +tree +common_type (tree t1, tree t2) +{ + if (TREE_CODE (t1) == ENUMERAL_TYPE) + t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1); + if (TREE_CODE (t2) == ENUMERAL_TYPE) + t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1); + + /* If both types are BOOLEAN_TYPE, then return boolean_type_node. */ + if (TREE_CODE (t1) == BOOLEAN_TYPE + && TREE_CODE (t2) == BOOLEAN_TYPE) + return boolean_type_node; + + /* If either type is BOOLEAN_TYPE, then return the other. */ + if (TREE_CODE (t1) == BOOLEAN_TYPE) + return t2; + if (TREE_CODE (t2) == BOOLEAN_TYPE) + return t1; + + return c_common_type (t1, t2); +} + +/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment + or various other operations. Return 2 if they are compatible + but a warning may be needed if you use them together. */ + +int +comptypes (tree type1, tree type2) +{ + const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; + int val; + + val = comptypes_internal (type1, type2, NULL, NULL); + free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); + + return val; +} + +/* Like comptypes, but if it returns non-zero because enum and int are + compatible, it sets *ENUM_AND_INT_P to true. */ + +static int +comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) +{ + const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; + int val; + + val = comptypes_internal (type1, type2, enum_and_int_p, NULL); + free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); + + return val; +} + +/* Like comptypes, but if it returns nonzero for different types, it + sets *DIFFERENT_TYPES_P to true. */ + +int +comptypes_check_different_types (tree type1, tree type2, + bool *different_types_p) +{ + const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; + int val; + + val = comptypes_internal (type1, type2, NULL, different_types_p); + free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); + + return val; +} + +/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment + or various other operations. Return 2 if they are compatible + but a warning may be needed if you use them together. If + ENUM_AND_INT_P is not NULL, and one type is an enum and the other a + compatible integer type, then this sets *ENUM_AND_INT_P to true; + *ENUM_AND_INT_P is never set to false. If DIFFERENT_TYPES_P is not + NULL, and the types are compatible but different enough not to be + permitted in C11 typedef redeclarations, then this sets + *DIFFERENT_TYPES_P to true; *DIFFERENT_TYPES_P is never set to + false, but may or may not be set if the types are incompatible. + This differs from comptypes, in that we don't free the seen + types. */ + +static int +comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, + bool *different_types_p) +{ + const_tree t1 = type1; + const_tree t2 = type2; + int attrval, val; + + /* Suppress errors caused by previously reported errors. */ + + if (t1 == t2 || !t1 || !t2 + || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK) + return 1; + + /* Enumerated types are compatible with integer types, but this is + not transitive: two enumerated types in the same translation unit + are compatible with each other only if they are the same type. */ + + if (TREE_CODE (t1) == ENUMERAL_TYPE + && COMPLETE_TYPE_P (t1) + && TREE_CODE (t2) != ENUMERAL_TYPE) + { + t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1)); + if (TREE_CODE (t2) != VOID_TYPE) + { + if (enum_and_int_p != NULL) + *enum_and_int_p = true; + if (different_types_p != NULL) + *different_types_p = true; + } + } + else if (TREE_CODE (t2) == ENUMERAL_TYPE + && COMPLETE_TYPE_P (t2) + && TREE_CODE (t1) != ENUMERAL_TYPE) + { + t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2)); + if (TREE_CODE (t1) != VOID_TYPE) + { + if (enum_and_int_p != NULL) + *enum_and_int_p = true; + if (different_types_p != NULL) + *different_types_p = true; + } + } + + if (t1 == t2) + return 1; + + /* Different classes of types can't be compatible. */ + + if (TREE_CODE (t1) != TREE_CODE (t2)) + return 0; + + /* Qualifiers must match. C99 6.7.3p9 */ + + if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) + return 0; + + /* Allow for two different type nodes which have essentially the same + definition. Note that we already checked for equality of the type + qualifiers (just above). */ + + if (TREE_CODE (t1) != ARRAY_TYPE + && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) + return 1; + + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + if (!(attrval = comp_type_attributes (t1, t2))) + return 0; + + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + val = 0; + + switch (TREE_CODE (t1)) + { + case INTEGER_TYPE: + case FIXED_POINT_TYPE: + case REAL_TYPE: + /* With these nodes, we can't determine type equivalence by + looking at what is stored in the nodes themselves, because + two nodes might have different TYPE_MAIN_VARIANTs but still + represent the same type. For example, wchar_t and int could + have the same properties (TYPE_PRECISION, TYPE_MIN_VALUE, + TYPE_MAX_VALUE, etc.), but have different TYPE_MAIN_VARIANTs + and are distinct types. On the other hand, int and the + following typedef + + typedef int INT __attribute((may_alias)); + + have identical properties, different TYPE_MAIN_VARIANTs, but + represent the same type. The canonical type system keeps + track of equivalence in this case, so we fall back on it. */ + return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2); + + case POINTER_TYPE: + /* Do not remove mode information. */ + if (TYPE_MODE (t1) != TYPE_MODE (t2)) + break; + val = (TREE_TYPE (t1) == TREE_TYPE (t2) + ? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), + enum_and_int_p, different_types_p)); + break; + + case FUNCTION_TYPE: + val = function_types_compatible_p (t1, t2, enum_and_int_p, + different_types_p); + break; + + case ARRAY_TYPE: + { + tree d1 = TYPE_DOMAIN (t1); + tree d2 = TYPE_DOMAIN (t2); + bool d1_variable, d2_variable; + bool d1_zero, d2_zero; + val = 1; + + /* Target types must match incl. qualifiers. */ + if (TREE_TYPE (t1) != TREE_TYPE (t2) + && (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), + enum_and_int_p, + different_types_p)) == 0) + return 0; + + if (different_types_p != NULL + && (d1 == NULL_TREE) != (d2 == NULL_TREE)) + *different_types_p = true; + /* Sizes must match unless one is missing or variable. */ + if (d1 == NULL_TREE || d2 == NULL_TREE || d1 == d2) + break; + + d1_zero = !TYPE_MAX_VALUE (d1); + d2_zero = !TYPE_MAX_VALUE (d2); + + d1_variable = (!d1_zero + && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST)); + d2_variable = (!d2_zero + && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); + d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1)); + d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2)); + + if (different_types_p != NULL + && d1_variable != d2_variable) + *different_types_p = true; + if (d1_variable || d2_variable) + break; + if (d1_zero && d2_zero) + break; + if (d1_zero || d2_zero + || !tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2)) + || !tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2))) + val = 0; + + break; + } + + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + if (val != 1 && !same_translation_unit_p (t1, t2)) + { + tree a1 = TYPE_ATTRIBUTES (t1); + tree a2 = TYPE_ATTRIBUTES (t2); + + if (! attribute_list_contained (a1, a2) + && ! attribute_list_contained (a2, a1)) + break; + + if (attrval != 2) + return tagged_types_tu_compatible_p (t1, t2, enum_and_int_p, + different_types_p); + val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p, + different_types_p); + } + break; + + case VECTOR_TYPE: + val = (known_eq (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2)) + && comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), + enum_and_int_p, different_types_p)); + break; + + default: + break; + } + return attrval == 2 && val == 1 ? 2 : val; +} + +/* Return 1 if TTL and TTR are pointers to types that are equivalent, ignoring + their qualifiers, except for named address spaces. If the pointers point to + different named addresses, then we must determine if one address space is a + subset of the other. */ + +static int +comp_target_types (location_t location, tree ttl, tree ttr) +{ + int val; + int val_ped; + tree mvl = TREE_TYPE (ttl); + tree mvr = TREE_TYPE (ttr); + addr_space_t asl = TYPE_ADDR_SPACE (mvl); + addr_space_t asr = TYPE_ADDR_SPACE (mvr); + addr_space_t as_common; + bool enum_and_int_p; + + /* Fail if pointers point to incompatible address spaces. */ + if (!addr_space_superset (asl, asr, &as_common)) + return 0; + + /* For pedantic record result of comptypes on arrays before losing + qualifiers on the element type below. */ + val_ped = 1; + + if (TREE_CODE (mvl) == ARRAY_TYPE + && TREE_CODE (mvr) == ARRAY_TYPE) + val_ped = comptypes (mvl, mvr); + + /* Qualifiers on element types of array types that are + pointer targets are lost by taking their TYPE_MAIN_VARIANT. */ + + mvl = (TYPE_ATOMIC (strip_array_types (mvl)) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (mvl)); + + mvr = (TYPE_ATOMIC (strip_array_types (mvr)) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (mvr)); + + enum_and_int_p = false; + val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p); + + if (val == 1 && val_ped != 1) + pedwarn_c11 (location, OPT_Wpedantic, "invalid use of pointers to arrays with different qualifiers " + "in ISO C before C2X"); + + if (val == 2) + pedwarn (location, OPT_Wpedantic, "types are not quite compatible"); + + if (val == 1 && enum_and_int_p && warn_cxx_compat) + warning_at (location, OPT_Wc___compat, + "pointer target types incompatible in C++"); + + return val; +} + +/* Subroutines of `comptypes'. */ + +/* Determine whether two trees derive from the same translation unit. + If the CONTEXT chain ends in a null, that tree's context is still + being parsed, so if two trees have context chains ending in null, + they're in the same translation unit. */ + +bool +same_translation_unit_p (const_tree t1, const_tree t2) +{ + while (t1 && TREE_CODE (t1) != TRANSLATION_UNIT_DECL) + switch (TREE_CODE_CLASS (TREE_CODE (t1))) + { + case tcc_declaration: + t1 = DECL_CONTEXT (t1); break; + case tcc_type: + t1 = TYPE_CONTEXT (t1); break; + case tcc_exceptional: + t1 = BLOCK_SUPERCONTEXT (t1); break; /* assume block */ + default: gcc_unreachable (); + } + + while (t2 && TREE_CODE (t2) != TRANSLATION_UNIT_DECL) + switch (TREE_CODE_CLASS (TREE_CODE (t2))) + { + case tcc_declaration: + t2 = DECL_CONTEXT (t2); break; + case tcc_type: + t2 = TYPE_CONTEXT (t2); break; + case tcc_exceptional: + t2 = BLOCK_SUPERCONTEXT (t2); break; /* assume block */ + default: gcc_unreachable (); + } + + return t1 == t2; +} + +/* Allocate the seen two types, assuming that they are compatible. */ + +static struct tagged_tu_seen_cache * +alloc_tagged_tu_seen_cache (const_tree t1, const_tree t2) +{ + struct tagged_tu_seen_cache *tu = XNEW (struct tagged_tu_seen_cache); + tu->next = tagged_tu_seen_base; + tu->t1 = t1; + tu->t2 = t2; + + tagged_tu_seen_base = tu; + + /* The C standard says that two structures in different translation + units are compatible with each other only if the types of their + fields are compatible (among other things). We assume that they + are compatible until proven otherwise when building the cache. + An example where this can occur is: + struct a + { + struct a *next; + }; + If we are comparing this against a similar struct in another TU, + and did not assume they were compatible, we end up with an infinite + loop. */ + tu->val = 1; + return tu; +} + +/* Free the seen types until we get to TU_TIL. */ + +static void +free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til) +{ + const struct tagged_tu_seen_cache *tu = tagged_tu_seen_base; + while (tu != tu_til) + { + const struct tagged_tu_seen_cache *const tu1 + = (const struct tagged_tu_seen_cache *) tu; + tu = tu1->next; + XDELETE (CONST_CAST (struct tagged_tu_seen_cache *, tu1)); + } + tagged_tu_seen_base = tu_til; +} + +/* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are + compatible. If the two types are not the same (which has been + checked earlier), this can only happen when multiple translation + units are being compiled. See C99 6.2.7 paragraph 1 for the exact + rules. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in + comptypes_internal. */ + +static int +tagged_types_tu_compatible_p (const_tree t1, const_tree t2, + bool *enum_and_int_p, bool *different_types_p) +{ + tree s1, s2; + bool needs_warning = false; + + /* We have to verify that the tags of the types are the same. This + is harder than it looks because this may be a typedef, so we have + to go look at the original type. It may even be a typedef of a + typedef... + In the case of compiler-created builtin structs the TYPE_DECL + may be a dummy, with no DECL_ORIGINAL_TYPE. Don't fault. */ + while (TYPE_NAME (t1) + && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (t1))) + t1 = DECL_ORIGINAL_TYPE (TYPE_NAME (t1)); + + while (TYPE_NAME (t2) + && TREE_CODE (TYPE_NAME (t2)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (t2))) + t2 = DECL_ORIGINAL_TYPE (TYPE_NAME (t2)); + + /* C90 didn't have the requirement that the two tags be the same. */ + if (flag_isoc99 && TYPE_NAME (t1) != TYPE_NAME (t2)) + return 0; + + /* C90 didn't say what happened if one or both of the types were + incomplete; we choose to follow C99 rules here, which is that they + are compatible. */ + if (TYPE_SIZE (t1) == NULL + || TYPE_SIZE (t2) == NULL) + return 1; + + { + const struct tagged_tu_seen_cache * tts_i; + for (tts_i = tagged_tu_seen_base; tts_i != NULL; tts_i = tts_i->next) + if (tts_i->t1 == t1 && tts_i->t2 == t2) + return tts_i->val; + } + + switch (TREE_CODE (t1)) + { + case ENUMERAL_TYPE: + { + struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); + /* Speed up the case where the type values are in the same order. */ + tree tv1 = TYPE_VALUES (t1); + tree tv2 = TYPE_VALUES (t2); + + if (tv1 == tv2) + { + return 1; + } + + for (;tv1 && tv2; tv1 = TREE_CHAIN (tv1), tv2 = TREE_CHAIN (tv2)) + { + if (TREE_PURPOSE (tv1) != TREE_PURPOSE (tv2)) + break; + if (simple_cst_equal (TREE_VALUE (tv1), TREE_VALUE (tv2)) != 1) + { + tu->val = 0; + return 0; + } + } + + if (tv1 == NULL_TREE && tv2 == NULL_TREE) + { + return 1; + } + if (tv1 == NULL_TREE || tv2 == NULL_TREE) + { + tu->val = 0; + return 0; + } + + if (list_length (TYPE_VALUES (t1)) != list_length (TYPE_VALUES (t2))) + { + tu->val = 0; + return 0; + } + + for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1)) + { + s2 = purpose_member (TREE_PURPOSE (s1), TYPE_VALUES (t2)); + if (s2 == NULL + || simple_cst_equal (TREE_VALUE (s1), TREE_VALUE (s2)) != 1) + { + tu->val = 0; + return 0; + } + } + return 1; + } + + case UNION_TYPE: + { + struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); + if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2))) + { + tu->val = 0; + return 0; + } + + /* Speed up the common case where the fields are in the same order. */ + for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2; + s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2)) + { + int result; + + if (DECL_NAME (s1) != DECL_NAME (s2)) + break; + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), + enum_and_int_p, different_types_p); + + if (result != 1 && !DECL_NAME (s1)) + break; + if (result == 0) + { + tu->val = 0; + return 0; + } + if (result == 2) + needs_warning = true; + + if (TREE_CODE (s1) == FIELD_DECL + && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), + DECL_FIELD_BIT_OFFSET (s2)) != 1) + { + tu->val = 0; + return 0; + } + } + if (!s1 && !s2) + { + tu->val = needs_warning ? 2 : 1; + return tu->val; + } + + for (s1 = TYPE_FIELDS (t1); s1; s1 = DECL_CHAIN (s1)) + { + bool ok = false; + + for (s2 = TYPE_FIELDS (t2); s2; s2 = DECL_CHAIN (s2)) + if (DECL_NAME (s1) == DECL_NAME (s2)) + { + int result; + + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), + enum_and_int_p, + different_types_p); + + if (result != 1 && !DECL_NAME (s1)) + continue; + if (result == 0) + { + tu->val = 0; + return 0; + } + if (result == 2) + needs_warning = true; + + if (TREE_CODE (s1) == FIELD_DECL + && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), + DECL_FIELD_BIT_OFFSET (s2)) != 1) + break; + + ok = true; + break; + } + if (!ok) + { + tu->val = 0; + return 0; + } + } + tu->val = needs_warning ? 2 : 10; + return tu->val; + } + + case RECORD_TYPE: + { + struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); + + for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); + s1 && s2; + s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2)) + { + int result; + if (TREE_CODE (s1) != TREE_CODE (s2) + || DECL_NAME (s1) != DECL_NAME (s2)) + break; + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), + enum_and_int_p, different_types_p); + if (result == 0) + break; + if (result == 2) + needs_warning = true; + + if (TREE_CODE (s1) == FIELD_DECL + && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), + DECL_FIELD_BIT_OFFSET (s2)) != 1) + break; + } + if (s1 && s2) + tu->val = 0; + else + tu->val = needs_warning ? 2 : 1; + return tu->val; + } + + default: + gcc_unreachable (); + } +} + +/* Return 1 if two function types F1 and F2 are compatible. + If either type specifies no argument types, + the other must specify a fixed number of self-promoting arg types. + Otherwise, if one type specifies only the number of arguments, + the other must specify that number of self-promoting arg types. + Otherwise, the argument types must match. + ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in comptypes_internal. */ + +static int +function_types_compatible_p (const_tree f1, const_tree f2, + bool *enum_and_int_p, bool *different_types_p) +{ + tree args1, args2; + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + int val = 1; + int val1; + tree ret1, ret2; + + ret1 = TREE_TYPE (f1); + ret2 = TREE_TYPE (f2); + + /* 'volatile' qualifiers on a function's return type used to mean + the function is noreturn. */ + if (TYPE_VOLATILE (ret1) != TYPE_VOLATILE (ret2)) + pedwarn (input_location, 0, "function return types not compatible due to %"); + if (TYPE_VOLATILE (ret1)) + ret1 = build_qualified_type (TYPE_MAIN_VARIANT (ret1), + TYPE_QUALS (ret1) & ~TYPE_QUAL_VOLATILE); + if (TYPE_VOLATILE (ret2)) + ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2), + TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE); + val = comptypes_internal (ret1, ret2, enum_and_int_p, different_types_p); + if (val == 0) + return 0; + + args1 = TYPE_ARG_TYPES (f1); + args2 = TYPE_ARG_TYPES (f2); + + if (different_types_p != NULL + && (args1 == NULL_TREE) != (args2 == NULL_TREE)) + *different_types_p = true; + + /* An unspecified parmlist matches any specified parmlist + whose argument types don't need default promotions. */ + + if (args1 == NULL_TREE) + { + if (flag_isoc2x ? stdarg_p (f2) : !self_promoting_args_p (args2)) + return 0; + /* If one of these types comes from a non-prototype fn definition, + compare that with the other type's arglist. + If they don't match, ask for a warning (but no error). */ + if (TYPE_ACTUAL_ARG_TYPES (f1) + && type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1), + enum_and_int_p, different_types_p) != 1) + val = 2; + return val; + } + if (args2 == NULL_TREE) + { + if (flag_isoc2x ? stdarg_p (f1) : !self_promoting_args_p (args1)) + return 0; + if (TYPE_ACTUAL_ARG_TYPES (f2) + && type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2), + enum_and_int_p, different_types_p) != 1) + val = 2; + return val; + } + + /* Both types have argument lists: compare them and propagate results. */ + val1 = type_lists_compatible_p (args1, args2, enum_and_int_p, + different_types_p); + return val1 != 1 ? val1 : val; +} + +/* Check two lists of types for compatibility, returning 0 for + incompatible, 1 for compatible, or 2 for compatible with + warning. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in + comptypes_internal. */ + +static int +type_lists_compatible_p (const_tree args1, const_tree args2, + bool *enum_and_int_p, bool *different_types_p) +{ + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + int val = 1; + int newval = 0; + + while (1) + { + tree a1, mv1, a2, mv2; + if (args1 == NULL_TREE && args2 == NULL_TREE) + return val; + /* If one list is shorter than the other, + they fail to match. */ + if (args1 == NULL_TREE || args2 == NULL_TREE) + return 0; + mv1 = a1 = TREE_VALUE (args1); + mv2 = a2 = TREE_VALUE (args2); + if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE) + mv1 = (TYPE_ATOMIC (mv1) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv1), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (mv1)); + if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE) + mv2 = (TYPE_ATOMIC (mv2) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv2), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (mv2)); + /* A null pointer instead of a type + means there is supposed to be an argument + but nothing is specified about what type it has. + So match anything that self-promotes. */ + if (different_types_p != NULL + && (a1 == NULL_TREE) != (a2 == NULL_TREE)) + *different_types_p = true; + if (a1 == NULL_TREE) + { + if (c_type_promotes_to (a2) != a2) + return 0; + } + else if (a2 == NULL_TREE) + { + if (c_type_promotes_to (a1) != a1) + return 0; + } + /* If one of the lists has an error marker, ignore this arg. */ + else if (TREE_CODE (a1) == ERROR_MARK + || TREE_CODE (a2) == ERROR_MARK) + ; + else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p, + different_types_p))) + { + if (different_types_p != NULL) + *different_types_p = true; + /* Allow wait (union {union wait *u; int *i} *) + and wait (union wait *) to be compatible. */ + if (TREE_CODE (a1) == UNION_TYPE + && (TYPE_NAME (a1) == NULL_TREE + || TYPE_TRANSPARENT_AGGR (a1)) + && TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST + && tree_int_cst_equal (TYPE_SIZE (a1), + TYPE_SIZE (a2))) + { + tree memb; + for (memb = TYPE_FIELDS (a1); + memb; memb = DECL_CHAIN (memb)) + { + tree mv3 = TREE_TYPE (memb); + if (mv3 && mv3 != error_mark_node + && TREE_CODE (mv3) != ARRAY_TYPE) + mv3 = (TYPE_ATOMIC (mv3) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (mv3)); + if (comptypes_internal (mv3, mv2, enum_and_int_p, + different_types_p)) + break; + } + if (memb == NULL_TREE) + return 0; + } + else if (TREE_CODE (a2) == UNION_TYPE + && (TYPE_NAME (a2) == NULL_TREE + || TYPE_TRANSPARENT_AGGR (a2)) + && TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST + && tree_int_cst_equal (TYPE_SIZE (a2), + TYPE_SIZE (a1))) + { + tree memb; + for (memb = TYPE_FIELDS (a2); + memb; memb = DECL_CHAIN (memb)) + { + tree mv3 = TREE_TYPE (memb); + if (mv3 && mv3 != error_mark_node + && TREE_CODE (mv3) != ARRAY_TYPE) + mv3 = (TYPE_ATOMIC (mv3) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (mv3)); + if (comptypes_internal (mv3, mv1, enum_and_int_p, + different_types_p)) + break; + } + if (memb == NULL_TREE) + return 0; + } + else + return 0; + } + + /* comptypes said ok, but record if it said to warn. */ + if (newval > val) + val = newval; + + args1 = TREE_CHAIN (args1); + args2 = TREE_CHAIN (args2); + } +} + +/* Compute the size to increment a pointer by. When a function type or void + type or incomplete type is passed, size_one_node is returned. + This function does not emit any diagnostics; the caller is responsible + for that. */ + +static tree +c_size_in_bytes (const_tree type) +{ + enum tree_code code = TREE_CODE (type); + + if (code == FUNCTION_TYPE || code == VOID_TYPE || code == ERROR_MARK + || !COMPLETE_TYPE_P (type)) + return size_one_node; + + /* Convert in case a char is more than one unit. */ + return size_binop_loc (input_location, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type), + size_int (TYPE_PRECISION (char_type_node) + / BITS_PER_UNIT)); +} + +/* Return either DECL or its known constant value (if it has one). */ + +tree +decl_constant_value_1 (tree decl, bool in_init) +{ + if (/* Note that DECL_INITIAL isn't valid for a PARM_DECL. */ + TREE_CODE (decl) != PARM_DECL + && !TREE_THIS_VOLATILE (decl) + && TREE_READONLY (decl) + && DECL_INITIAL (decl) != NULL_TREE + && !error_operand_p (DECL_INITIAL (decl)) + /* This is invalid if initial value is not constant. + If it has either a function call, a memory reference, + or a variable, then re-evaluating it could give different results. */ + && TREE_CONSTANT (DECL_INITIAL (decl)) + /* Check for cases where this is sub-optimal, even though valid. */ + && (in_init || TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR)) + return DECL_INITIAL (decl); + return decl; +} + +/* Return either DECL or its known constant value (if it has one). + Like the above, but always return decl outside of functions. */ + +tree +decl_constant_value (tree decl) +{ + /* Don't change a variable array bound or initial value to a constant + in a place where a variable is invalid. */ + return current_function_decl ? decl_constant_value_1 (decl, false) : decl; +} + +/* Convert the array expression EXP to a pointer. */ +static tree +array_to_pointer_conversion (location_t loc, tree exp) +{ + tree orig_exp = exp; + tree type = TREE_TYPE (exp); + tree adr; + tree restype = TREE_TYPE (type); + tree ptrtype; + + gcc_assert (TREE_CODE (type) == ARRAY_TYPE); + + STRIP_TYPE_NOPS (exp); + + copy_warning (exp, orig_exp); + + ptrtype = build_pointer_type (restype); + + if (INDIRECT_REF_P (exp)) + return convert (ptrtype, TREE_OPERAND (exp, 0)); + + /* In C++ array compound literals are temporary objects unless they are + const or appear in namespace scope, so they are destroyed too soon + to use them for much of anything (c++/53220). */ + if (warn_cxx_compat && TREE_CODE (exp) == COMPOUND_LITERAL_EXPR) + { + tree decl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + if (!TREE_READONLY (decl) && !TREE_STATIC (decl)) + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, + "converting an array compound literal to a pointer " + "is ill-formed in C++"); + } + + adr = build_unary_op (loc, ADDR_EXPR, exp, true); + return convert (ptrtype, adr); +} + +/* Convert the function expression EXP to a pointer. */ +static tree +function_to_pointer_conversion (location_t loc, tree exp) +{ + tree orig_exp = exp; + + gcc_assert (TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE); + + STRIP_TYPE_NOPS (exp); + + copy_warning (exp, orig_exp); + + return build_unary_op (loc, ADDR_EXPR, exp, false); +} + +/* Mark EXP as read, not just set, for set but not used -Wunused + warning purposes. */ + +void +mark_exp_read (tree exp) +{ + switch (TREE_CODE (exp)) + { + case VAR_DECL: + case PARM_DECL: + DECL_READ_P (exp) = 1; + break; + case ARRAY_REF: + case COMPONENT_REF: + case MODIFY_EXPR: + case REALPART_EXPR: + case IMAGPART_EXPR: + CASE_CONVERT: + case ADDR_EXPR: + case VIEW_CONVERT_EXPR: + mark_exp_read (TREE_OPERAND (exp, 0)); + break; + case COMPOUND_EXPR: + /* Pattern match what build_atomic_assign produces with modifycode + NOP_EXPR. */ + if (VAR_P (TREE_OPERAND (exp, 1)) + && DECL_ARTIFICIAL (TREE_OPERAND (exp, 1)) + && TREE_CODE (TREE_OPERAND (exp, 0)) == COMPOUND_EXPR) + { + tree t1 = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + tree t2 = TREE_OPERAND (TREE_OPERAND (exp, 0), 1); + if (TREE_CODE (t1) == TARGET_EXPR + && TARGET_EXPR_SLOT (t1) == TREE_OPERAND (exp, 1) + && TREE_CODE (t2) == CALL_EXPR) + { + tree fndecl = get_callee_fndecl (t2); + tree arg = NULL_TREE; + if (fndecl + && TREE_CODE (fndecl) == FUNCTION_DECL + && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL) + && call_expr_nargs (t2) >= 2) + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_ATOMIC_STORE: + arg = CALL_EXPR_ARG (t2, 1); + break; + case BUILT_IN_ATOMIC_STORE_1: + case BUILT_IN_ATOMIC_STORE_2: + case BUILT_IN_ATOMIC_STORE_4: + case BUILT_IN_ATOMIC_STORE_8: + case BUILT_IN_ATOMIC_STORE_16: + arg = CALL_EXPR_ARG (t2, 0); + break; + default: + break; + } + if (arg) + { + STRIP_NOPS (arg); + if (TREE_CODE (arg) == ADDR_EXPR + && DECL_P (TREE_OPERAND (arg, 0)) + && TYPE_ATOMIC (TREE_TYPE (TREE_OPERAND (arg, 0)))) + mark_exp_read (TREE_OPERAND (arg, 0)); + } + } + } + /* FALLTHRU */ + case C_MAYBE_CONST_EXPR: + mark_exp_read (TREE_OPERAND (exp, 1)); + break; + default: + break; + } +} + +/* Perform the default conversion of arrays and functions to pointers. + Return the result of converting EXP. For any other expression, just + return EXP. + + LOC is the location of the expression. */ + +struct c_expr +default_function_array_conversion (location_t loc, struct c_expr exp) +{ + tree orig_exp = exp.value; + tree type = TREE_TYPE (exp.value); + enum tree_code code = TREE_CODE (type); + + switch (code) + { + case ARRAY_TYPE: + { + bool not_lvalue = false; + bool lvalue_array_p; + + while ((TREE_CODE (exp.value) == NON_LVALUE_EXPR + || CONVERT_EXPR_P (exp.value)) + && TREE_TYPE (TREE_OPERAND (exp.value, 0)) == type) + { + if (TREE_CODE (exp.value) == NON_LVALUE_EXPR) + not_lvalue = true; + exp.value = TREE_OPERAND (exp.value, 0); + } + + copy_warning (exp.value, orig_exp); + + lvalue_array_p = !not_lvalue && lvalue_p (exp.value); + if (!flag_isoc99 && !lvalue_array_p) + { + /* Before C99, non-lvalue arrays do not decay to pointers. + Normally, using such an array would be invalid; but it can + be used correctly inside sizeof or as a statement expression. + Thus, do not give an error here; an error will result later. */ + return exp; + } + + exp.value = array_to_pointer_conversion (loc, exp.value); + } + break; + case FUNCTION_TYPE: + exp.value = function_to_pointer_conversion (loc, exp.value); + break; + default: + break; + } + + return exp; +} + +struct c_expr +default_function_array_read_conversion (location_t loc, struct c_expr exp) +{ + mark_exp_read (exp.value); + return default_function_array_conversion (loc, exp); +} + +/* Return whether EXPR should be treated as an atomic lvalue for the + purposes of load and store handling. */ + +static bool +really_atomic_lvalue (tree expr) +{ + if (error_operand_p (expr)) + return false; + if (!TYPE_ATOMIC (TREE_TYPE (expr))) + return false; + if (!lvalue_p (expr)) + return false; + + /* Ignore _Atomic on register variables, since their addresses can't + be taken so (a) atomicity is irrelevant and (b) the normal atomic + sequences wouldn't work. Ignore _Atomic on structures containing + bit-fields, since accessing elements of atomic structures or + unions is undefined behavior (C11 6.5.2.3#5), but it's unclear if + it's undefined at translation time or execution time, and the + normal atomic sequences again wouldn't work. */ + while (handled_component_p (expr)) + { + if (TREE_CODE (expr) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1))) + return false; + expr = TREE_OPERAND (expr, 0); + } + if (DECL_P (expr) && C_DECL_REGISTER (expr)) + return false; + return true; +} + +/* Convert expression EXP (location LOC) from lvalue to rvalue, + including converting functions and arrays to pointers if CONVERT_P. + If READ_P, also mark the expression as having been read. */ + +struct c_expr +convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, + bool convert_p, bool read_p) +{ + if (read_p) + mark_exp_read (exp.value); + if (convert_p) + exp = default_function_array_conversion (loc, exp); + if (!VOID_TYPE_P (TREE_TYPE (exp.value))) + exp.value = require_complete_type (loc, exp.value); + if (really_atomic_lvalue (exp.value)) + { + vec *params; + tree nonatomic_type, tmp, tmp_addr, fndecl, func_call; + tree expr_type = TREE_TYPE (exp.value); + tree expr_addr = build_unary_op (loc, ADDR_EXPR, exp.value, false); + tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); + + gcc_assert (TYPE_ATOMIC (expr_type)); + + /* Expansion of a generic atomic load may require an addition + element, so allocate enough to prevent a resize. */ + vec_alloc (params, 4); + + /* Remove the qualifiers for the rest of the expressions and + create the VAL temp variable to hold the RHS. */ + nonatomic_type = build_qualified_type (expr_type, TYPE_UNQUALIFIED); + tmp = create_tmp_var_raw (nonatomic_type); + tmp_addr = build_unary_op (loc, ADDR_EXPR, tmp, false); + TREE_ADDRESSABLE (tmp) = 1; + /* Do not disable warnings for TMP even though it's artificial. + -Winvalid-memory-model depends on it. */ + + /* Issue __atomic_load (&expr, &tmp, SEQ_CST); */ + fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD); + params->quick_push (expr_addr); + params->quick_push (tmp_addr); + params->quick_push (seq_cst); + func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); + + /* EXPR is always read. */ + mark_exp_read (exp.value); + + /* Return tmp which contains the value loaded. */ + exp.value = build4 (TARGET_EXPR, nonatomic_type, tmp, func_call, + NULL_TREE, NULL_TREE); + } + if (convert_p && !error_operand_p (exp.value) + && (TREE_CODE (TREE_TYPE (exp.value)) != ARRAY_TYPE)) + exp.value = convert (build_qualified_type (TREE_TYPE (exp.value), TYPE_UNQUALIFIED), exp.value); + return exp; +} + +/* EXP is an expression of integer type. Apply the integer promotions + to it and return the promoted value. */ + +tree +perform_integral_promotions (tree exp) +{ + tree type = TREE_TYPE (exp); + enum tree_code code = TREE_CODE (type); + + gcc_assert (INTEGRAL_TYPE_P (type)); + + /* Normally convert enums to int, + but convert wide enums to something wider. */ + if (code == ENUMERAL_TYPE) + { + type = c_common_type_for_size (MAX (TYPE_PRECISION (type), + TYPE_PRECISION (integer_type_node)), + ((TYPE_PRECISION (type) + >= TYPE_PRECISION (integer_type_node)) + && TYPE_UNSIGNED (type))); + + return convert (type, exp); + } + + /* ??? This should no longer be needed now bit-fields have their + proper types. */ + if (TREE_CODE (exp) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1)) + /* If it's thinner than an int, promote it like a + c_promoting_integer_type_p, otherwise leave it alone. */ + && compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)), + TYPE_PRECISION (integer_type_node)) < 0) + return convert (integer_type_node, exp); + + if (c_promoting_integer_type_p (type)) + { + /* Preserve unsignedness if not really getting any wider. */ + if (TYPE_UNSIGNED (type) + && TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) + return convert (unsigned_type_node, exp); + + return convert (integer_type_node, exp); + } + + return exp; +} + + +/* Perform default promotions for C data used in expressions. + Enumeral types or short or char are converted to int. + In addition, manifest constants symbols are replaced by their values. */ + +tree +default_conversion (tree exp) +{ + tree orig_exp; + tree type = TREE_TYPE (exp); + enum tree_code code = TREE_CODE (type); + tree promoted_type; + + mark_exp_read (exp); + + /* Functions and arrays have been converted during parsing. */ + gcc_assert (code != FUNCTION_TYPE); + if (code == ARRAY_TYPE) + return exp; + + /* Constants can be used directly unless they're not loadable. */ + if (TREE_CODE (exp) == CONST_DECL) + exp = DECL_INITIAL (exp); + + /* Strip no-op conversions. */ + orig_exp = exp; + STRIP_TYPE_NOPS (exp); + + copy_warning (exp, orig_exp); + + if (code == VOID_TYPE) + { + error_at (EXPR_LOC_OR_LOC (exp, input_location), + "void value not ignored as it ought to be"); + return error_mark_node; + } + + exp = require_complete_type (EXPR_LOC_OR_LOC (exp, input_location), exp); + if (exp == error_mark_node) + return error_mark_node; + + promoted_type = targetm.promoted_type (type); + if (promoted_type) + return convert (promoted_type, exp); + + if (INTEGRAL_TYPE_P (type)) + return perform_integral_promotions (exp); + + return exp; +} + +/* Look up COMPONENT in a structure or union TYPE. + + If the component name is not found, returns NULL_TREE. Otherwise, + the return value is a TREE_LIST, with each TREE_VALUE a FIELD_DECL + stepping down the chain to the component, which is in the last + TREE_VALUE of the list. Normally the list is of length one, but if + the component is embedded within (nested) anonymous structures or + unions, the list steps down the chain to the component. */ + +static tree +lookup_field (tree type, tree component) +{ + tree field; + + /* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers + to the field elements. Use a binary search on this array to quickly + find the element. Otherwise, do a linear search. TYPE_LANG_SPECIFIC + will always be set for structures which have many elements. + + Duplicate field checking replaces duplicates with NULL_TREE so + TYPE_LANG_SPECIFIC arrays are potentially no longer sorted. In that + case just iterate using DECL_CHAIN. */ + + if (TYPE_LANG_SPECIFIC (type) && TYPE_LANG_SPECIFIC (type)->s + && !seen_error ()) + { + int bot, top, half; + tree *field_array = &TYPE_LANG_SPECIFIC (type)->s->elts[0]; + + field = TYPE_FIELDS (type); + bot = 0; + top = TYPE_LANG_SPECIFIC (type)->s->len; + while (top - bot > 1) + { + half = (top - bot + 1) >> 1; + field = field_array[bot+half]; + + if (DECL_NAME (field) == NULL_TREE) + { + /* Step through all anon unions in linear fashion. */ + while (DECL_NAME (field_array[bot]) == NULL_TREE) + { + field = field_array[bot++]; + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) + { + tree anon = lookup_field (TREE_TYPE (field), component); + + if (anon) + return tree_cons (NULL_TREE, field, anon); + + /* The Plan 9 compiler permits referring + directly to an anonymous struct/union field + using a typedef name. */ + if (flag_plan9_extensions + && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE + && (TREE_CODE (TYPE_NAME (TREE_TYPE (field))) + == TYPE_DECL) + && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) + == component)) + break; + } + } + + /* Entire record is only anon unions. */ + if (bot > top) + return NULL_TREE; + + /* Restart the binary search, with new lower bound. */ + continue; + } + + if (DECL_NAME (field) == component) + break; + if (DECL_NAME (field) < component) + bot += half; + else + top = bot + half; + } + + if (DECL_NAME (field_array[bot]) == component) + field = field_array[bot]; + else if (DECL_NAME (field) != component) + return NULL_TREE; + } + else + { + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + if (DECL_NAME (field) == NULL_TREE + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) + { + tree anon = lookup_field (TREE_TYPE (field), component); + + if (anon) + return tree_cons (NULL_TREE, field, anon); + + /* The Plan 9 compiler permits referring directly to an + anonymous struct/union field using a typedef + name. */ + if (flag_plan9_extensions + && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE + && TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL + && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) + == component)) + break; + } + + if (DECL_NAME (field) == component) + break; + } + + if (field == NULL_TREE) + return NULL_TREE; + } + + return tree_cons (NULL_TREE, field, NULL_TREE); +} + +/* Recursively append candidate IDENTIFIER_NODEs to CANDIDATES. */ + +static void +lookup_field_fuzzy_find_candidates (tree type, tree component, + vec *candidates) +{ + tree field; + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + if (DECL_NAME (field) == NULL_TREE + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) + lookup_field_fuzzy_find_candidates (TREE_TYPE (field), component, + candidates); + + if (DECL_NAME (field)) + candidates->safe_push (DECL_NAME (field)); + } +} + +/* Like "lookup_field", but find the closest matching IDENTIFIER_NODE, + rather than returning a TREE_LIST for an exact match. */ + +static tree +lookup_field_fuzzy (tree type, tree component) +{ + gcc_assert (TREE_CODE (component) == IDENTIFIER_NODE); + + /* First, gather a list of candidates. */ + auto_vec candidates; + + lookup_field_fuzzy_find_candidates (type, component, + &candidates); + + return find_closest_identifier (component, &candidates); +} + +/* Support function for build_component_ref's error-handling. + + Given DATUM_TYPE, and "DATUM.COMPONENT", where DATUM is *not* a + struct or union, should we suggest "DATUM->COMPONENT" as a hint? */ + +static bool +should_suggest_deref_p (tree datum_type) +{ + /* We don't do it for Objective-C, since Objective-C 2.0 dot-syntax + allows "." for ptrs; we could be handling a failed attempt + to access a property. */ + if (c_dialect_objc ()) + return false; + + /* Only suggest it for pointers... */ + if (TREE_CODE (datum_type) != POINTER_TYPE) + return false; + + /* ...to structs/unions. */ + tree underlying_type = TREE_TYPE (datum_type); + enum tree_code code = TREE_CODE (underlying_type); + if (code == RECORD_TYPE || code == UNION_TYPE) + return true; + else + return false; +} + +/* Make an expression to refer to the COMPONENT field of structure or + union value DATUM. COMPONENT is an IDENTIFIER_NODE. LOC is the + location of the COMPONENT_REF. COMPONENT_LOC is the location + of COMPONENT. */ + +tree +build_component_ref (location_t loc, tree datum, tree component, + location_t component_loc) +{ + tree type = TREE_TYPE (datum); + enum tree_code code = TREE_CODE (type); + tree field = NULL; + tree ref; + bool datum_lvalue = lvalue_p (datum); + + if (!objc_is_public (datum, component)) + return error_mark_node; + + /* Detect Objective-C property syntax object.property. */ + if (c_dialect_objc () + && (ref = objc_maybe_build_component_ref (datum, component))) + return ref; + + /* See if there is a field or component with name COMPONENT. */ + + if (code == RECORD_TYPE || code == UNION_TYPE) + { + if (!COMPLETE_TYPE_P (type)) + { + c_incomplete_type_error (loc, NULL_TREE, type); + return error_mark_node; + } + + field = lookup_field (type, component); + + if (!field) + { + tree guessed_id = lookup_field_fuzzy (type, component); + if (guessed_id) + { + /* Attempt to provide a fixit replacement hint, if + we have a valid range for the component. */ + location_t reported_loc + = (component_loc != UNKNOWN_LOCATION) ? component_loc : loc; + gcc_rich_location rich_loc (reported_loc); + if (component_loc != UNKNOWN_LOCATION) + rich_loc.add_fixit_misspelled_id (component_loc, guessed_id); + error_at (&rich_loc, + "%qT has no member named %qE; did you mean %qE?", + type, component, guessed_id); + } + else + error_at (loc, "%qT has no member named %qE", type, component); + return error_mark_node; + } + + /* Accessing elements of atomic structures or unions is undefined + behavior (C11 6.5.2.3#5). */ + if (TYPE_ATOMIC (type) && c_inhibit_evaluation_warnings == 0) + { + if (code == RECORD_TYPE) + warning_at (loc, 0, "accessing a member %qE of an atomic " + "structure %qE", component, datum); + else + warning_at (loc, 0, "accessing a member %qE of an atomic " + "union %qE", component, datum); + } + + /* Chain the COMPONENT_REFs if necessary down to the FIELD. + This might be better solved in future the way the C++ front + end does it - by giving the anonymous entities each a + separate name and type, and then have build_component_ref + recursively call itself. We can't do that here. */ + do + { + tree subdatum = TREE_VALUE (field); + int quals; + tree subtype; + bool use_datum_quals; + + if (TREE_TYPE (subdatum) == error_mark_node) + return error_mark_node; + + /* If this is an rvalue, it does not have qualifiers in C + standard terms and we must avoid propagating such + qualifiers down to a non-lvalue array that is then + converted to a pointer. */ + use_datum_quals = (datum_lvalue + || TREE_CODE (TREE_TYPE (subdatum)) != ARRAY_TYPE); + + quals = TYPE_QUALS (strip_array_types (TREE_TYPE (subdatum))); + if (use_datum_quals) + quals |= TYPE_QUALS (TREE_TYPE (datum)); + subtype = c_build_qualified_type (TREE_TYPE (subdatum), quals); + + ref = build3 (COMPONENT_REF, subtype, datum, subdatum, + NULL_TREE); + SET_EXPR_LOCATION (ref, loc); + if (TREE_READONLY (subdatum) + || (use_datum_quals && TREE_READONLY (datum))) + TREE_READONLY (ref) = 1; + if (TREE_THIS_VOLATILE (subdatum) + || (use_datum_quals && TREE_THIS_VOLATILE (datum))) + TREE_THIS_VOLATILE (ref) = 1; + + if (TREE_UNAVAILABLE (subdatum)) + error_unavailable_use (subdatum, NULL_TREE); + else if (TREE_DEPRECATED (subdatum)) + warn_deprecated_use (subdatum, NULL_TREE); + + datum = ref; + + field = TREE_CHAIN (field); + } + while (field); + + return ref; + } + else if (should_suggest_deref_p (type)) + { + /* Special-case the error message for "ptr.field" for the case + where the user has confused "." vs "->". */ + rich_location richloc (line_table, loc); + /* "loc" should be the "." token. */ + richloc.add_fixit_replace ("->"); + error_at (&richloc, + "%qE is a pointer; did you mean to use %<->%>?", + datum); + return error_mark_node; + } + else if (code != ERROR_MARK) + error_at (loc, + "request for member %qE in something not a structure or union", + component); + + return error_mark_node; +} + +/* Given an expression PTR for a pointer, return an expression + for the value pointed to. + ERRORSTRING is the name of the operator to appear in error messages. + + LOC is the location to use for the generated tree. */ + +tree +build_indirect_ref (location_t loc, tree ptr, ref_operator errstring) +{ + tree pointer = default_conversion (ptr); + tree type = TREE_TYPE (pointer); + tree ref; + + if (TREE_CODE (type) == POINTER_TYPE) + { + if (CONVERT_EXPR_P (pointer) + || TREE_CODE (pointer) == VIEW_CONVERT_EXPR) + { + /* If a warning is issued, mark it to avoid duplicates from + the backend. This only needs to be done at + warn_strict_aliasing > 2. */ + if (warn_strict_aliasing > 2) + if (strict_aliasing_warning (EXPR_LOCATION (pointer), + type, TREE_OPERAND (pointer, 0))) + suppress_warning (pointer, OPT_Wstrict_aliasing_); + } + + if (TREE_CODE (pointer) == ADDR_EXPR + && (TREE_TYPE (TREE_OPERAND (pointer, 0)) + == TREE_TYPE (type))) + { + ref = TREE_OPERAND (pointer, 0); + protected_set_expr_location (ref, loc); + return ref; + } + else + { + tree t = TREE_TYPE (type); + + ref = build1 (INDIRECT_REF, t, pointer); + + if (VOID_TYPE_P (t) && c_inhibit_evaluation_warnings == 0) + warning_at (loc, 0, "dereferencing % pointer"); + + /* We *must* set TREE_READONLY when dereferencing a pointer to const, + so that we get the proper error message if the result is used + to assign to. Also, &* is supposed to be a no-op. + And ANSI C seems to specify that the type of the result + should be the const type. */ + /* A de-reference of a pointer to const is not a const. It is valid + to change it via some other pointer. */ + TREE_READONLY (ref) = TYPE_READONLY (t); + TREE_SIDE_EFFECTS (ref) + = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer); + TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t); + protected_set_expr_location (ref, loc); + return ref; + } + } + else if (TREE_CODE (pointer) != ERROR_MARK) + invalid_indirection_error (loc, type, errstring); + + return error_mark_node; +} + +/* This handles expressions of the form "a[i]", which denotes + an array reference. + + This is logically equivalent in C to *(a+i), but we may do it differently. + If A is a variable or a member, we generate a primitive ARRAY_REF. + This avoids forcing the array out of registers, and can work on + arrays that are not lvalues (for example, members of structures returned + by functions). + + For vector types, allow vector[i] but not i[vector], and create + *(((type*)&vectortype) + i) for the expression. + + LOC is the location to use for the returned expression. */ + +tree +build_array_ref (location_t loc, tree array, tree index) +{ + tree ret; + bool swapped = false; + if (TREE_TYPE (array) == error_mark_node + || TREE_TYPE (index) == error_mark_node) + return error_mark_node; + + if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE + && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE + /* Allow vector[index] but not index[vector]. */ + && !gnu_vector_type_p (TREE_TYPE (array))) + { + if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE + && TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE) + { + error_at (loc, + "subscripted value is neither array nor pointer nor vector"); + + return error_mark_node; + } + std::swap (array, index); + swapped = true; + } + + if (!INTEGRAL_TYPE_P (TREE_TYPE (index))) + { + error_at (loc, "array subscript is not an integer"); + return error_mark_node; + } + + if (TREE_CODE (TREE_TYPE (TREE_TYPE (array))) == FUNCTION_TYPE) + { + error_at (loc, "subscripted value is pointer to function"); + return error_mark_node; + } + + /* ??? Existing practice has been to warn only when the char + index is syntactically the index, not for char[array]. */ + if (!swapped) + warn_array_subscript_with_type_char (loc, index); + + /* Apply default promotions *after* noticing character types. */ + index = default_conversion (index); + if (index == error_mark_node) + return error_mark_node; + + gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE); + + bool was_vector = VECTOR_TYPE_P (TREE_TYPE (array)); + bool non_lvalue = convert_vector_to_array_for_subscript (loc, &array, index); + + if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE) + { + tree rval, type; + + /* An array that is indexed by a non-constant + cannot be stored in a register; we must be able to do + address arithmetic on its address. + Likewise an array of elements of variable size. */ + if (TREE_CODE (index) != INTEGER_CST + || (COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (array))) + && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST)) + { + if (!c_mark_addressable (array, true)) + return error_mark_node; + } + /* An array that is indexed by a constant value which is not within + the array bounds cannot be stored in a register either; because we + would get a crash in store_bit_field/extract_bit_field when trying + to access a non-existent part of the register. */ + if (TREE_CODE (index) == INTEGER_CST + && TYPE_DOMAIN (TREE_TYPE (array)) + && !int_fits_type_p (index, TYPE_DOMAIN (TREE_TYPE (array)))) + { + if (!c_mark_addressable (array)) + return error_mark_node; + } + + if ((pedantic || warn_c90_c99_compat) + && ! was_vector) + { + tree foo = array; + while (TREE_CODE (foo) == COMPONENT_REF) + foo = TREE_OPERAND (foo, 0); + if (VAR_P (foo) && C_DECL_REGISTER (foo)) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids subscripting % array"); + else if (!lvalue_p (foo)) + pedwarn_c90 (loc, OPT_Wpedantic, + "ISO C90 forbids subscripting non-lvalue " + "array"); + } + + type = TREE_TYPE (TREE_TYPE (array)); + rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE); + /* Array ref is const/volatile if the array elements are + or if the array is. */ + TREE_READONLY (rval) + |= (TYPE_READONLY (TREE_TYPE (TREE_TYPE (array))) + | TREE_READONLY (array)); + TREE_SIDE_EFFECTS (rval) + |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) + | TREE_SIDE_EFFECTS (array)); + TREE_THIS_VOLATILE (rval) + |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) + /* This was added by rms on 16 Nov 91. + It fixes vol struct foo *a; a->elts[1] + in an inline function. + Hope it doesn't break something else. */ + | TREE_THIS_VOLATILE (array)); + ret = require_complete_type (loc, rval); + protected_set_expr_location (ret, loc); + if (non_lvalue) + ret = non_lvalue_loc (loc, ret); + return ret; + } + else + { + tree ar = default_conversion (array); + + if (ar == error_mark_node) + return ar; + + gcc_assert (TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE); + gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE); + + ret = build_indirect_ref (loc, build_binary_op (loc, PLUS_EXPR, ar, + index, false), + RO_ARRAY_INDEXING); + if (non_lvalue) + ret = non_lvalue_loc (loc, ret); + return ret; + } +} + +/* Build an external reference to identifier ID. FUN indicates + whether this will be used for a function call. LOC is the source + location of the identifier. This sets *TYPE to the type of the + identifier, which is not the same as the type of the returned value + for CONST_DECLs defined as enum constants. If the type of the + identifier is not available, *TYPE is set to NULL. */ +tree +build_external_ref (location_t loc, tree id, bool fun, tree *type) +{ + tree ref; + tree decl = lookup_name (id); + + /* In Objective-C, an instance variable (ivar) may be preferred to + whatever lookup_name() found. */ + decl = objc_lookup_ivar (decl, id); + + *type = NULL; + if (decl && decl != error_mark_node) + { + ref = decl; + *type = TREE_TYPE (ref); + } + else if (fun) + /* Implicit function declaration. */ + ref = implicitly_declare (loc, id); + else if (decl == error_mark_node) + /* Don't complain about something that's already been + complained about. */ + return error_mark_node; + else + { + undeclared_variable (loc, id); + return error_mark_node; + } + + if (TREE_TYPE (ref) == error_mark_node) + return error_mark_node; + + if (TREE_UNAVAILABLE (ref)) + error_unavailable_use (ref, NULL_TREE); + else if (TREE_DEPRECATED (ref)) + warn_deprecated_use (ref, NULL_TREE); + + /* Recursive call does not count as usage. */ + if (ref != current_function_decl) + { + TREE_USED (ref) = 1; + } + + if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof) + { + if (!in_sizeof && !in_typeof) + C_DECL_USED (ref) = 1; + else if (DECL_INITIAL (ref) == NULL_TREE + && DECL_EXTERNAL (ref) + && !TREE_PUBLIC (ref)) + record_maybe_used_decl (ref); + } + + if (TREE_CODE (ref) == CONST_DECL) + { + used_types_insert (TREE_TYPE (ref)); + + if (warn_cxx_compat + && TREE_CODE (TREE_TYPE (ref)) == ENUMERAL_TYPE + && C_TYPE_DEFINED_IN_STRUCT (TREE_TYPE (ref))) + { + warning_at (loc, OPT_Wc___compat, + ("enum constant defined in struct or union " + "is not visible in C++")); + inform (DECL_SOURCE_LOCATION (ref), "enum constant defined here"); + } + + ref = DECL_INITIAL (ref); + TREE_CONSTANT (ref) = 1; + } + else if (current_function_decl != NULL_TREE + && !DECL_FILE_SCOPE_P (current_function_decl) + && (VAR_OR_FUNCTION_DECL_P (ref) + || TREE_CODE (ref) == PARM_DECL)) + { + tree context = decl_function_context (ref); + + if (context != NULL_TREE && context != current_function_decl) + DECL_NONLOCAL (ref) = 1; + } + /* C99 6.7.4p3: An inline definition of a function with external + linkage ... shall not contain a reference to an identifier with + internal linkage. */ + else if (current_function_decl != NULL_TREE + && DECL_DECLARED_INLINE_P (current_function_decl) + && DECL_EXTERNAL (current_function_decl) + && VAR_OR_FUNCTION_DECL_P (ref) + && (!VAR_P (ref) || TREE_STATIC (ref)) + && ! TREE_PUBLIC (ref) + && DECL_CONTEXT (ref) != current_function_decl) + record_inline_static (loc, current_function_decl, ref, + csi_internal); + + return ref; +} + +/* Record details of decls possibly used inside sizeof or typeof. */ +struct maybe_used_decl +{ + /* The decl. */ + tree decl; + /* The level seen at (in_sizeof + in_typeof). */ + int level; + /* The next one at this level or above, or NULL. */ + struct maybe_used_decl *next; +}; + +static struct maybe_used_decl *maybe_used_decls; + +/* Record that DECL, an undefined static function reference seen + inside sizeof or typeof, might be used if the operand of sizeof is + a VLA type or the operand of typeof is a variably modified + type. */ + +static void +record_maybe_used_decl (tree decl) +{ + struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl); + t->decl = decl; + t->level = in_sizeof + in_typeof; + t->next = maybe_used_decls; + maybe_used_decls = t; +} + +/* Pop the stack of decls possibly used inside sizeof or typeof. If + USED is false, just discard them. If it is true, mark them used + (if no longer inside sizeof or typeof) or move them to the next + level up (if still inside sizeof or typeof). */ + +void +pop_maybe_used (bool used) +{ + struct maybe_used_decl *p = maybe_used_decls; + int cur_level = in_sizeof + in_typeof; + while (p && p->level > cur_level) + { + if (used) + { + if (cur_level == 0) + C_DECL_USED (p->decl) = 1; + else + p->level = cur_level; + } + p = p->next; + } + if (!used || cur_level == 0) + maybe_used_decls = p; +} + +/* Return the result of sizeof applied to EXPR. */ + +struct c_expr +c_expr_sizeof_expr (location_t loc, struct c_expr expr) +{ + struct c_expr ret; + if (expr.value == error_mark_node) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + pop_maybe_used (false); + } + else + { + bool expr_const_operands = true; + + if (TREE_CODE (expr.value) == PARM_DECL + && C_ARRAY_PARAMETER (expr.value)) + { + auto_diagnostic_group d; + if (warning_at (loc, OPT_Wsizeof_array_argument, + "% on array function parameter %qE will " + "return size of %qT", expr.value, + TREE_TYPE (expr.value))) + inform (DECL_SOURCE_LOCATION (expr.value), "declared here"); + } + tree folded_expr = c_fully_fold (expr.value, require_constant_value, + &expr_const_operands); + ret.value = c_sizeof (loc, TREE_TYPE (folded_expr)); + c_last_sizeof_arg = expr.value; + c_last_sizeof_loc = loc; + ret.original_code = SIZEOF_EXPR; + ret.original_type = NULL; + if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr))) + { + /* sizeof is evaluated when given a vla (C99 6.5.3.4p2). */ + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), + folded_expr, ret.value); + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands; + SET_EXPR_LOCATION (ret.value, loc); + } + pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr))); + } + return ret; +} + +/* Return the result of sizeof applied to T, a structure for the type + name passed to sizeof (rather than the type itself). LOC is the + location of the original expression. */ + +struct c_expr +c_expr_sizeof_type (location_t loc, struct c_type_name *t) +{ + tree type; + struct c_expr ret; + tree type_expr = NULL_TREE; + bool type_expr_const = true; + type = groktypename (t, &type_expr, &type_expr_const); + ret.value = c_sizeof (loc, type); + c_last_sizeof_arg = type; + c_last_sizeof_loc = loc; + ret.original_code = SIZEOF_EXPR; + ret.original_type = NULL; + if (type == error_mark_node) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + } + else + if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST) + && C_TYPE_VARIABLE_SIZE (type)) + { + /* If the type is a [*] array, it is a VLA but is represented as + having a size of zero. In such a case we must ensure that + the result of sizeof does not get folded to a constant by + c_fully_fold, because if the size is evaluated the result is + not constant and so constraints on zero or negative size + arrays must not be applied when this sizeof call is inside + another array declarator. */ + if (!type_expr) + type_expr = integer_zero_node; + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), + type_expr, ret.value); + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const; + } + pop_maybe_used (type != error_mark_node + ? C_TYPE_VARIABLE_SIZE (type) : false); + return ret; +} + +/* Build a function call to function FUNCTION with parameters PARAMS. + The function call is at LOC. + PARAMS is a list--a chain of TREE_LIST nodes--in which the + TREE_VALUE of each node is a parameter-expression. + FUNCTION's data type may be a function type or a pointer-to-function. */ + +tree +build_function_call (location_t loc, tree function, tree params) +{ + vec *v; + tree ret; + + vec_alloc (v, list_length (params)); + for (; params; params = TREE_CHAIN (params)) + v->quick_push (TREE_VALUE (params)); + ret = c_build_function_call_vec (loc, vNULL, function, v, NULL); + vec_free (v); + return ret; +} + +/* Give a note about the location of the declaration of DECL. */ + +static void +inform_declaration (tree decl) +{ + if (decl && (TREE_CODE (decl) != FUNCTION_DECL + || !DECL_IS_UNDECLARED_BUILTIN (decl))) + inform (DECL_SOURCE_LOCATION (decl), "declared here"); +} + +/* Build a function call to function FUNCTION with parameters PARAMS. + If FUNCTION is the result of resolving an overloaded target built-in, + ORIG_FUNDECL is the original function decl, otherwise it is null. + ORIGTYPES, if not NULL, is a vector of types; each element is + either NULL or the original type of the corresponding element in + PARAMS. The original type may differ from TREE_TYPE of the + parameter for enums. FUNCTION's data type may be a function type + or pointer-to-function. This function changes the elements of + PARAMS. */ + +tree +build_function_call_vec (location_t loc, vec arg_loc, + tree function, vec *params, + vec *origtypes, tree orig_fundecl) +{ + tree fntype, fundecl = NULL_TREE; + tree name = NULL_TREE, result; + tree tem; + int nargs; + tree *argarray; + + + /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (function); + + /* Convert anything with function type to a pointer-to-function. */ + if (TREE_CODE (function) == FUNCTION_DECL) + { + name = DECL_NAME (function); + + if (flag_tm) + tm_malloc_replacement (function); + fundecl = function; + if (!orig_fundecl) + orig_fundecl = fundecl; + /* Atomic functions have type checking/casting already done. They are + often rewritten and don't match the original parameter list. */ + if (name && startswith (IDENTIFIER_POINTER (name), "__atomic_")) + origtypes = NULL; + } + if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE) + function = function_to_pointer_conversion (loc, function); + + /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF + expressions, like those used for ObjC messenger dispatches. */ + if (params && !params->is_empty ()) + function = objc_rewrite_function_call (function, (*params)[0]); + + function = c_fully_fold (function, false, NULL); + + fntype = TREE_TYPE (function); + + if (TREE_CODE (fntype) == ERROR_MARK) + return error_mark_node; + + if (!(TREE_CODE (fntype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)) + { + if (!flag_diagnostics_show_caret && !STATEMENT_CLASS_P (function)) + error_at (loc, + "called object %qE is not a function or function pointer", + function); + else if (DECL_P (function)) + { + error_at (loc, + "called object %qD is not a function or function pointer", + function); + inform_declaration (function); + } + else + error_at (loc, + "called object is not a function or function pointer"); + return error_mark_node; + } + + if (fundecl && TREE_THIS_VOLATILE (fundecl)) + current_function_returns_abnormally = 1; + + /* fntype now gets the type of function pointed to. */ + fntype = TREE_TYPE (fntype); + + /* Convert the parameters to the types declared in the + function prototype, or apply default promotions. */ + + nargs = convert_arguments (loc, arg_loc, TYPE_ARG_TYPES (fntype), params, + origtypes, function, fundecl); + if (nargs < 0) + return error_mark_node; + + /* Check that the function is called through a compatible prototype. + If it is not, warn. */ + if (CONVERT_EXPR_P (function) + && TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR + && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL + && !comptypes (fntype, TREE_TYPE (tem))) + { + tree return_type = TREE_TYPE (fntype); + + /* This situation leads to run-time undefined behavior. We can't, + therefore, simply error unless we can prove that all possible + executions of the program must execute the code. */ + warning_at (loc, 0, "function called through a non-compatible type"); + + if (VOID_TYPE_P (return_type) + && TYPE_QUALS (return_type) != TYPE_UNQUALIFIED) + pedwarn (loc, 0, + "function with qualified void return type called"); + } + + argarray = vec_safe_address (params); + + /* Check that arguments to builtin functions match the expectations. */ + if (fundecl + && fndecl_built_in_p (fundecl) + && !check_builtin_function_arguments (loc, arg_loc, fundecl, + orig_fundecl, nargs, argarray)) + return error_mark_node; + + /* Check that the arguments to the function are valid. */ + bool warned_p = check_function_arguments (loc, fundecl, fntype, + nargs, argarray, &arg_loc); + + if (name != NULL_TREE + && startswith (IDENTIFIER_POINTER (name), "__builtin_")) + { + if (require_constant_value) + result + = fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype), + function, nargs, argarray); + else + result = fold_build_call_array_loc (loc, TREE_TYPE (fntype), + function, nargs, argarray); + if (TREE_CODE (result) == NOP_EXPR + && TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST) + STRIP_TYPE_NOPS (result); + } + else + result = build_call_array_loc (loc, TREE_TYPE (fntype), + function, nargs, argarray); + /* If -Wnonnull warning has been diagnosed, avoid diagnosing it again + later. */ + if (warned_p && TREE_CODE (result) == CALL_EXPR) + suppress_warning (result, OPT_Wnonnull); + + /* In this improbable scenario, a nested function returns a VM type. + Create a TARGET_EXPR so that the call always has a LHS, much as + what the C++ FE does for functions returning non-PODs. */ + if (variably_modified_type_p (TREE_TYPE (fntype), NULL_TREE)) + { + tree tmp = create_tmp_var_raw (TREE_TYPE (fntype)); + result = build4 (TARGET_EXPR, TREE_TYPE (fntype), tmp, result, + NULL_TREE, NULL_TREE); + } + + if (VOID_TYPE_P (TREE_TYPE (result))) + { + if (TYPE_QUALS (TREE_TYPE (result)) != TYPE_UNQUALIFIED) + pedwarn (loc, 0, + "function with qualified void return type called"); + return result; + } + return require_complete_type (loc, result); +} + +/* Like build_function_call_vec, but call also resolve_overloaded_builtin. */ + +tree +c_build_function_call_vec (location_t loc, const vec &arg_loc, + tree function, vec *params, + vec *origtypes) +{ + /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (function); + + /* Convert anything with function type to a pointer-to-function. */ + if (TREE_CODE (function) == FUNCTION_DECL) + { + /* Implement type-directed function overloading for builtins. + resolve_overloaded_builtin and targetm.resolve_overloaded_builtin + handle all the type checking. The result is a complete expression + that implements this function call. */ + tree tem = resolve_overloaded_builtin (loc, function, params); + if (tem) + return tem; + } + return build_function_call_vec (loc, arg_loc, function, params, origtypes); +} + +/* Helper for convert_arguments called to convert the VALue of argument + number ARGNUM from ORIGTYPE to the corresponding parameter number + PARMNUM and TYPE. + PLOC is the location where the conversion is being performed. + FUNCTION and FUNDECL are the same as in convert_arguments. + VALTYPE is the original type of VAL before the conversion and, + for EXCESS_PRECISION_EXPR, the operand of the expression. + NPC is true if VAL represents the null pointer constant (VAL itself + will have been folded to an integer constant). + RNAME is the same as FUNCTION except in Objective C when it's + the function selector. + EXCESS_PRECISION is true when VAL was originally represented + as EXCESS_PRECISION_EXPR. + WARNOPT is the same as in convert_for_assignment. */ + +static tree +convert_argument (location_t ploc, tree function, tree fundecl, + tree type, tree origtype, tree val, tree valtype, + bool npc, tree rname, int parmnum, int argnum, + bool excess_precision, int warnopt) +{ + /* Formal parm type is specified by a function prototype. */ + + if (type == error_mark_node || !COMPLETE_TYPE_P (type)) + { + error_at (ploc, "type of formal parameter %d is incomplete", + parmnum + 1); + return val; + } + + /* Optionally warn about conversions that differ from the default + conversions. */ + if (warn_traditional_conversion || warn_traditional) + { + unsigned int formal_prec = TYPE_PRECISION (type); + + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (valtype) == REAL_TYPE) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as integer rather " + "than floating due to prototype", + argnum, rname); + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (valtype) == COMPLEX_TYPE) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as integer rather " + "than complex due to prototype", + argnum, rname); + else if (TREE_CODE (type) == COMPLEX_TYPE + && TREE_CODE (valtype) == REAL_TYPE) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as complex rather " + "than floating due to prototype", + argnum, rname); + else if (TREE_CODE (type) == REAL_TYPE + && INTEGRAL_TYPE_P (valtype)) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as floating rather " + "than integer due to prototype", + argnum, rname); + else if (TREE_CODE (type) == COMPLEX_TYPE + && INTEGRAL_TYPE_P (valtype)) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as complex rather " + "than integer due to prototype", + argnum, rname); + else if (TREE_CODE (type) == REAL_TYPE + && TREE_CODE (valtype) == COMPLEX_TYPE) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as floating rather " + "than complex due to prototype", + argnum, rname); + /* ??? At some point, messages should be written about + conversions between complex types, but that's too messy + to do now. */ + else if (TREE_CODE (type) == REAL_TYPE + && TREE_CODE (valtype) == REAL_TYPE) + { + /* Warn if any argument is passed as `float', + since without a prototype it would be `double'. */ + if (formal_prec == TYPE_PRECISION (float_type_node) + && type != dfloat32_type_node) + warning_at (ploc, 0, + "passing argument %d of %qE as % " + "rather than % due to prototype", + argnum, rname); + + /* Warn if mismatch between argument and prototype + for decimal float types. Warn of conversions with + binary float types and of precision narrowing due to + prototype. */ + else if (type != valtype + && (type == dfloat32_type_node + || type == dfloat64_type_node + || type == dfloat128_type_node + || valtype == dfloat32_type_node + || valtype == dfloat64_type_node + || valtype == dfloat128_type_node) + && (formal_prec + <= TYPE_PRECISION (valtype) + || (type == dfloat128_type_node + && (valtype + != dfloat64_type_node + && (valtype + != dfloat32_type_node))) + || (type == dfloat64_type_node + && (valtype + != dfloat32_type_node)))) + warning_at (ploc, 0, + "passing argument %d of %qE as %qT " + "rather than %qT due to prototype", + argnum, rname, type, valtype); + + } + /* Detect integer changing in width or signedness. + These warnings are only activated with + -Wtraditional-conversion, not with -Wtraditional. */ + else if (warn_traditional_conversion + && INTEGRAL_TYPE_P (type) + && INTEGRAL_TYPE_P (valtype)) + { + tree would_have_been = default_conversion (val); + tree type1 = TREE_TYPE (would_have_been); + + if (val == error_mark_node) + /* VAL could have been of incomplete type. */; + else if (TREE_CODE (type) == ENUMERAL_TYPE + && (TYPE_MAIN_VARIANT (type) + == TYPE_MAIN_VARIANT (valtype))) + /* No warning if function asks for enum + and the actual arg is that enum type. */ + ; + else if (formal_prec != TYPE_PRECISION (type1)) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE " + "with different width due to prototype", + argnum, rname); + else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1)) + ; + /* Don't complain if the formal parameter type + is an enum, because we can't tell now whether + the value was an enum--even the same enum. */ + else if (TREE_CODE (type) == ENUMERAL_TYPE) + ; + else if (TREE_CODE (val) == INTEGER_CST + && int_fits_type_p (val, type)) + /* Change in signedness doesn't matter + if a constant value is unaffected. */ + ; + /* If the value is extended from a narrower + unsigned type, it doesn't matter whether we + pass it as signed or unsigned; the value + certainly is the same either way. */ + else if (TYPE_PRECISION (valtype) < TYPE_PRECISION (type) + && TYPE_UNSIGNED (valtype)) + ; + else if (TYPE_UNSIGNED (type)) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE " + "as unsigned due to prototype", + argnum, rname); + else + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE " + "as signed due to prototype", + argnum, rname); + } + } + + /* Possibly restore an EXCESS_PRECISION_EXPR for the + sake of better warnings from convert_and_check. */ + if (excess_precision) + val = build1 (EXCESS_PRECISION_EXPR, valtype, val); + + tree parmval = convert_for_assignment (ploc, ploc, type, + val, origtype, ic_argpass, + npc, fundecl, function, + parmnum + 1, warnopt); + + if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0) + && INTEGRAL_TYPE_P (type) + && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) + parmval = default_conversion (parmval); + + return parmval; +} + +/* Convert the argument expressions in the vector VALUES + to the types in the list TYPELIST. + + If TYPELIST is exhausted, or when an element has NULL as its type, + perform the default conversions. + + ORIGTYPES is the original types of the expressions in VALUES. This + holds the type of enum values which have been converted to integral + types. It may be NULL. + + FUNCTION is a tree for the called function. It is used only for + error messages, where it is formatted with %qE. + + This is also where warnings about wrong number of args are generated. + + ARG_LOC are locations of function arguments (if any). + + Returns the actual number of arguments processed (which may be less + than the length of VALUES in some error situations), or -1 on + failure. */ + +static int +convert_arguments (location_t loc, vec arg_loc, tree typelist, + vec *values, vec *origtypes, + tree function, tree fundecl) +{ + unsigned int parmnum; + bool error_args = false; + const bool type_generic = fundecl + && lookup_attribute ("type generic", TYPE_ATTRIBUTES (TREE_TYPE (fundecl))); + bool type_generic_remove_excess_precision = false; + bool type_generic_overflow_p = false; + tree selector; + + /* Change pointer to function to the function itself for + diagnostics. */ + if (TREE_CODE (function) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) + function = TREE_OPERAND (function, 0); + + /* Handle an ObjC selector specially for diagnostics. */ + selector = objc_message_selector (); + + /* For a call to a built-in function declared without a prototype, + set to the built-in function's argument list. */ + tree builtin_typelist = NULL_TREE; + + /* For type-generic built-in functions, determine whether excess + precision should be removed (classification) or not + (comparison). */ + if (fundecl + && fndecl_built_in_p (fundecl, BUILT_IN_NORMAL)) + { + built_in_function code = DECL_FUNCTION_CODE (fundecl); + if (C_DECL_BUILTIN_PROTOTYPE (fundecl)) + { + /* For a call to a built-in function declared without a prototype + use the types of the parameters of the internal built-in to + match those of the arguments to. */ + if (tree bdecl = builtin_decl_explicit (code)) + builtin_typelist = TYPE_ARG_TYPES (TREE_TYPE (bdecl)); + } + + /* For type-generic built-in functions, determine whether excess + precision should be removed (classification) or not + (comparison). */ + if (type_generic) + switch (code) + { + case BUILT_IN_ISFINITE: + case BUILT_IN_ISINF: + case BUILT_IN_ISINF_SIGN: + case BUILT_IN_ISNAN: + case BUILT_IN_ISNORMAL: + case BUILT_IN_FPCLASSIFY: + type_generic_remove_excess_precision = true; + break; + + case BUILT_IN_ADD_OVERFLOW_P: + case BUILT_IN_SUB_OVERFLOW_P: + case BUILT_IN_MUL_OVERFLOW_P: + /* The last argument of these type-generic builtins + should not be promoted. */ + type_generic_overflow_p = true; + break; + + default: + break; + } + } + + /* Scan the given expressions (VALUES) and types (TYPELIST), producing + individual converted arguments. */ + + tree typetail, builtin_typetail, val; + for (typetail = typelist, + builtin_typetail = builtin_typelist, + parmnum = 0; + values && values->iterate (parmnum, &val); + ++parmnum) + { + /* The type of the function parameter (if it was declared with one). */ + tree type = typetail ? TREE_VALUE (typetail) : NULL_TREE; + /* The type of the built-in function parameter (if the function + is a built-in). Used to detect type incompatibilities in + calls to built-ins declared without a prototype. */ + tree builtin_type = (builtin_typetail + ? TREE_VALUE (builtin_typetail) : NULL_TREE); + /* The original type of the argument being passed to the function. */ + tree valtype = TREE_TYPE (val); + /* The called function (or function selector in Objective C). */ + tree rname = function; + int argnum = parmnum + 1; + const char *invalid_func_diag; + /* Set for EXCESS_PRECISION_EXPR arguments. */ + bool excess_precision = false; + /* The value of the argument after conversion to the type + of the function parameter it is passed to. */ + tree parmval; + /* Some __atomic_* builtins have additional hidden argument at + position 0. */ + location_t ploc + = !arg_loc.is_empty () && values->length () == arg_loc.length () + ? expansion_point_location_if_in_system_header (arg_loc[parmnum]) + : input_location; + + if (type == void_type_node) + { + if (selector) + error_at (loc, "too many arguments to method %qE", selector); + else + error_at (loc, "too many arguments to function %qE", function); + inform_declaration (fundecl); + return error_args ? -1 : (int) parmnum; + } + + if (builtin_type == void_type_node) + { + if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch, + "too many arguments to built-in function %qE " + "expecting %d", function, parmnum)) + inform_declaration (fundecl); + builtin_typetail = NULL_TREE; + } + + if (selector && argnum > 2) + { + rname = selector; + argnum -= 2; + } + + /* Determine if VAL is a null pointer constant before folding it. */ + bool npc = null_pointer_constant_p (val); + + /* If there is excess precision and a prototype, convert once to + the required type rather than converting via the semantic + type. Likewise without a prototype a float value represented + as long double should be converted once to double. But for + type-generic classification functions excess precision must + be removed here. */ + if (TREE_CODE (val) == EXCESS_PRECISION_EXPR + && (type || !type_generic || !type_generic_remove_excess_precision)) + { + val = TREE_OPERAND (val, 0); + excess_precision = true; + } + val = c_fully_fold (val, false, NULL); + STRIP_TYPE_NOPS (val); + + val = require_complete_type (ploc, val); + + /* Some floating-point arguments must be promoted to double when + no type is specified by a prototype. This applies to + arguments of type float, and to architecture-specific types + (ARM __fp16), but not to _FloatN or _FloatNx types. */ + bool promote_float_arg = false; + if (type == NULL_TREE + && TREE_CODE (valtype) == REAL_TYPE + && (TYPE_PRECISION (valtype) + <= TYPE_PRECISION (double_type_node)) + && TYPE_MAIN_VARIANT (valtype) != double_type_node + && TYPE_MAIN_VARIANT (valtype) != long_double_type_node + && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype))) + { + /* Promote this argument, unless it has a _FloatN or + _FloatNx type. */ + promote_float_arg = true; + for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++) + if (TYPE_MAIN_VARIANT (valtype) == FLOATN_NX_TYPE_NODE (i)) + { + promote_float_arg = false; + break; + } + } + + if (type != NULL_TREE) + { + tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum]; + parmval = convert_argument (ploc, function, fundecl, type, origtype, + val, valtype, npc, rname, parmnum, argnum, + excess_precision, 0); + } + else if (promote_float_arg) + { + if (type_generic) + parmval = val; + else + { + /* Convert `float' to `double'. */ + if (warn_double_promotion && !c_inhibit_evaluation_warnings) + warning_at (ploc, OPT_Wdouble_promotion, + "implicit conversion from %qT to %qT when passing " + "argument to function", + valtype, double_type_node); + parmval = convert (double_type_node, val); + } + } + else if ((excess_precision && !type_generic) + || (type_generic_overflow_p && parmnum == 2)) + /* A "double" argument with excess precision being passed + without a prototype or in variable arguments. + The last argument of __builtin_*_overflow_p should not be + promoted. */ + parmval = convert (valtype, val); + else if ((invalid_func_diag = + targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val))) + { + error (invalid_func_diag); + return -1; + } + else if (TREE_CODE (val) == ADDR_EXPR && reject_gcc_builtin (val)) + { + return -1; + } + else + /* Convert `short' and `char' to full-size `int'. */ + parmval = default_conversion (val); + + (*values)[parmnum] = parmval; + if (parmval == error_mark_node) + error_args = true; + + if (!type && builtin_type && TREE_CODE (builtin_type) != VOID_TYPE) + { + /* For a call to a built-in function declared without a prototype, + perform the conversions from the argument to the expected type + but issue warnings rather than errors for any mismatches. + Ignore the converted argument and use the PARMVAL obtained + above by applying default conversions instead. */ + tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum]; + convert_argument (ploc, function, fundecl, builtin_type, origtype, + val, valtype, npc, rname, parmnum, argnum, + excess_precision, + OPT_Wbuiltin_declaration_mismatch); + } + + if (typetail) + typetail = TREE_CHAIN (typetail); + + if (builtin_typetail) + builtin_typetail = TREE_CHAIN (builtin_typetail); + } + + gcc_assert (parmnum == vec_safe_length (values)); + + if (typetail != NULL_TREE && TREE_VALUE (typetail) != void_type_node) + { + error_at (loc, "too few arguments to function %qE", function); + inform_declaration (fundecl); + return -1; + } + + if (builtin_typetail && TREE_VALUE (builtin_typetail) != void_type_node) + { + unsigned nargs = parmnum; + for (tree t = builtin_typetail; t; t = TREE_CHAIN (t)) + ++nargs; + + if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch, + "too few arguments to built-in function %qE " + "expecting %u", function, nargs - 1)) + inform_declaration (fundecl); + } + + return error_args ? -1 : (int) parmnum; +} + +/* This is the entry point used by the parser to build unary operators + in the input. CODE, a tree_code, specifies the unary operator, and + ARG is the operand. For unary plus, the C parser currently uses + CONVERT_EXPR for code. + + LOC is the location to use for the tree generated. +*/ + +struct c_expr +parser_build_unary_op (location_t loc, enum tree_code code, struct c_expr arg) +{ + struct c_expr result; + + result.original_code = code; + result.original_type = NULL; + + if (reject_gcc_builtin (arg.value)) + { + result.value = error_mark_node; + } + else + { + result.value = build_unary_op (loc, code, arg.value, false); + + if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value)) + overflow_warning (loc, result.value, arg.value); + } + + /* We are typically called when parsing a prefix token at LOC acting on + ARG. Reflect this by updating the source range of the result to + start at LOC and end at the end of ARG. */ + set_c_expr_source_range (&result, + loc, arg.get_finish ()); + + return result; +} + +/* Returns true if TYPE is a character type, *not* including wchar_t. */ + +bool +char_type_p (tree type) +{ + return (type == char_type_node + || type == unsigned_char_type_node + || type == signed_char_type_node + || type == char16_type_node + || type == char32_type_node); +} + +/* This is the entry point used by the parser to build binary operators + in the input. CODE, a tree_code, specifies the binary operator, and + ARG1 and ARG2 are the operands. In addition to constructing the + expression, we check for operands that were written with other binary + operators in a way that is likely to confuse the user. + + LOCATION is the location of the binary operator. */ + +struct c_expr +parser_build_binary_op (location_t location, enum tree_code code, + struct c_expr arg1, struct c_expr arg2) +{ + struct c_expr result; + + enum tree_code code1 = arg1.original_code; + enum tree_code code2 = arg2.original_code; + tree type1 = (arg1.original_type + ? arg1.original_type + : TREE_TYPE (arg1.value)); + tree type2 = (arg2.original_type + ? arg2.original_type + : TREE_TYPE (arg2.value)); + + result.value = build_binary_op (location, code, + arg1.value, arg2.value, true); + result.original_code = code; + result.original_type = NULL; + + if (TREE_CODE (result.value) == ERROR_MARK) + { + set_c_expr_source_range (&result, + arg1.get_start (), + arg2.get_finish ()); + return result; + } + + if (location != UNKNOWN_LOCATION) + protected_set_expr_location (result.value, location); + + set_c_expr_source_range (&result, + arg1.get_start (), + arg2.get_finish ()); + + /* Check for cases such as x+y< used in subtraction"); + if (TREE_CODE (target_type) == FUNCTION_TYPE) + pedwarn (loc, OPT_Wpointer_arith, + "pointer to a function used in subtraction"); + + if (current_function_decl != NULL_TREE + && sanitize_flags_p (SANITIZE_POINTER_SUBTRACT)) + { + op0 = save_expr (op0); + op1 = save_expr (op1); + + tree tt = builtin_decl_explicit (BUILT_IN_ASAN_POINTER_SUBTRACT); + *instrument_expr = build_call_expr_loc (loc, tt, 2, op0, op1); + } + + /* First do the subtraction, then build the divide operator + and only convert at the very end. + Do not do default conversions in case restype is a short type. */ + + /* POINTER_DIFF_EXPR requires a signed integer type of the same size as + pointers. If some platform cannot provide that, or has a larger + ptrdiff_type to support differences larger than half the address + space, cast the pointers to some larger integer type and do the + computations in that type. */ + if (TYPE_PRECISION (inttype) > TYPE_PRECISION (TREE_TYPE (op0))) + op0 = build_binary_op (loc, MINUS_EXPR, convert (inttype, op0), + convert (inttype, op1), false); + else + { + /* Cast away qualifiers. */ + op0 = convert (c_common_type (TREE_TYPE (op0), TREE_TYPE (op0)), op0); + op1 = convert (c_common_type (TREE_TYPE (op1), TREE_TYPE (op1)), op1); + op0 = build2_loc (loc, POINTER_DIFF_EXPR, inttype, op0, op1); + } + + /* This generates an error if op1 is pointer to incomplete type. */ + if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1)))) + error_at (loc, "arithmetic on pointer to an incomplete type"); + else if (verify_type_context (loc, TCTX_POINTER_ARITH, + TREE_TYPE (TREE_TYPE (orig_op0)))) + verify_type_context (loc, TCTX_POINTER_ARITH, + TREE_TYPE (TREE_TYPE (orig_op1))); + + op1 = c_size_in_bytes (target_type); + + if (pointer_to_zero_sized_aggr_p (TREE_TYPE (orig_op1))) + error_at (loc, "arithmetic on pointer to an empty aggregate"); + + /* Divide by the size, in easiest possible way. */ + result = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype, + op0, convert (inttype, op1)); + + /* Convert to final result type if necessary. */ + return convert (restype, result); +} + +/* Expand atomic compound assignments into an appropriate sequence as + specified by the C11 standard section 6.5.16.2. + + _Atomic T1 E1 + T2 E2 + E1 op= E2 + + This sequence is used for all types for which these operations are + supported. + + In addition, built-in versions of the 'fe' prefixed routines may + need to be invoked for floating point (real, complex or vector) when + floating-point exceptions are supported. See 6.5.16.2 footnote 113. + + T1 newval; + T1 old; + T1 *addr + T2 val + fenv_t fenv + + addr = &E1; + val = (E2); + __atomic_load (addr, &old, SEQ_CST); + feholdexcept (&fenv); +loop: + newval = old op val; + if (__atomic_compare_exchange_strong (addr, &old, &newval, SEQ_CST, + SEQ_CST)) + goto done; + feclearexcept (FE_ALL_EXCEPT); + goto loop: +done: + feupdateenv (&fenv); + + The compiler will issue the __atomic_fetch_* built-in when possible, + otherwise it will generate the generic form of the atomic operations. + This requires temp(s) and has their address taken. The atomic processing + is smart enough to figure out when the size of an object can utilize + a lock-free version, and convert the built-in call to the appropriate + lock-free routine. The optimizers will then dispose of any temps that + are no longer required, and lock-free implementations are utilized as + long as there is target support for the required size. + + If the operator is NOP_EXPR, then this is a simple assignment, and + an __atomic_store is issued to perform the assignment rather than + the above loop. */ + +/* Build an atomic assignment at LOC, expanding into the proper + sequence to store LHS MODIFYCODE= RHS. Return a value representing + the result of the operation, unless RETURN_OLD_P, in which case + return the old value of LHS (this is only for postincrement and + postdecrement). */ + +static tree +build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode, + tree rhs, bool return_old_p) +{ + tree fndecl, func_call; + vec *params; + tree val, nonatomic_lhs_type, nonatomic_rhs_type, newval, newval_addr; + tree old, old_addr; + tree compound_stmt = NULL_TREE; + tree stmt, goto_stmt; + tree loop_label, loop_decl, done_label, done_decl; + + tree lhs_type = TREE_TYPE (lhs); + tree lhs_addr = build_unary_op (loc, ADDR_EXPR, lhs, false); + tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); + tree rhs_semantic_type = TREE_TYPE (rhs); + tree nonatomic_rhs_semantic_type; + tree rhs_type; + + gcc_assert (TYPE_ATOMIC (lhs_type)); + + if (return_old_p) + gcc_assert (modifycode == PLUS_EXPR || modifycode == MINUS_EXPR); + + /* Allocate enough vector items for a compare_exchange. */ + vec_alloc (params, 6); + + /* Create a compound statement to hold the sequence of statements + with a loop. */ + if (modifycode != NOP_EXPR) + { + compound_stmt = c_begin_compound_stmt (false); + + /* For consistency with build_modify_expr on non-_Atomic, + mark the lhs as read. Also, it would be very hard to match + such expressions in mark_exp_read. */ + mark_exp_read (lhs); + } + + /* Remove any excess precision (which is only present here in the + case of compound assignments). */ + if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) + { + gcc_assert (modifycode != NOP_EXPR); + rhs = TREE_OPERAND (rhs, 0); + } + rhs_type = TREE_TYPE (rhs); + + /* Fold the RHS if it hasn't already been folded. */ + if (modifycode != NOP_EXPR) + rhs = c_fully_fold (rhs, false, NULL); + + /* Remove the qualifiers for the rest of the expressions and create + the VAL temp variable to hold the RHS. */ + nonatomic_lhs_type = build_qualified_type (lhs_type, TYPE_UNQUALIFIED); + nonatomic_rhs_type = build_qualified_type (rhs_type, TYPE_UNQUALIFIED); + nonatomic_rhs_semantic_type = build_qualified_type (rhs_semantic_type, + TYPE_UNQUALIFIED); + val = create_tmp_var_raw (nonatomic_rhs_type); + TREE_ADDRESSABLE (val) = 1; + suppress_warning (val); + rhs = build4 (TARGET_EXPR, nonatomic_rhs_type, val, rhs, NULL_TREE, + NULL_TREE); + TREE_SIDE_EFFECTS (rhs) = 1; + SET_EXPR_LOCATION (rhs, loc); + if (modifycode != NOP_EXPR) + add_stmt (rhs); + + /* NOP_EXPR indicates it's a straight store of the RHS. Simply issue + an atomic_store. */ + if (modifycode == NOP_EXPR) + { + compound_stmt = rhs; + /* Build __atomic_store (&lhs, &val, SEQ_CST) */ + rhs = build_unary_op (loc, ADDR_EXPR, val, false); + fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_STORE); + params->quick_push (lhs_addr); + params->quick_push (rhs); + params->quick_push (seq_cst); + func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); + + compound_stmt = build2 (COMPOUND_EXPR, void_type_node, + compound_stmt, func_call); + + /* VAL is the value which was stored, return a COMPOUND_STMT of + the statement and that value. */ + return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt, val); + } + + /* Attempt to implement the atomic operation as an __atomic_fetch_* or + __atomic_*_fetch built-in rather than a CAS loop. atomic_bool type + isn't applicable for such builtins. ??? Do we want to handle enums? */ + if ((TREE_CODE (lhs_type) == INTEGER_TYPE || POINTER_TYPE_P (lhs_type)) + && TREE_CODE (rhs_type) == INTEGER_TYPE) + { + built_in_function fncode; + switch (modifycode) + { + case PLUS_EXPR: + case POINTER_PLUS_EXPR: + fncode = (return_old_p + ? BUILT_IN_ATOMIC_FETCH_ADD_N + : BUILT_IN_ATOMIC_ADD_FETCH_N); + break; + case MINUS_EXPR: + fncode = (return_old_p + ? BUILT_IN_ATOMIC_FETCH_SUB_N + : BUILT_IN_ATOMIC_SUB_FETCH_N); + break; + case BIT_AND_EXPR: + fncode = (return_old_p + ? BUILT_IN_ATOMIC_FETCH_AND_N + : BUILT_IN_ATOMIC_AND_FETCH_N); + break; + case BIT_IOR_EXPR: + fncode = (return_old_p + ? BUILT_IN_ATOMIC_FETCH_OR_N + : BUILT_IN_ATOMIC_OR_FETCH_N); + break; + case BIT_XOR_EXPR: + fncode = (return_old_p + ? BUILT_IN_ATOMIC_FETCH_XOR_N + : BUILT_IN_ATOMIC_XOR_FETCH_N); + break; + default: + goto cas_loop; + } + + /* We can only use "_1" through "_16" variants of the atomic fetch + built-ins. */ + unsigned HOST_WIDE_INT size = tree_to_uhwi (TYPE_SIZE_UNIT (lhs_type)); + if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) + goto cas_loop; + + /* If this is a pointer type, we need to multiply by the size of + the pointer target type. */ + if (POINTER_TYPE_P (lhs_type)) + { + if (!COMPLETE_TYPE_P (TREE_TYPE (lhs_type)) + /* ??? This would introduce -Wdiscarded-qualifiers + warning: __atomic_fetch_* expect volatile void * + type as the first argument. (Assignments between + atomic and non-atomic objects are OK.) */ + || TYPE_RESTRICT (lhs_type)) + goto cas_loop; + tree sz = TYPE_SIZE_UNIT (TREE_TYPE (lhs_type)); + rhs = fold_build2_loc (loc, MULT_EXPR, ptrdiff_type_node, + convert (ptrdiff_type_node, rhs), + convert (ptrdiff_type_node, sz)); + } + + /* Build __atomic_fetch_* (&lhs, &val, SEQ_CST), or + __atomic_*_fetch (&lhs, &val, SEQ_CST). */ + fndecl = builtin_decl_explicit (fncode); + params->quick_push (lhs_addr); + params->quick_push (rhs); + params->quick_push (seq_cst); + func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); + + newval = create_tmp_var_raw (nonatomic_lhs_type); + TREE_ADDRESSABLE (newval) = 1; + suppress_warning (newval); + rhs = build4 (TARGET_EXPR, nonatomic_lhs_type, newval, func_call, + NULL_TREE, NULL_TREE); + SET_EXPR_LOCATION (rhs, loc); + add_stmt (rhs); + + /* Finish the compound statement. */ + compound_stmt = c_end_compound_stmt (loc, compound_stmt, false); + + /* NEWVAL is the value which was stored, return a COMPOUND_STMT of + the statement and that value. */ + return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt, newval); + } + +cas_loop: + /* Create the variables and labels required for the op= form. */ + old = create_tmp_var_raw (nonatomic_lhs_type); + old_addr = build_unary_op (loc, ADDR_EXPR, old, false); + TREE_ADDRESSABLE (old) = 1; + suppress_warning (old); + + newval = create_tmp_var_raw (nonatomic_lhs_type); + newval_addr = build_unary_op (loc, ADDR_EXPR, newval, false); + TREE_ADDRESSABLE (newval) = 1; + suppress_warning (newval); + + loop_decl = create_artificial_label (loc); + loop_label = build1 (LABEL_EXPR, void_type_node, loop_decl); + + done_decl = create_artificial_label (loc); + done_label = build1 (LABEL_EXPR, void_type_node, done_decl); + + /* __atomic_load (addr, &old, SEQ_CST). */ + fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD); + params->quick_push (lhs_addr); + params->quick_push (old_addr); + params->quick_push (seq_cst); + func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); + old = build4 (TARGET_EXPR, nonatomic_lhs_type, old, func_call, NULL_TREE, + NULL_TREE); + add_stmt (old); + params->truncate (0); + + /* Create the expressions for floating-point environment + manipulation, if required. */ + bool need_fenv = (flag_trapping_math + && (FLOAT_TYPE_P (lhs_type) || FLOAT_TYPE_P (rhs_type))); + tree hold_call = NULL_TREE, clear_call = NULL_TREE, update_call = NULL_TREE; + if (need_fenv) + targetm.atomic_assign_expand_fenv (&hold_call, &clear_call, &update_call); + + if (hold_call) + add_stmt (hold_call); + + /* loop: */ + add_stmt (loop_label); + + /* newval = old + val; */ + if (rhs_type != rhs_semantic_type) + val = build1 (EXCESS_PRECISION_EXPR, nonatomic_rhs_semantic_type, val); + rhs = build_binary_op (loc, modifycode, old, val, true); + if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) + { + tree eptype = TREE_TYPE (rhs); + rhs = c_fully_fold (TREE_OPERAND (rhs, 0), false, NULL); + rhs = build1 (EXCESS_PRECISION_EXPR, eptype, rhs); + } + else + rhs = c_fully_fold (rhs, false, NULL); + rhs = convert_for_assignment (loc, UNKNOWN_LOCATION, nonatomic_lhs_type, + rhs, NULL_TREE, ic_assign, false, NULL_TREE, + NULL_TREE, 0); + if (rhs != error_mark_node) + { + rhs = build4 (TARGET_EXPR, nonatomic_lhs_type, newval, rhs, NULL_TREE, + NULL_TREE); + SET_EXPR_LOCATION (rhs, loc); + add_stmt (rhs); + } + + /* if (__atomic_compare_exchange (addr, &old, &new, false, SEQ_CST, SEQ_CST)) + goto done; */ + fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_COMPARE_EXCHANGE); + params->quick_push (lhs_addr); + params->quick_push (old_addr); + params->quick_push (newval_addr); + params->quick_push (integer_zero_node); + params->quick_push (seq_cst); + params->quick_push (seq_cst); + func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); + + goto_stmt = build1 (GOTO_EXPR, void_type_node, done_decl); + SET_EXPR_LOCATION (goto_stmt, loc); + + stmt = build3 (COND_EXPR, void_type_node, func_call, goto_stmt, NULL_TREE); + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + + if (clear_call) + add_stmt (clear_call); + + /* goto loop; */ + goto_stmt = build1 (GOTO_EXPR, void_type_node, loop_decl); + SET_EXPR_LOCATION (goto_stmt, loc); + add_stmt (goto_stmt); + + /* done: */ + add_stmt (done_label); + + if (update_call) + add_stmt (update_call); + + /* Finish the compound statement. */ + compound_stmt = c_end_compound_stmt (loc, compound_stmt, false); + + /* NEWVAL is the value that was successfully stored, return a + COMPOUND_EXPR of the statement and the appropriate value. */ + return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt, + return_old_p ? old : newval); +} + +/* Construct and perhaps optimize a tree representation + for a unary operation. CODE, a tree_code, specifies the operation + and XARG is the operand. + For any CODE other than ADDR_EXPR, NOCONVERT suppresses the default + promotions (such as from short to int). + For ADDR_EXPR, the default promotions are not applied; NOCONVERT allows + non-lvalues; this is only used to handle conversion of non-lvalue arrays + to pointers in C99. + + LOCATION is the location of the operator. */ + +tree +build_unary_op (location_t location, enum tree_code code, tree xarg, + bool noconvert) +{ + /* No default_conversion here. It causes trouble for ADDR_EXPR. */ + tree arg = xarg; + tree argtype = NULL_TREE; + enum tree_code typecode; + tree val; + tree ret = error_mark_node; + tree eptype = NULL_TREE; + const char *invalid_op_diag; + bool int_operands; + + int_operands = EXPR_INT_CONST_OPERANDS (xarg); + if (int_operands) + arg = remove_c_maybe_const_expr (arg); + + if (code != ADDR_EXPR) + arg = require_complete_type (location, arg); + + typecode = TREE_CODE (TREE_TYPE (arg)); + if (typecode == ERROR_MARK) + return error_mark_node; + if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE) + typecode = INTEGER_TYPE; + + if ((invalid_op_diag + = targetm.invalid_unary_op (code, TREE_TYPE (xarg)))) + { + error_at (location, invalid_op_diag); + return error_mark_node; + } + + if (TREE_CODE (arg) == EXCESS_PRECISION_EXPR) + { + eptype = TREE_TYPE (arg); + arg = TREE_OPERAND (arg, 0); + } + + switch (code) + { + case CONVERT_EXPR: + /* This is used for unary plus, because a CONVERT_EXPR + is enough to prevent anybody from looking inside for + associativity, but won't generate any code. */ + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE + || gnu_vector_type_p (TREE_TYPE (arg)))) + { + error_at (location, "wrong type argument to unary plus"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + arg = non_lvalue_loc (location, arg); + break; + + case NEGATE_EXPR: + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE + || gnu_vector_type_p (TREE_TYPE (arg)))) + { + error_at (location, "wrong type argument to unary minus"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + + case BIT_NOT_EXPR: + /* ~ works on integer types and non float vectors. */ + if (typecode == INTEGER_TYPE + || (gnu_vector_type_p (TREE_TYPE (arg)) + && !VECTOR_FLOAT_TYPE_P (TREE_TYPE (arg)))) + { + tree e = arg; + + /* Warn if the expression has boolean value. */ + while (TREE_CODE (e) == COMPOUND_EXPR) + e = TREE_OPERAND (e, 1); + + if ((TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE + || truth_value_p (TREE_CODE (e)))) + { + auto_diagnostic_group d; + if (warning_at (location, OPT_Wbool_operation, + "%<~%> on a boolean expression")) + { + gcc_rich_location richloc (location); + richloc.add_fixit_insert_before (location, "!"); + inform (&richloc, "did you mean to use logical not?"); + } + } + if (!noconvert) + arg = default_conversion (arg); + } + else if (typecode == COMPLEX_TYPE) + { + code = CONJ_EXPR; + pedwarn (location, OPT_Wpedantic, + "ISO C does not support %<~%> for complex conjugation"); + if (!noconvert) + arg = default_conversion (arg); + } + else + { + error_at (location, "wrong type argument to bit-complement"); + return error_mark_node; + } + break; + + case ABS_EXPR: + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE)) + { + error_at (location, "wrong type argument to abs"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + + case ABSU_EXPR: + if (!(typecode == INTEGER_TYPE)) + { + error_at (location, "wrong type argument to absu"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + + case CONJ_EXPR: + /* Conjugating a real value is a no-op, but allow it anyway. */ + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == COMPLEX_TYPE)) + { + error_at (location, "wrong type argument to conjugation"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + + case TRUTH_NOT_EXPR: + if (typecode != INTEGER_TYPE && typecode != FIXED_POINT_TYPE + && typecode != REAL_TYPE && typecode != POINTER_TYPE + && typecode != COMPLEX_TYPE) + { + error_at (location, + "wrong type argument to unary exclamation mark"); + return error_mark_node; + } + if (int_operands) + { + arg = c_objc_common_truthvalue_conversion (location, xarg); + arg = remove_c_maybe_const_expr (arg); + } + else + arg = c_objc_common_truthvalue_conversion (location, arg); + ret = invert_truthvalue_loc (location, arg); + /* If the TRUTH_NOT_EXPR has been folded, reset the location. */ + if (EXPR_P (ret) && EXPR_HAS_LOCATION (ret)) + location = EXPR_LOCATION (ret); + goto return_build_unary_op; + + case REALPART_EXPR: + case IMAGPART_EXPR: + ret = build_real_imag_expr (location, code, arg); + if (ret == error_mark_node) + return error_mark_node; + if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE) + eptype = TREE_TYPE (eptype); + goto return_build_unary_op; + + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + + if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR) + { + tree inner = build_unary_op (location, code, + C_MAYBE_CONST_EXPR_EXPR (arg), + noconvert); + if (inner == error_mark_node) + return error_mark_node; + ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner), + C_MAYBE_CONST_EXPR_PRE (arg), inner); + gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg)); + C_MAYBE_CONST_EXPR_NON_CONST (ret) = 1; + goto return_build_unary_op; + } + + /* Complain about anything that is not a true lvalue. In + Objective-C, skip this check for property_refs. */ + if (!objc_is_property_ref (arg) + && !lvalue_or_else (location, + arg, ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? lv_increment + : lv_decrement))) + return error_mark_node; + + if (warn_cxx_compat && TREE_CODE (TREE_TYPE (arg)) == ENUMERAL_TYPE) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + warning_at (location, OPT_Wc___compat, + "increment of enumeration value is invalid in C++"); + else + warning_at (location, OPT_Wc___compat, + "decrement of enumeration value is invalid in C++"); + } + + if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + warning_at (location, OPT_Wbool_operation, + "increment of a boolean expression"); + else + warning_at (location, OPT_Wbool_operation, + "decrement of a boolean expression"); + } + + /* Ensure the argument is fully folded inside any SAVE_EXPR. */ + arg = c_fully_fold (arg, false, NULL, true); + + bool atomic_op; + atomic_op = really_atomic_lvalue (arg); + + /* Increment or decrement the real part of the value, + and don't change the imaginary part. */ + if (typecode == COMPLEX_TYPE) + { + tree real, imag; + + pedwarn (location, OPT_Wpedantic, + "ISO C does not support %<++%> and %<--%> on complex types"); + + if (!atomic_op) + { + arg = stabilize_reference (arg); + real = build_unary_op (EXPR_LOCATION (arg), REALPART_EXPR, arg, + true); + imag = build_unary_op (EXPR_LOCATION (arg), IMAGPART_EXPR, arg, + true); + real = build_unary_op (EXPR_LOCATION (arg), code, real, true); + if (real == error_mark_node || imag == error_mark_node) + return error_mark_node; + ret = build2 (COMPLEX_EXPR, TREE_TYPE (arg), + real, imag); + goto return_build_unary_op; + } + } + + /* Report invalid types. */ + + if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE + && typecode != INTEGER_TYPE && typecode != REAL_TYPE + && typecode != COMPLEX_TYPE + && !gnu_vector_type_p (TREE_TYPE (arg))) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + error_at (location, "wrong type argument to increment"); + else + error_at (location, "wrong type argument to decrement"); + + return error_mark_node; + } + + { + tree inc; + + argtype = TREE_TYPE (arg); + + /* Compute the increment. */ + + if (typecode == POINTER_TYPE) + { + /* If pointer target is an incomplete type, + we just cannot know how to do the arithmetic. */ + if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (argtype))) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + error_at (location, + "increment of pointer to an incomplete type %qT", + TREE_TYPE (argtype)); + else + error_at (location, + "decrement of pointer to an incomplete type %qT", + TREE_TYPE (argtype)); + } + else if (TREE_CODE (TREE_TYPE (argtype)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (argtype)) == VOID_TYPE) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + pedwarn (location, OPT_Wpointer_arith, + "wrong type argument to increment"); + else + pedwarn (location, OPT_Wpointer_arith, + "wrong type argument to decrement"); + } + else + verify_type_context (location, TCTX_POINTER_ARITH, + TREE_TYPE (argtype)); + + inc = c_size_in_bytes (TREE_TYPE (argtype)); + inc = convert_to_ptrofftype_loc (location, inc); + } + else if (FRACT_MODE_P (TYPE_MODE (argtype))) + { + /* For signed fract types, we invert ++ to -- or + -- to ++, and change inc from 1 to -1, because + it is not possible to represent 1 in signed fract constants. + For unsigned fract types, the result always overflows and + we get an undefined (original) or the maximum value. */ + if (code == PREINCREMENT_EXPR) + code = PREDECREMENT_EXPR; + else if (code == PREDECREMENT_EXPR) + code = PREINCREMENT_EXPR; + else if (code == POSTINCREMENT_EXPR) + code = POSTDECREMENT_EXPR; + else /* code == POSTDECREMENT_EXPR */ + code = POSTINCREMENT_EXPR; + + inc = integer_minus_one_node; + inc = convert (argtype, inc); + } + else + { + inc = VECTOR_TYPE_P (argtype) + ? build_one_cst (argtype) + : integer_one_node; + inc = convert (argtype, inc); + } + + /* If 'arg' is an Objective-C PROPERTY_REF expression, then we + need to ask Objective-C to build the increment or decrement + expression for it. */ + if (objc_is_property_ref (arg)) + return objc_build_incr_expr_for_property_ref (location, code, + arg, inc); + + /* Report a read-only lvalue. */ + if (TYPE_READONLY (argtype)) + { + readonly_error (location, arg, + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? lv_increment : lv_decrement)); + return error_mark_node; + } + else if (TREE_READONLY (arg)) + readonly_warning (arg, + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? lv_increment : lv_decrement)); + + /* If the argument is atomic, use the special code sequences for + atomic compound assignment. */ + if (atomic_op) + { + arg = stabilize_reference (arg); + ret = build_atomic_assign (location, arg, + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? PLUS_EXPR + : MINUS_EXPR), + (FRACT_MODE_P (TYPE_MODE (argtype)) + ? inc + : integer_one_node), + (code == POSTINCREMENT_EXPR + || code == POSTDECREMENT_EXPR)); + goto return_build_unary_op; + } + + if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + val = boolean_increment (code, arg); + else + val = build2 (code, TREE_TYPE (arg), arg, inc); + TREE_SIDE_EFFECTS (val) = 1; + ret = val; + goto return_build_unary_op; + } + + case ADDR_EXPR: + /* Note that this operation never does default_conversion. */ + + /* The operand of unary '&' must be an lvalue (which excludes + expressions of type void), or, in C99, the result of a [] or + unary '*' operator. */ + if (VOID_TYPE_P (TREE_TYPE (arg)) + && TYPE_QUALS (TREE_TYPE (arg)) == TYPE_UNQUALIFIED + && (!INDIRECT_REF_P (arg) || !flag_isoc99)) + pedwarn (location, 0, "taking address of expression of type %"); + + /* Let &* cancel out to simplify resulting code. */ + if (INDIRECT_REF_P (arg)) + { + /* Don't let this be an lvalue. */ + if (lvalue_p (TREE_OPERAND (arg, 0))) + return non_lvalue_loc (location, TREE_OPERAND (arg, 0)); + ret = TREE_OPERAND (arg, 0); + goto return_build_unary_op; + } + + /* Anything not already handled and not a true memory reference + or a non-lvalue array is an error. */ + if (typecode != FUNCTION_TYPE && !noconvert + && !lvalue_or_else (location, arg, lv_addressof)) + return error_mark_node; + + /* Move address operations inside C_MAYBE_CONST_EXPR to simplify + folding later. */ + if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR) + { + tree inner = build_unary_op (location, code, + C_MAYBE_CONST_EXPR_EXPR (arg), + noconvert); + ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner), + C_MAYBE_CONST_EXPR_PRE (arg), inner); + gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg)); + C_MAYBE_CONST_EXPR_NON_CONST (ret) + = C_MAYBE_CONST_EXPR_NON_CONST (arg); + goto return_build_unary_op; + } + + /* Ordinary case; arg is a COMPONENT_REF or a decl. */ + argtype = TREE_TYPE (arg); + + /* If the lvalue is const or volatile, merge that into the type + to which the address will point. This is only needed + for function types. */ + if ((DECL_P (arg) || REFERENCE_CLASS_P (arg)) + && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)) + && TREE_CODE (argtype) == FUNCTION_TYPE) + { + int orig_quals = TYPE_QUALS (strip_array_types (argtype)); + int quals = orig_quals; + + if (TREE_READONLY (arg)) + quals |= TYPE_QUAL_CONST; + if (TREE_THIS_VOLATILE (arg)) + quals |= TYPE_QUAL_VOLATILE; + + argtype = c_build_qualified_type (argtype, quals); + } + + switch (TREE_CODE (arg)) + { + case COMPONENT_REF: + if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1))) + { + error_at (location, "cannot take address of bit-field %qD", + TREE_OPERAND (arg, 1)); + return error_mark_node; + } + + /* fall through */ + + case ARRAY_REF: + if (TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (TREE_OPERAND (arg, 0)))) + { + if (!AGGREGATE_TYPE_P (TREE_TYPE (arg)) + && !POINTER_TYPE_P (TREE_TYPE (arg)) + && !VECTOR_TYPE_P (TREE_TYPE (arg))) + { + error_at (location, "cannot take address of scalar with " + "reverse storage order"); + return error_mark_node; + } + + if (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE + && TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (arg))) + warning_at (location, OPT_Wscalar_storage_order, + "address of array with reverse scalar storage " + "order requested"); + } + + default: + break; + } + + if (!c_mark_addressable (arg)) + return error_mark_node; + + gcc_assert (TREE_CODE (arg) != COMPONENT_REF + || !DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1))); + + argtype = build_pointer_type (argtype); + + /* ??? Cope with user tricks that amount to offsetof. Delete this + when we have proper support for integer constant expressions. */ + val = get_base_address (arg); + if (val && INDIRECT_REF_P (val) + && TREE_CONSTANT (TREE_OPERAND (val, 0))) + { + ret = fold_offsetof (arg, argtype); + goto return_build_unary_op; + } + + val = build1 (ADDR_EXPR, argtype, arg); + + ret = val; + goto return_build_unary_op; + + default: + gcc_unreachable (); + } + + if (argtype == NULL_TREE) + argtype = TREE_TYPE (arg); + if (TREE_CODE (arg) == INTEGER_CST) + ret = (require_constant_value + ? fold_build1_initializer_loc (location, code, argtype, arg) + : fold_build1_loc (location, code, argtype, arg)); + else + ret = build1 (code, argtype, arg); + return_build_unary_op: + gcc_assert (ret != error_mark_node); + if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret) + && !(TREE_CODE (xarg) == INTEGER_CST && !TREE_OVERFLOW (xarg))) + ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret); + else if (TREE_CODE (ret) != INTEGER_CST && int_operands) + ret = note_integer_operands (ret); + if (eptype) + ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret); + protected_set_expr_location (ret, location); + return ret; +} + +/* Return nonzero if REF is an lvalue valid for this language. + Lvalues can be assigned, unless their type has TYPE_READONLY. + Lvalues can have their address taken, unless they have C_DECL_REGISTER. */ + +bool +lvalue_p (const_tree ref) +{ + const enum tree_code code = TREE_CODE (ref); + + switch (code) + { + case REALPART_EXPR: + case IMAGPART_EXPR: + case COMPONENT_REF: + return lvalue_p (TREE_OPERAND (ref, 0)); + + case C_MAYBE_CONST_EXPR: + return lvalue_p (TREE_OPERAND (ref, 1)); + + case COMPOUND_LITERAL_EXPR: + case STRING_CST: + return true; + + case MEM_REF: + case TARGET_MEM_REF: + /* MEM_REFs can appear from -fgimple parsing or folding, so allow them + here as well. */ + case INDIRECT_REF: + case ARRAY_REF: + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + case ERROR_MARK: + return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE); + + case BIND_EXPR: + return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE; + + default: + return false; + } +} + +/* Give a warning for storing in something that is read-only in GCC + terms but not const in ISO C terms. */ + +static void +readonly_warning (tree arg, enum lvalue_use use) +{ + switch (use) + { + case lv_assign: + warning (0, "assignment of read-only location %qE", arg); + break; + case lv_increment: + warning (0, "increment of read-only location %qE", arg); + break; + case lv_decrement: + warning (0, "decrement of read-only location %qE", arg); + break; + default: + gcc_unreachable (); + } + return; +} + + +/* Return nonzero if REF is an lvalue valid for this language; + otherwise, print an error message and return zero. USE says + how the lvalue is being used and so selects the error message. + LOCATION is the location at which any error should be reported. */ + +static int +lvalue_or_else (location_t loc, const_tree ref, enum lvalue_use use) +{ + int win = lvalue_p (ref); + + if (!win) + lvalue_error (loc, use); + + return win; +} + +/* Mark EXP saying that we need to be able to take the + address of it; it should not be allocated in a register. + Returns true if successful. ARRAY_REF_P is true if this + is for ARRAY_REF construction - in that case we don't want + to look through VIEW_CONVERT_EXPR from VECTOR_TYPE to ARRAY_TYPE, + it is fine to use ARRAY_REFs for vector subscripts on vector + register variables. */ + +bool +c_mark_addressable (tree exp, bool array_ref_p) +{ + tree x = exp; + + while (1) + switch (TREE_CODE (x)) + { + case VIEW_CONVERT_EXPR: + if (array_ref_p + && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE + && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0)))) + return true; + x = TREE_OPERAND (x, 0); + break; + + case COMPONENT_REF: + if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1))) + { + error ("cannot take address of bit-field %qD", + TREE_OPERAND (x, 1)); + return false; + } + /* FALLTHRU */ + case ADDR_EXPR: + case ARRAY_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + x = TREE_OPERAND (x, 0); + break; + + case COMPOUND_LITERAL_EXPR: + TREE_ADDRESSABLE (x) = 1; + TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (x)) = 1; + return true; + + case CONSTRUCTOR: + TREE_ADDRESSABLE (x) = 1; + return true; + + case VAR_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + if (C_DECL_REGISTER (x) + && DECL_NONLOCAL (x)) + { + if (TREE_PUBLIC (x) || is_global_var (x)) + { + error + ("global register variable %qD used in nested function", x); + return false; + } + pedwarn (input_location, 0, "register variable %qD used in nested function", x); + } + else if (C_DECL_REGISTER (x)) + { + if (TREE_PUBLIC (x) || is_global_var (x)) + error ("address of global register variable %qD requested", x); + else + error ("address of register variable %qD requested", x); + return false; + } + + /* FALLTHRU */ + case FUNCTION_DECL: + TREE_ADDRESSABLE (x) = 1; + /* FALLTHRU */ + default: + return true; + } +} + +/* Convert EXPR to TYPE, warning about conversion problems with + constants. SEMANTIC_TYPE is the type this conversion would use + without excess precision. If SEMANTIC_TYPE is NULL, this function + is equivalent to convert_and_check. This function is a wrapper that + handles conversions that may be different than + the usual ones because of excess precision. */ + +static tree +ep_convert_and_check (location_t loc, tree type, tree expr, + tree semantic_type) +{ + if (TREE_TYPE (expr) == type) + return expr; + + /* For C11, integer conversions may have results with excess + precision. */ + if (flag_isoc11 || !semantic_type) + return convert_and_check (loc, type, expr); + + if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE + && TREE_TYPE (expr) != semantic_type) + { + /* For integers, we need to check the real conversion, not + the conversion to the excess precision type. */ + expr = convert_and_check (loc, semantic_type, expr); + } + /* Result type is the excess precision type, which should be + large enough, so do not check. */ + return convert (type, expr); +} + +/* If EXPR refers to a built-in declared without a prototype returns + the actual type of the built-in and, if non-null, set *BLTIN to + a pointer to the built-in. Otherwise return the type of EXPR + and clear *BLTIN if non-null. */ + +static tree +type_or_builtin_type (tree expr, tree *bltin = NULL) +{ + tree dummy; + if (!bltin) + bltin = &dummy; + + *bltin = NULL_TREE; + + tree type = TREE_TYPE (expr); + if (TREE_CODE (expr) != ADDR_EXPR) + return type; + + tree oper = TREE_OPERAND (expr, 0); + if (!DECL_P (oper) + || TREE_CODE (oper) != FUNCTION_DECL + || !fndecl_built_in_p (oper, BUILT_IN_NORMAL)) + return type; + + built_in_function code = DECL_FUNCTION_CODE (oper); + if (!C_DECL_BUILTIN_PROTOTYPE (oper)) + return type; + + if ((*bltin = builtin_decl_implicit (code))) + type = build_pointer_type (TREE_TYPE (*bltin)); + + return type; +} + +/* Build and return a conditional expression IFEXP ? OP1 : OP2. If + IFEXP_BCP then the condition is a call to __builtin_constant_p, and + if folded to an integer constant then the unselected half may + contain arbitrary operations not normally permitted in constant + expressions. Set the location of the expression to LOC. */ + +tree +build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, + tree op1, tree op1_original_type, location_t op1_loc, + tree op2, tree op2_original_type, location_t op2_loc) +{ + tree type1; + tree type2; + enum tree_code code1; + enum tree_code code2; + tree result_type = NULL; + tree semantic_result_type = NULL; + tree orig_op1 = op1, orig_op2 = op2; + bool int_const, op1_int_operands, op2_int_operands, int_operands; + bool ifexp_int_operands; + tree ret; + + op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1); + if (op1_int_operands) + op1 = remove_c_maybe_const_expr (op1); + op2_int_operands = EXPR_INT_CONST_OPERANDS (orig_op2); + if (op2_int_operands) + op2 = remove_c_maybe_const_expr (op2); + ifexp_int_operands = EXPR_INT_CONST_OPERANDS (ifexp); + if (ifexp_int_operands) + ifexp = remove_c_maybe_const_expr (ifexp); + + /* Promote both alternatives. */ + + if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE) + op1 = default_conversion (op1); + if (TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE) + op2 = default_conversion (op2); + + if (TREE_CODE (ifexp) == ERROR_MARK + || TREE_CODE (TREE_TYPE (op1)) == ERROR_MARK + || TREE_CODE (TREE_TYPE (op2)) == ERROR_MARK) + return error_mark_node; + + tree bltin1 = NULL_TREE; + tree bltin2 = NULL_TREE; + type1 = type_or_builtin_type (op1, &bltin1); + code1 = TREE_CODE (type1); + type2 = type_or_builtin_type (op2, &bltin2); + code2 = TREE_CODE (type2); + + if (code1 == POINTER_TYPE && reject_gcc_builtin (op1)) + return error_mark_node; + + if (code2 == POINTER_TYPE && reject_gcc_builtin (op2)) + return error_mark_node; + + /* C90 does not permit non-lvalue arrays in conditional expressions. + In C99 they will be pointers by now. */ + if (code1 == ARRAY_TYPE || code2 == ARRAY_TYPE) + { + error_at (colon_loc, "non-lvalue array in conditional expression"); + return error_mark_node; + } + + if ((TREE_CODE (op1) == EXCESS_PRECISION_EXPR + || TREE_CODE (op2) == EXCESS_PRECISION_EXPR) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == COMPLEX_TYPE) + && (code2 == INTEGER_TYPE || code2 == REAL_TYPE + || code2 == COMPLEX_TYPE)) + { + semantic_result_type = c_common_type (type1, type2); + if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR) + { + op1 = TREE_OPERAND (op1, 0); + type1 = TREE_TYPE (op1); + gcc_assert (TREE_CODE (type1) == code1); + } + if (TREE_CODE (op2) == EXCESS_PRECISION_EXPR) + { + op2 = TREE_OPERAND (op2, 0); + type2 = TREE_TYPE (op2); + gcc_assert (TREE_CODE (type2) == code2); + } + } + + if (warn_cxx_compat) + { + tree t1 = op1_original_type ? op1_original_type : TREE_TYPE (orig_op1); + tree t2 = op2_original_type ? op2_original_type : TREE_TYPE (orig_op2); + + if (TREE_CODE (t1) == ENUMERAL_TYPE + && TREE_CODE (t2) == ENUMERAL_TYPE + && TYPE_MAIN_VARIANT (t1) != TYPE_MAIN_VARIANT (t2)) + warning_at (colon_loc, OPT_Wc___compat, + ("different enum types in conditional is " + "invalid in C++: %qT vs %qT"), + t1, t2); + } + + /* Quickly detect the usual case where op1 and op2 have the same type + after promotion. */ + if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)) + { + if (type1 == type2) + result_type = type1; + else + result_type = TYPE_MAIN_VARIANT (type1); + } + else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == COMPLEX_TYPE) + && (code2 == INTEGER_TYPE || code2 == REAL_TYPE + || code2 == COMPLEX_TYPE)) + { + /* In C11, a conditional expression between a floating-point + type and an integer type should convert the integer type to + the evaluation format of the floating-point type, with + possible excess precision. */ + tree eptype1 = type1; + tree eptype2 = type2; + if (flag_isoc11) + { + tree eptype; + if (ANY_INTEGRAL_TYPE_P (type1) + && (eptype = excess_precision_type (type2)) != NULL_TREE) + { + eptype2 = eptype; + if (!semantic_result_type) + semantic_result_type = c_common_type (type1, type2); + } + else if (ANY_INTEGRAL_TYPE_P (type2) + && (eptype = excess_precision_type (type1)) != NULL_TREE) + { + eptype1 = eptype; + if (!semantic_result_type) + semantic_result_type = c_common_type (type1, type2); + } + } + result_type = c_common_type (eptype1, eptype2); + if (result_type == error_mark_node) + return error_mark_node; + do_warn_double_promotion (result_type, type1, type2, + "implicit conversion from %qT to %qT to " + "match other result of conditional", + colon_loc); + + /* If -Wsign-compare, warn here if type1 and type2 have + different signedness. We'll promote the signed to unsigned + and later code won't know it used to be different. + Do this check on the original types, so that explicit casts + will be considered, but default promotions won't. */ + if (c_inhibit_evaluation_warnings == 0) + { + int unsigned_op1 = TYPE_UNSIGNED (TREE_TYPE (orig_op1)); + int unsigned_op2 = TYPE_UNSIGNED (TREE_TYPE (orig_op2)); + + if (unsigned_op1 ^ unsigned_op2) + { + bool ovf; + + /* Do not warn if the result type is signed, since the + signed type will only be chosen if it can represent + all the values of the unsigned type. */ + if (!TYPE_UNSIGNED (result_type)) + /* OK */; + else + { + bool op1_maybe_const = true; + bool op2_maybe_const = true; + + /* Do not warn if the signed quantity is an + unsuffixed integer literal (or some static + constant expression involving such literals) and + it is non-negative. This warning requires the + operands to be folded for best results, so do + that folding in this case even without + warn_sign_compare to avoid warning options + possibly affecting code generation. */ + c_inhibit_evaluation_warnings + += (ifexp == truthvalue_false_node); + op1 = c_fully_fold (op1, require_constant_value, + &op1_maybe_const); + c_inhibit_evaluation_warnings + -= (ifexp == truthvalue_false_node); + + c_inhibit_evaluation_warnings + += (ifexp == truthvalue_true_node); + op2 = c_fully_fold (op2, require_constant_value, + &op2_maybe_const); + c_inhibit_evaluation_warnings + -= (ifexp == truthvalue_true_node); + + if (warn_sign_compare) + { + if ((unsigned_op2 + && tree_expr_nonnegative_warnv_p (op1, &ovf)) + || (unsigned_op1 + && tree_expr_nonnegative_warnv_p (op2, &ovf))) + /* OK */; + else if (unsigned_op2) + warning_at (op1_loc, OPT_Wsign_compare, + "operand of % changes signedness from " + "%qT to %qT due to unsignedness of other " + "operand", TREE_TYPE (orig_op1), + TREE_TYPE (orig_op2)); + else + warning_at (op2_loc, OPT_Wsign_compare, + "operand of % changes signedness from " + "%qT to %qT due to unsignedness of other " + "operand", TREE_TYPE (orig_op2), + TREE_TYPE (orig_op1)); + } + if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST) + op1 = c_wrap_maybe_const (op1, !op1_maybe_const); + if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST) + op2 = c_wrap_maybe_const (op2, !op2_maybe_const); + } + } + } + } + else if (code1 == VOID_TYPE || code2 == VOID_TYPE) + { + if (code1 != VOID_TYPE || code2 != VOID_TYPE) + pedwarn (colon_loc, OPT_Wpedantic, + "ISO C forbids conditional expr with only one void side"); + result_type = void_type_node; + } + else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE) + { + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); + addr_space_t as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2)); + addr_space_t as_common; + + if (comp_target_types (colon_loc, type1, type2)) + result_type = common_pointer_type (type1, type2); + else if (null_pointer_constant_p (orig_op1)) + result_type = type2; + else if (null_pointer_constant_p (orig_op2)) + result_type = type1; + else if (!addr_space_superset (as1, as2, &as_common)) + { + error_at (colon_loc, "pointers to disjoint address spaces " + "used in conditional expression"); + return error_mark_node; + } + else if ((VOID_TYPE_P (TREE_TYPE (type1)) + && !TYPE_ATOMIC (TREE_TYPE (type1))) + || (VOID_TYPE_P (TREE_TYPE (type2)) + && !TYPE_ATOMIC (TREE_TYPE (type2)))) + { + tree t1 = TREE_TYPE (type1); + tree t2 = TREE_TYPE (type2); + if (!(VOID_TYPE_P (t1) + && !TYPE_ATOMIC (t1))) + { + /* roles are swapped */ + t1 = t2; + t2 = TREE_TYPE (type1); + } + tree t2_stripped = strip_array_types (t2); + if ((TREE_CODE (t2) == ARRAY_TYPE) + && (TYPE_QUALS (t2_stripped) & ~TYPE_QUALS (t1))) + { + if (!flag_isoc2x) + warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers, + "pointer to array loses qualifier " + "in conditional expression"); + else if (warn_c11_c2x_compat > 0) + warning_at (colon_loc, OPT_Wc11_c2x_compat, + "pointer to array loses qualifier " + "in conditional expression in ISO C before C2X"); + } + if (TREE_CODE (t2) == FUNCTION_TYPE) + pedwarn (colon_loc, OPT_Wpedantic, + "ISO C forbids conditional expr between " + "% and function pointer"); + /* for array, use qualifiers of element type */ + if (flag_isoc2x) + t2 = t2_stripped; + result_type = build_pointer_type (qualify_type (t1, t2)); + } + /* Objective-C pointer comparisons are a bit more lenient. */ + else if (objc_have_common_type (type1, type2, -3, NULL_TREE)) + result_type = objc_common_type (type1, type2); + else + { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + if (bltin1 && bltin2) + warning_at (colon_loc, OPT_Wincompatible_pointer_types, + "pointer type mismatch between %qT and %qT " + "of %qD and %qD in conditional expression", + type1, type2, bltin1, bltin2); + else + pedwarn (colon_loc, 0, + "pointer type mismatch in conditional expression"); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); + } + } + else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) + { + if (!null_pointer_constant_p (orig_op2)) + pedwarn (colon_loc, 0, + "pointer/integer type mismatch in conditional expression"); + else + { + op2 = null_pointer_node; + } + result_type = type1; + } + else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + if (!null_pointer_constant_p (orig_op1)) + pedwarn (colon_loc, 0, + "pointer/integer type mismatch in conditional expression"); + else + { + op1 = null_pointer_node; + } + result_type = type2; + } + + if (!result_type) + { + if (flag_cond_mismatch) + result_type = void_type_node; + else + { + error_at (colon_loc, "type mismatch in conditional expression"); + return error_mark_node; + } + } + + /* Merge const and volatile flags of the incoming types. */ + result_type + = build_type_variant (result_type, + TYPE_READONLY (type1) || TYPE_READONLY (type2), + TYPE_VOLATILE (type1) || TYPE_VOLATILE (type2)); + + op1 = ep_convert_and_check (colon_loc, result_type, op1, + semantic_result_type); + op2 = ep_convert_and_check (colon_loc, result_type, op2, + semantic_result_type); + + if (ifexp_bcp && ifexp == truthvalue_true_node) + { + op2_int_operands = true; + op1 = c_fully_fold (op1, require_constant_value, NULL); + } + if (ifexp_bcp && ifexp == truthvalue_false_node) + { + op1_int_operands = true; + op2 = c_fully_fold (op2, require_constant_value, NULL); + } + int_const = int_operands = (ifexp_int_operands + && op1_int_operands + && op2_int_operands); + if (int_operands) + { + int_const = ((ifexp == truthvalue_true_node + && TREE_CODE (orig_op1) == INTEGER_CST + && !TREE_OVERFLOW (orig_op1)) + || (ifexp == truthvalue_false_node + && TREE_CODE (orig_op2) == INTEGER_CST + && !TREE_OVERFLOW (orig_op2))); + } + + /* Need to convert condition operand into a vector mask. */ + if (VECTOR_TYPE_P (TREE_TYPE (ifexp))) + { + tree vectype = TREE_TYPE (ifexp); + tree elem_type = TREE_TYPE (vectype); + tree zero = build_int_cst (elem_type, 0); + tree zero_vec = build_vector_from_val (vectype, zero); + tree cmp_type = truth_type_for (vectype); + ifexp = build2 (NE_EXPR, cmp_type, ifexp, zero_vec); + } + + if (int_const || (ifexp_bcp && TREE_CODE (ifexp) == INTEGER_CST)) + ret = fold_build3_loc (colon_loc, COND_EXPR, result_type, ifexp, op1, op2); + else + { + if (int_operands) + { + /* Use c_fully_fold here, since C_MAYBE_CONST_EXPR might be + nested inside of the expression. */ + op1 = c_fully_fold (op1, false, NULL); + op2 = c_fully_fold (op2, false, NULL); + } + ret = build3 (COND_EXPR, result_type, ifexp, op1, op2); + if (int_operands) + ret = note_integer_operands (ret); + } + if (semantic_result_type) + ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret); + + protected_set_expr_location (ret, colon_loc); + + /* If the OP1 and OP2 are the same and don't have side-effects, + warn here, because the COND_EXPR will be turned into OP1. */ + if (warn_duplicated_branches + && TREE_CODE (ret) == COND_EXPR + && (op1 == op2 || operand_equal_p (op1, op2, OEP_ADDRESS_OF_SAME_FIELD))) + warning_at (EXPR_LOCATION (ret), OPT_Wduplicated_branches, + "this condition has identical branches"); + + return ret; +} + +/* EXPR is an expression, location LOC, whose result is discarded. + Warn if it is a call to a nodiscard function (or a COMPOUND_EXPR + whose right-hand operand is such a call, possibly recursively). */ + +static void +maybe_warn_nodiscard (location_t loc, tree expr) +{ + if (VOID_TYPE_P (TREE_TYPE (expr))) + return; + while (TREE_CODE (expr) == COMPOUND_EXPR) + { + expr = TREE_OPERAND (expr, 1); + if (EXPR_HAS_LOCATION (expr)) + loc = EXPR_LOCATION (expr); + } + if (TREE_CODE (expr) != CALL_EXPR) + return; + tree fn = CALL_EXPR_FN (expr); + if (!fn) + return; + tree attr; + if (TREE_CODE (fn) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL + && (attr = lookup_attribute ("nodiscard", + DECL_ATTRIBUTES (TREE_OPERAND (fn, 0))))) + { + fn = TREE_OPERAND (fn, 0); + tree args = TREE_VALUE (attr); + if (args) + args = TREE_VALUE (args); + auto_diagnostic_group d; + int warned; + if (args) + warned = warning_at (loc, OPT_Wunused_result, + "ignoring return value of %qD, declared with " + "attribute %: %E", fn, args); + else + warned = warning_at (loc, OPT_Wunused_result, + "ignoring return value of %qD, declared with " + "attribute %", fn); + if (warned) + inform (DECL_SOURCE_LOCATION (fn), "declared here"); + } + else + { + tree rettype = TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))); + attr = lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype)); + if (!attr) + return; + tree args = TREE_VALUE (attr); + if (args) + args = TREE_VALUE (args); + auto_diagnostic_group d; + int warned; + if (args) + warned = warning_at (loc, OPT_Wunused_result, + "ignoring return value of type %qT, declared " + "with attribute %: %E", + rettype, args); + else + warned = warning_at (loc, OPT_Wunused_result, + "ignoring return value of type %qT, declared " + "with attribute %", rettype); + if (warned) + { + if (TREE_CODE (fn) == ADDR_EXPR) + { + fn = TREE_OPERAND (fn, 0); + if (TREE_CODE (fn) == FUNCTION_DECL) + inform (DECL_SOURCE_LOCATION (fn), + "in call to %qD, declared here", fn); + } + } + } +} + +/* Return a compound expression that performs two expressions and + returns the value of the second of them. + + LOC is the location of the COMPOUND_EXPR. */ + +tree +build_compound_expr (location_t loc, tree expr1, tree expr2) +{ + bool expr1_int_operands, expr2_int_operands; + tree eptype = NULL_TREE; + tree ret; + + expr1_int_operands = EXPR_INT_CONST_OPERANDS (expr1); + if (expr1_int_operands) + expr1 = remove_c_maybe_const_expr (expr1); + expr2_int_operands = EXPR_INT_CONST_OPERANDS (expr2); + if (expr2_int_operands) + expr2 = remove_c_maybe_const_expr (expr2); + + if (TREE_CODE (expr1) == EXCESS_PRECISION_EXPR) + expr1 = TREE_OPERAND (expr1, 0); + if (TREE_CODE (expr2) == EXCESS_PRECISION_EXPR) + { + eptype = TREE_TYPE (expr2); + expr2 = TREE_OPERAND (expr2, 0); + } + + if (!TREE_SIDE_EFFECTS (expr1)) + { + /* The left-hand operand of a comma expression is like an expression + statement: with -Wunused, we should warn if it doesn't have + any side-effects, unless it was explicitly cast to (void). */ + if (warn_unused_value) + { + if (VOID_TYPE_P (TREE_TYPE (expr1)) + && CONVERT_EXPR_P (expr1)) + ; /* (void) a, b */ + else if (VOID_TYPE_P (TREE_TYPE (expr1)) + && TREE_CODE (expr1) == COMPOUND_EXPR + && CONVERT_EXPR_P (TREE_OPERAND (expr1, 1))) + ; /* (void) a, (void) b, c */ + else + warning_at (loc, OPT_Wunused_value, + "left-hand operand of comma expression has no effect"); + } + } + else if (TREE_CODE (expr1) == COMPOUND_EXPR + && warn_unused_value) + { + tree r = expr1; + location_t cloc = loc; + while (TREE_CODE (r) == COMPOUND_EXPR) + { + if (EXPR_HAS_LOCATION (r)) + cloc = EXPR_LOCATION (r); + r = TREE_OPERAND (r, 1); + } + if (!TREE_SIDE_EFFECTS (r) + && !VOID_TYPE_P (TREE_TYPE (r)) + && !CONVERT_EXPR_P (r)) + warning_at (cloc, OPT_Wunused_value, + "right-hand operand of comma expression has no effect"); + } + + /* With -Wunused, we should also warn if the left-hand operand does have + side-effects, but computes a value which is not used. For example, in + `foo() + bar(), baz()' the result of the `+' operator is not used, + so we should issue a warning. */ + else if (warn_unused_value) + warn_if_unused_value (expr1, loc); + + maybe_warn_nodiscard (loc, expr1); + + if (expr2 == error_mark_node) + return error_mark_node; + + ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2); + + if (flag_isoc99 + && expr1_int_operands + && expr2_int_operands) + ret = note_integer_operands (ret); + + if (eptype) + ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret); + + protected_set_expr_location (ret, loc); + return ret; +} + +/* Issue -Wcast-qual warnings when appropriate. TYPE is the type to + which we are casting. OTYPE is the type of the expression being + cast. Both TYPE and OTYPE are pointer types. LOC is the location + of the cast. -Wcast-qual appeared on the command line. Named + address space qualifiers are not handled here, because they result + in different warnings. */ + +static void +handle_warn_cast_qual (location_t loc, tree type, tree otype) +{ + tree in_type = type; + tree in_otype = otype; + int added = 0; + int discarded = 0; + bool is_const; + + /* Check that the qualifiers on IN_TYPE are a superset of the + qualifiers of IN_OTYPE. The outermost level of POINTER_TYPE + nodes is uninteresting and we stop as soon as we hit a + non-POINTER_TYPE node on either type. */ + do + { + in_otype = TREE_TYPE (in_otype); + in_type = TREE_TYPE (in_type); + + /* GNU C allows cv-qualified function types. 'const' means the + function is very pure, 'volatile' means it can't return. We + need to warn when such qualifiers are added, not when they're + taken away. */ + if (TREE_CODE (in_otype) == FUNCTION_TYPE + && TREE_CODE (in_type) == FUNCTION_TYPE) + added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type) + & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype)); + else + discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype) + & ~TYPE_QUALS_NO_ADDR_SPACE (in_type)); + } + while (TREE_CODE (in_type) == POINTER_TYPE + && TREE_CODE (in_otype) == POINTER_TYPE); + + if (added) + warning_at (loc, OPT_Wcast_qual, + "cast adds %q#v qualifier to function type", added); + + if (discarded) + /* There are qualifiers present in IN_OTYPE that are not present + in IN_TYPE. */ + warning_at (loc, OPT_Wcast_qual, + "cast discards %qv qualifier from pointer target type", + discarded); + + if (added || discarded) + return; + + /* A cast from **T to const **T is unsafe, because it can cause a + const value to be changed with no additional warning. We only + issue this warning if T is the same on both sides, and we only + issue the warning if there are the same number of pointers on + both sides, as otherwise the cast is clearly unsafe anyhow. A + cast is unsafe when a qualifier is added at one level and const + is not present at all outer levels. + + To issue this warning, we check at each level whether the cast + adds new qualifiers not already seen. We don't need to special + case function types, as they won't have the same + TYPE_MAIN_VARIANT. */ + + if (TYPE_MAIN_VARIANT (in_type) != TYPE_MAIN_VARIANT (in_otype)) + return; + if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE) + return; + + in_type = type; + in_otype = otype; + is_const = TYPE_READONLY (TREE_TYPE (in_type)); + do + { + in_type = TREE_TYPE (in_type); + in_otype = TREE_TYPE (in_otype); + if ((TYPE_QUALS (in_type) &~ TYPE_QUALS (in_otype)) != 0 + && !is_const) + { + warning_at (loc, OPT_Wcast_qual, + "to be safe all intermediate pointers in cast from " + "%qT to %qT must be % qualified", + otype, type); + break; + } + if (is_const) + is_const = TYPE_READONLY (in_type); + } + while (TREE_CODE (in_type) == POINTER_TYPE); +} + +/* Heuristic check if two parameter types can be considered ABI-equivalent. */ + +static bool +c_safe_arg_type_equiv_p (tree t1, tree t2) +{ + t1 = TYPE_MAIN_VARIANT (t1); + t2 = TYPE_MAIN_VARIANT (t2); + + if (TREE_CODE (t1) == POINTER_TYPE + && TREE_CODE (t2) == POINTER_TYPE) + return true; + + /* The signedness of the parameter matters only when an integral + type smaller than int is promoted to int, otherwise only the + precision of the parameter matters. + This check should make sure that the callee does not see + undefined values in argument registers. */ + if (INTEGRAL_TYPE_P (t1) + && INTEGRAL_TYPE_P (t2) + && TYPE_PRECISION (t1) == TYPE_PRECISION (t2) + && (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2) + || !targetm.calls.promote_prototypes (NULL_TREE) + || TYPE_PRECISION (t1) >= TYPE_PRECISION (integer_type_node))) + return true; + + return comptypes (t1, t2); +} + +/* Check if a type cast between two function types can be considered safe. */ + +static bool +c_safe_function_type_cast_p (tree t1, tree t2) +{ + if (TREE_TYPE (t1) == void_type_node && + TYPE_ARG_TYPES (t1) == void_list_node) + return true; + + if (TREE_TYPE (t2) == void_type_node && + TYPE_ARG_TYPES (t2) == void_list_node) + return true; + + if (!c_safe_arg_type_equiv_p (TREE_TYPE (t1), TREE_TYPE (t2))) + return false; + + for (t1 = TYPE_ARG_TYPES (t1), t2 = TYPE_ARG_TYPES (t2); + t1 && t2; + t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) + if (!c_safe_arg_type_equiv_p (TREE_VALUE (t1), TREE_VALUE (t2))) + return false; + + return true; +} + +/* Build an expression representing a cast to type TYPE of expression EXPR. + LOC is the location of the cast-- typically the open paren of the cast. */ + +tree +build_c_cast (location_t loc, tree type, tree expr) +{ + tree value; + + bool int_operands = EXPR_INT_CONST_OPERANDS (expr); + + if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) + expr = TREE_OPERAND (expr, 0); + + value = expr; + if (int_operands) + value = remove_c_maybe_const_expr (value); + + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; + + /* The ObjC front-end uses TYPE_MAIN_VARIANT to tie together types differing + only in qualifications. But when constructing cast expressions, + the protocols do matter and must be kept around. */ + if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr))) + return build1 (NOP_EXPR, type, expr); + + type = TYPE_MAIN_VARIANT (type); + + if (TREE_CODE (type) == ARRAY_TYPE) + { + error_at (loc, "cast specifies array type"); + return error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error_at (loc, "cast specifies function type"); + return error_mark_node; + } + + if (!VOID_TYPE_P (type)) + { + value = require_complete_type (loc, value); + if (value == error_mark_node) + return error_mark_node; + } + + if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value))) + { + if (RECORD_OR_UNION_TYPE_P (type)) + pedwarn (loc, OPT_Wpedantic, + "ISO C forbids casting nonscalar to the same type"); + + /* Convert to remove any qualifiers from VALUE's type. */ + value = convert (type, value); + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_TYPE (field) != error_mark_node + && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)), + TYPE_MAIN_VARIANT (TREE_TYPE (value)))) + break; + + if (field) + { + tree t; + bool maybe_const = true; + + pedwarn (loc, OPT_Wpedantic, "ISO C forbids casts to union type"); + t = c_fully_fold (value, false, &maybe_const); + t = build_constructor_single (type, field, t); + if (!maybe_const) + t = c_wrap_maybe_const (t, true); + t = digest_init (loc, type, t, + NULL_TREE, false, true, 0); + TREE_CONSTANT (t) = TREE_CONSTANT (value); + return t; + } + error_at (loc, "cast to union type from type not present in union"); + return error_mark_node; + } + else + { + tree otype, ovalue; + + if (type == void_type_node) + { + tree t = build1 (CONVERT_EXPR, type, value); + SET_EXPR_LOCATION (t, loc); + return t; + } + + otype = TREE_TYPE (value); + + /* Optionally warn about potentially worrisome casts. */ + if (warn_cast_qual + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE) + handle_warn_cast_qual (loc, type, otype); + + /* Warn about conversions between pointers to disjoint + address spaces. */ + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && !null_pointer_constant_p (value)) + { + addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type)); + addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype)); + addr_space_t as_common; + + if (!addr_space_superset (as_to, as_from, &as_common)) + { + if (ADDR_SPACE_GENERIC_P (as_from)) + warning_at (loc, 0, "cast to %s address space pointer " + "from disjoint generic address space pointer", + c_addr_space_name (as_to)); + + else if (ADDR_SPACE_GENERIC_P (as_to)) + warning_at (loc, 0, "cast to generic address space pointer " + "from disjoint %s address space pointer", + c_addr_space_name (as_from)); + + else + warning_at (loc, 0, "cast to %s address space pointer " + "from disjoint %s address space pointer", + c_addr_space_name (as_to), + c_addr_space_name (as_from)); + } + } + + /* Warn about possible alignment problems. */ + if ((STRICT_ALIGNMENT || warn_cast_align == 2) + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE + && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE + /* Don't warn about opaque types, where the actual alignment + restriction is unknown. */ + && !(RECORD_OR_UNION_TYPE_P (TREE_TYPE (otype)) + && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode) + && min_align_of_type (TREE_TYPE (type)) + > min_align_of_type (TREE_TYPE (otype))) + warning_at (loc, OPT_Wcast_align, + "cast increases required alignment of target type"); + + if (TREE_CODE (type) == INTEGER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TYPE_PRECISION (type) != TYPE_PRECISION (otype)) + /* Unlike conversion of integers to pointers, where the + warning is disabled for converting constants because + of cases such as SIG_*, warn about converting constant + pointers to integers. In some cases it may cause unwanted + sign extension, and a warning is appropriate. */ + warning_at (loc, OPT_Wpointer_to_int_cast, + "cast from pointer to integer of different size"); + + if (TREE_CODE (value) == CALL_EXPR + && TREE_CODE (type) != TREE_CODE (otype)) + warning_at (loc, OPT_Wbad_function_cast, + "cast from function call of type %qT " + "to non-matching type %qT", otype, type); + + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == INTEGER_TYPE + && TYPE_PRECISION (type) != TYPE_PRECISION (otype) + /* Don't warn about converting any constant. */ + && !TREE_CONSTANT (value)) + warning_at (loc, + OPT_Wint_to_pointer_cast, "cast to pointer from integer " + "of different size"); + + if (warn_strict_aliasing <= 2) + strict_aliasing_warning (EXPR_LOCATION (value), type, expr); + + /* If pedantic, warn for conversions between function and object + pointer types, except for converting a null pointer constant + to function pointer type. */ + if (pedantic + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE) + pedwarn (loc, OPT_Wpedantic, "ISO C forbids " + "conversion of function pointer to object pointer type"); + + if (pedantic + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE + && !null_pointer_constant_p (value)) + pedwarn (loc, OPT_Wpedantic, "ISO C forbids " + "conversion of object pointer to function pointer type"); + + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE + && !c_safe_function_type_cast_p (TREE_TYPE (type), + TREE_TYPE (otype))) + warning_at (loc, OPT_Wcast_function_type, + "cast between incompatible function types" + " from %qT to %qT", otype, type); + + ovalue = value; + value = convert (type, value); + + /* Ignore any integer overflow caused by the cast. */ + if (TREE_CODE (value) == INTEGER_CST && !FLOAT_TYPE_P (otype)) + { + if (CONSTANT_CLASS_P (ovalue) && TREE_OVERFLOW (ovalue)) + { + if (!TREE_OVERFLOW (value)) + { + /* Avoid clobbering a shared constant. */ + value = copy_node (value); + TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue); + } + } + else if (TREE_OVERFLOW (value)) + /* Reset VALUE's overflow flags, ensuring constant sharing. */ + value = wide_int_to_tree (TREE_TYPE (value), wi::to_wide (value)); + } + } + + /* Don't let a cast be an lvalue. */ + if (lvalue_p (value)) + value = non_lvalue_loc (loc, value); + + /* Don't allow the results of casting to floating-point or complex + types be confused with actual constants, or casts involving + integer and pointer types other than direct integer-to-integer + and integer-to-pointer be confused with integer constant + expressions and null pointer constants. */ + if (TREE_CODE (value) == REAL_CST + || TREE_CODE (value) == COMPLEX_CST + || (TREE_CODE (value) == INTEGER_CST + && !((TREE_CODE (expr) == INTEGER_CST + && INTEGRAL_TYPE_P (TREE_TYPE (expr))) + || TREE_CODE (expr) == REAL_CST + || TREE_CODE (expr) == COMPLEX_CST))) + value = build1 (NOP_EXPR, type, value); + + /* If the expression has integer operands and so can occur in an + unevaluated part of an integer constant expression, ensure the + return value reflects this. */ + if (int_operands + && INTEGRAL_TYPE_P (type) + && value != error_mark_node + && !EXPR_INT_CONST_OPERANDS (value)) + value = note_integer_operands (value); + + protected_set_expr_location (value, loc); + return value; +} + +/* Interpret a cast of expression EXPR to type TYPE. LOC is the + location of the open paren of the cast, or the position of the cast + expr. */ +tree +c_cast_expr (location_t loc, struct c_type_name *type_name, tree expr) +{ + tree type; + tree type_expr = NULL_TREE; + bool type_expr_const = true; + tree ret; + int saved_wsp = warn_strict_prototypes; + + /* This avoids warnings about unprototyped casts on + integers. E.g. "#define SIG_DFL (void(*)())0". */ + if (TREE_CODE (expr) == INTEGER_CST) + warn_strict_prototypes = 0; + type = groktypename (type_name, &type_expr, &type_expr_const); + warn_strict_prototypes = saved_wsp; + + if (TREE_CODE (expr) == ADDR_EXPR && !VOID_TYPE_P (type) + && reject_gcc_builtin (expr)) + return error_mark_node; + + ret = build_c_cast (loc, type, expr); + if (type_expr) + { + bool inner_expr_const = true; + ret = c_fully_fold (ret, require_constant_value, &inner_expr_const); + ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret), type_expr, ret); + C_MAYBE_CONST_EXPR_NON_CONST (ret) = !(type_expr_const + && inner_expr_const); + SET_EXPR_LOCATION (ret, loc); + } + + if (!EXPR_HAS_LOCATION (ret)) + protected_set_expr_location (ret, loc); + + /* C++ does not permits types to be defined in a cast, but it + allows references to incomplete types. */ + if (warn_cxx_compat && type_name->specs->typespec_kind == ctsk_tagdef) + warning_at (loc, OPT_Wc___compat, + "defining a type in a cast is invalid in C++"); + + return ret; +} + +/* Build an assignment expression of lvalue LHS from value RHS. + If LHS_ORIGTYPE is not NULL, it is the original type of LHS, which + may differ from TREE_TYPE (LHS) for an enum bitfield. + MODIFYCODE is the code for a binary operator that we use + to combine the old value of LHS with RHS to get the new value. + Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment. + If RHS_ORIGTYPE is not NULL_TREE, it is the original type of RHS, + which may differ from TREE_TYPE (RHS) for an enum value. + + LOCATION is the location of the MODIFYCODE operator. + RHS_LOC is the location of the RHS. */ + +tree +build_modify_expr (location_t location, tree lhs, tree lhs_origtype, + enum tree_code modifycode, + location_t rhs_loc, tree rhs, tree rhs_origtype) +{ + tree result; + tree newrhs; + tree rhseval = NULL_TREE; + tree lhstype = TREE_TYPE (lhs); + tree olhstype = lhstype; + bool npc; + bool is_atomic_op; + + /* Types that aren't fully specified cannot be used in assignments. */ + lhs = require_complete_type (location, lhs); + + /* Avoid duplicate error messages from operands that had errors. */ + if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK) + return error_mark_node; + + /* Ensure an error for assigning a non-lvalue array to an array in + C90. */ + if (TREE_CODE (lhstype) == ARRAY_TYPE) + { + error_at (location, "assignment to expression with array type"); + return error_mark_node; + } + + /* For ObjC properties, defer this check. */ + if (!objc_is_property_ref (lhs) && !lvalue_or_else (location, lhs, lv_assign)) + return error_mark_node; + + is_atomic_op = really_atomic_lvalue (lhs); + + newrhs = rhs; + + if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR) + { + tree inner = build_modify_expr (location, C_MAYBE_CONST_EXPR_EXPR (lhs), + lhs_origtype, modifycode, rhs_loc, rhs, + rhs_origtype); + if (inner == error_mark_node) + return error_mark_node; + result = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner), + C_MAYBE_CONST_EXPR_PRE (lhs), inner); + gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (lhs)); + C_MAYBE_CONST_EXPR_NON_CONST (result) = 1; + protected_set_expr_location (result, location); + return result; + } + + /* If a binary op has been requested, combine the old LHS value with the RHS + producing the value we should actually store into the LHS. */ + + if (modifycode != NOP_EXPR) + { + lhs = c_fully_fold (lhs, false, NULL, true); + lhs = stabilize_reference (lhs); + + /* Construct the RHS for any non-atomic compound assignemnt. */ + if (!is_atomic_op) + { + /* If in LHS op= RHS the RHS has side-effects, ensure they + are preevaluated before the rest of the assignment expression's + side-effects, because RHS could contain e.g. function calls + that modify LHS. */ + if (TREE_SIDE_EFFECTS (rhs)) + { + if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) + newrhs = save_expr (TREE_OPERAND (rhs, 0)); + else + newrhs = save_expr (rhs); + rhseval = newrhs; + if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) + newrhs = build1 (EXCESS_PRECISION_EXPR, TREE_TYPE (rhs), + newrhs); + } + newrhs = build_binary_op (location, + modifycode, lhs, newrhs, true); + + /* The original type of the right hand side is no longer + meaningful. */ + rhs_origtype = NULL_TREE; + } + } + + if (c_dialect_objc ()) + { + /* Check if we are modifying an Objective-C property reference; + if so, we need to generate setter calls. */ + if (TREE_CODE (newrhs) == EXCESS_PRECISION_EXPR) + result = objc_maybe_build_modify_expr (lhs, TREE_OPERAND (newrhs, 0)); + else + result = objc_maybe_build_modify_expr (lhs, newrhs); + if (result) + goto return_result; + + /* Else, do the check that we postponed for Objective-C. */ + if (!lvalue_or_else (location, lhs, lv_assign)) + return error_mark_node; + } + + /* Give an error for storing in something that is 'const'. */ + + if (TYPE_READONLY (lhstype) + || (RECORD_OR_UNION_TYPE_P (lhstype) + && C_TYPE_FIELDS_READONLY (lhstype))) + { + readonly_error (location, lhs, lv_assign); + return error_mark_node; + } + else if (TREE_READONLY (lhs)) + readonly_warning (lhs, lv_assign); + + /* If storing into a structure or union member, + it has probably been given type `int'. + Compute the type that would go with + the actual amount of storage the member occupies. */ + + if (TREE_CODE (lhs) == COMPONENT_REF + && (TREE_CODE (lhstype) == INTEGER_TYPE + || TREE_CODE (lhstype) == BOOLEAN_TYPE + || TREE_CODE (lhstype) == REAL_TYPE + || TREE_CODE (lhstype) == ENUMERAL_TYPE)) + lhstype = TREE_TYPE (get_unwidened (lhs, 0)); + + /* If storing in a field that is in actuality a short or narrower than one, + we must store in the field in its actual type. */ + + if (lhstype != TREE_TYPE (lhs)) + { + lhs = copy_node (lhs); + TREE_TYPE (lhs) = lhstype; + } + + /* Issue -Wc++-compat warnings about an assignment to an enum type + when LHS does not have its original type. This happens for, + e.g., an enum bitfield in a struct. */ + if (warn_cxx_compat + && lhs_origtype != NULL_TREE + && lhs_origtype != lhstype + && TREE_CODE (lhs_origtype) == ENUMERAL_TYPE) + { + tree checktype = (rhs_origtype != NULL_TREE + ? rhs_origtype + : TREE_TYPE (rhs)); + if (checktype != error_mark_node + && (TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (lhs_origtype) + || (is_atomic_op && modifycode != NOP_EXPR))) + warning_at (location, OPT_Wc___compat, + "enum conversion in assignment is invalid in C++"); + } + + /* Remove qualifiers. */ + lhstype = build_qualified_type (lhstype, TYPE_UNQUALIFIED); + olhstype = build_qualified_type (olhstype, TYPE_UNQUALIFIED); + + /* Convert new value to destination type. Fold it first, then + restore any excess precision information, for the sake of + conversion warnings. */ + + if (!(is_atomic_op && modifycode != NOP_EXPR)) + { + tree rhs_semantic_type = NULL_TREE; + if (!c_in_omp_for) + { + if (TREE_CODE (newrhs) == EXCESS_PRECISION_EXPR) + { + rhs_semantic_type = TREE_TYPE (newrhs); + newrhs = TREE_OPERAND (newrhs, 0); + } + npc = null_pointer_constant_p (newrhs); + newrhs = c_fully_fold (newrhs, false, NULL); + if (rhs_semantic_type) + newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs); + } + else + npc = null_pointer_constant_p (newrhs); + newrhs = convert_for_assignment (location, rhs_loc, lhstype, newrhs, + rhs_origtype, ic_assign, npc, + NULL_TREE, NULL_TREE, 0); + if (TREE_CODE (newrhs) == ERROR_MARK) + return error_mark_node; + } + + /* Emit ObjC write barrier, if necessary. */ + if (c_dialect_objc () && flag_objc_gc) + { + result = objc_generate_write_barrier (lhs, modifycode, newrhs); + if (result) + { + protected_set_expr_location (result, location); + goto return_result; + } + } + + /* Scan operands. */ + + if (is_atomic_op) + result = build_atomic_assign (location, lhs, modifycode, newrhs, false); + else + { + result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs); + TREE_SIDE_EFFECTS (result) = 1; + protected_set_expr_location (result, location); + } + + /* If we got the LHS in a different type for storing in, + convert the result back to the nominal type of LHS + so that the value we return always has the same type + as the LHS argument. */ + + if (olhstype == TREE_TYPE (result)) + goto return_result; + + result = convert_for_assignment (location, rhs_loc, olhstype, result, + rhs_origtype, ic_assign, false, NULL_TREE, + NULL_TREE, 0); + protected_set_expr_location (result, location); + +return_result: + if (rhseval) + result = build2 (COMPOUND_EXPR, TREE_TYPE (result), rhseval, result); + return result; +} + +/* Return whether STRUCT_TYPE has an anonymous field with type TYPE. + This is used to implement -fplan9-extensions. */ + +static bool +find_anonymous_field_with_type (tree struct_type, tree type) +{ + tree field; + bool found; + + gcc_assert (RECORD_OR_UNION_TYPE_P (struct_type)); + found = false; + for (field = TYPE_FIELDS (struct_type); + field != NULL_TREE; + field = TREE_CHAIN (field)) + { + tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field)) + ? c_build_qualified_type (TREE_TYPE (field), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (TREE_TYPE (field))); + if (DECL_NAME (field) == NULL + && comptypes (type, fieldtype)) + { + if (found) + return false; + found = true; + } + else if (DECL_NAME (field) == NULL + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)) + && find_anonymous_field_with_type (TREE_TYPE (field), type)) + { + if (found) + return false; + found = true; + } + } + return found; +} + +/* RHS is an expression whose type is pointer to struct. If there is + an anonymous field in RHS with type TYPE, then return a pointer to + that field in RHS. This is used with -fplan9-extensions. This + returns NULL if no conversion could be found. */ + +static tree +convert_to_anonymous_field (location_t location, tree type, tree rhs) +{ + tree rhs_struct_type, lhs_main_type; + tree field, found_field; + bool found_sub_field; + tree ret; + + gcc_assert (POINTER_TYPE_P (TREE_TYPE (rhs))); + rhs_struct_type = TREE_TYPE (TREE_TYPE (rhs)); + gcc_assert (RECORD_OR_UNION_TYPE_P (rhs_struct_type)); + + gcc_assert (POINTER_TYPE_P (type)); + lhs_main_type = (TYPE_ATOMIC (TREE_TYPE (type)) + ? c_build_qualified_type (TREE_TYPE (type), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (TREE_TYPE (type))); + + found_field = NULL_TREE; + found_sub_field = false; + for (field = TYPE_FIELDS (rhs_struct_type); + field != NULL_TREE; + field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) != NULL_TREE + || !RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) + continue; + tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field)) + ? c_build_qualified_type (TREE_TYPE (field), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (TREE_TYPE (field))); + if (comptypes (lhs_main_type, fieldtype)) + { + if (found_field != NULL_TREE) + return NULL_TREE; + found_field = field; + } + else if (find_anonymous_field_with_type (TREE_TYPE (field), + lhs_main_type)) + { + if (found_field != NULL_TREE) + return NULL_TREE; + found_field = field; + found_sub_field = true; + } + } + + if (found_field == NULL_TREE) + return NULL_TREE; + + ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (found_field), + build_fold_indirect_ref (rhs), found_field, + NULL_TREE); + ret = build_fold_addr_expr_loc (location, ret); + + if (found_sub_field) + { + ret = convert_to_anonymous_field (location, type, ret); + gcc_assert (ret != NULL_TREE); + } + + return ret; +} + +/* Issue an error message for a bad initializer component. + GMSGID identifies the message. + The component name is taken from the spelling stack. */ + +static void ATTRIBUTE_GCC_DIAG (2,0) +error_init (location_t loc, const char *gmsgid, ...) +{ + char *ofwhat; + + auto_diagnostic_group d; + + /* The gmsgid may be a format string with %< and %>. */ + va_list ap; + va_start (ap, gmsgid); + bool warned = emit_diagnostic_valist (DK_ERROR, loc, -1, gmsgid, &ap); + va_end (ap); + + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + if (*ofwhat && warned) + inform (loc, "(near initialization for %qs)", ofwhat); +} + +/* Issue a pedantic warning for a bad initializer component. OPT is + the option OPT_* (from options.h) controlling this warning or 0 if + it is unconditionally given. GMSGID identifies the message. The + component name is taken from the spelling stack. */ + +static void ATTRIBUTE_GCC_DIAG (3,0) +pedwarn_init (location_t loc, int opt, const char *gmsgid, ...) +{ + /* Use the location where a macro was expanded rather than where + it was defined to make sure macros defined in system headers + but used incorrectly elsewhere are diagnosed. */ + location_t exploc = expansion_point_location_if_in_system_header (loc); + auto_diagnostic_group d; + va_list ap; + va_start (ap, gmsgid); + bool warned = emit_diagnostic_valist (DK_PEDWARN, exploc, opt, gmsgid, &ap); + va_end (ap); + char *ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + if (*ofwhat && warned) + inform (exploc, "(near initialization for %qs)", ofwhat); +} + +/* Issue a warning for a bad initializer component. + + OPT is the OPT_W* value corresponding to the warning option that + controls this warning. GMSGID identifies the message. The + component name is taken from the spelling stack. */ + +static void +warning_init (location_t loc, int opt, const char *gmsgid) +{ + char *ofwhat; + bool warned; + + auto_diagnostic_group d; + + /* Use the location where a macro was expanded rather than where + it was defined to make sure macros defined in system headers + but used incorrectly elsewhere are diagnosed. */ + location_t exploc = expansion_point_location_if_in_system_header (loc); + + /* The gmsgid may be a format string with %< and %>. */ + warned = warning_at (exploc, opt, gmsgid); + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + if (*ofwhat && warned) + inform (exploc, "(near initialization for %qs)", ofwhat); +} + +/* If TYPE is an array type and EXPR is a parenthesized string + constant, warn if pedantic that EXPR is being used to initialize an + object of type TYPE. */ + +void +maybe_warn_string_init (location_t loc, tree type, struct c_expr expr) +{ + if (pedantic + && TREE_CODE (type) == ARRAY_TYPE + && TREE_CODE (expr.value) == STRING_CST + && expr.original_code != STRING_CST) + pedwarn_init (loc, OPT_Wpedantic, + "array initialized from parenthesized string constant"); +} + +/* Attempt to locate the parameter with the given index within FNDECL, + returning DECL_SOURCE_LOCATION (FNDECL) if it can't be found. */ + +static location_t +get_fndecl_argument_location (tree fndecl, int argnum) +{ + int i; + tree param; + + /* Locate param by index within DECL_ARGUMENTS (fndecl). */ + for (i = 0, param = DECL_ARGUMENTS (fndecl); + i < argnum && param; + i++, param = TREE_CHAIN (param)) + ; + + /* If something went wrong (e.g. if we have a builtin and thus no arguments), + return DECL_SOURCE_LOCATION (FNDECL). */ + if (param == NULL) + return DECL_SOURCE_LOCATION (fndecl); + + return DECL_SOURCE_LOCATION (param); +} + +/* Issue a note about a mismatching argument for parameter PARMNUM + to FUNDECL, for types EXPECTED_TYPE and ACTUAL_TYPE. + Attempt to issue the note at the pertinent parameter of the decl; + failing that issue it at the location of FUNDECL; failing that + issue it at PLOC. */ + +static void +inform_for_arg (tree fundecl, location_t ploc, int parmnum, + tree expected_type, tree actual_type) +{ + location_t loc; + if (fundecl && !DECL_IS_UNDECLARED_BUILTIN (fundecl)) + loc = get_fndecl_argument_location (fundecl, parmnum - 1); + else + loc = ploc; + + inform (loc, + "expected %qT but argument is of type %qT", + expected_type, actual_type); +} + +/* Issue a warning when an argument of ARGTYPE is passed to a built-in + function FUNDECL declared without prototype to parameter PARMNUM of + PARMTYPE when ARGTYPE does not promote to PARMTYPE. */ + +static void +maybe_warn_builtin_no_proto_arg (location_t loc, tree fundecl, int parmnum, + tree parmtype, tree argtype) +{ + tree_code parmcode = TREE_CODE (parmtype); + tree_code argcode = TREE_CODE (argtype); + tree promoted = c_type_promotes_to (argtype); + + /* Avoid warning for enum arguments that promote to an integer type + of the same size/mode. */ + if (parmcode == INTEGER_TYPE + && argcode == ENUMERAL_TYPE + && TYPE_MODE (parmtype) == TYPE_MODE (argtype)) + return; + + if ((parmcode == argcode + || (parmcode == INTEGER_TYPE + && argcode == ENUMERAL_TYPE)) + && TYPE_MAIN_VARIANT (parmtype) == TYPE_MAIN_VARIANT (promoted)) + return; + + /* This diagnoses even signed/unsigned mismatches. Those might be + safe in many cases but GCC may emit suboptimal code for them so + warning on those cases drives efficiency improvements. */ + if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch, + TYPE_MAIN_VARIANT (promoted) == argtype + ? G_("%qD argument %d type is %qT where %qT is expected " + "in a call to built-in function declared without " + "prototype") + : G_("%qD argument %d promotes to %qT where %qT is expected " + "in a call to built-in function declared without " + "prototype"), + fundecl, parmnum, promoted, parmtype)) + inform (DECL_SOURCE_LOCATION (fundecl), + "built-in %qD declared here", + fundecl); +} + +/* Convert value RHS to type TYPE as preparation for an assignment to + an lvalue of type TYPE. If ORIGTYPE is not NULL_TREE, it is the + original type of RHS; this differs from TREE_TYPE (RHS) for enum + types. NULL_POINTER_CONSTANT says whether RHS was a null pointer + constant before any folding. + The real work of conversion is done by `convert'. + The purpose of this function is to generate error messages + for assignments that are not allowed in C. + ERRTYPE says whether it is argument passing, assignment, + initialization or return. + + In the following example, '~' denotes where EXPR_LOC and '^' where + LOCATION point to: + + f (var); [ic_argpass] + ^ ~~~ + x = var; [ic_assign] + ^ ~~~; + int x = var; [ic_init] + ^^^ + return x; [ic_return] + ^ + + FUNCTION is a tree for the function being called. + PARMNUM is the number of the argument, for printing in error messages. + WARNOPT may be set to a warning option to issue the corresponding warning + rather than an error for invalid conversions. Used for calls to built-in + functions declared without a prototype. */ + +static tree +convert_for_assignment (location_t location, location_t expr_loc, tree type, + tree rhs, tree origtype, enum impl_conv errtype, + bool null_pointer_constant, tree fundecl, + tree function, int parmnum, int warnopt /* = 0 */) +{ + enum tree_code codel = TREE_CODE (type); + tree orig_rhs = rhs; + tree rhstype; + enum tree_code coder; + tree rname = NULL_TREE; + bool objc_ok = false; + + /* Use the expansion point location to handle cases such as user's + function returning a wrong-type macro defined in a system header. */ + location = expansion_point_location_if_in_system_header (location); + + if (errtype == ic_argpass) + { + tree selector; + /* Change pointer to function to the function itself for + diagnostics. */ + if (TREE_CODE (function) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) + function = TREE_OPERAND (function, 0); + + /* Handle an ObjC selector specially for diagnostics. */ + selector = objc_message_selector (); + rname = function; + if (selector && parmnum > 2) + { + rname = selector; + parmnum -= 2; + } + } + + /* This macro is used to emit diagnostics to ensure that all format + strings are complete sentences, visible to gettext and checked at + compile time. */ +#define PEDWARN_FOR_ASSIGNMENT(LOCATION, PLOC, OPT, AR, AS, IN, RE) \ + do { \ + switch (errtype) \ + { \ + case ic_argpass: \ + { \ + auto_diagnostic_group d; \ + if (pedwarn (PLOC, OPT, AR, parmnum, rname)) \ + inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ + } \ + break; \ + case ic_assign: \ + pedwarn (LOCATION, OPT, AS); \ + break; \ + case ic_init: \ + case ic_init_const: \ + pedwarn_init (LOCATION, OPT, IN); \ + break; \ + case ic_return: \ + pedwarn (LOCATION, OPT, RE); \ + break; \ + default: \ + gcc_unreachable (); \ + } \ + } while (0) + + /* This macro is used to emit diagnostics to ensure that all format + strings are complete sentences, visible to gettext and checked at + compile time. It can be called with 'pedwarn' or 'warning_at'. */ +#define WARNING_FOR_QUALIFIERS(PEDWARN, LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \ + do { \ + switch (errtype) \ + { \ + case ic_argpass: \ + { \ + auto_diagnostic_group d; \ + if (PEDWARN) { \ + if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS)) \ + inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ + } else { \ + if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS)) \ + inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ + } \ + } \ + break; \ + case ic_assign: \ + if (PEDWARN) \ + pedwarn (LOCATION, OPT, AS, QUALS); \ + else \ + warning_at (LOCATION, OPT, AS, QUALS); \ + break; \ + case ic_init: \ + case ic_init_const: \ + if (PEDWARN) \ + pedwarn (LOCATION, OPT, IN, QUALS); \ + else \ + warning_at (LOCATION, OPT, IN, QUALS); \ + break; \ + case ic_return: \ + if (PEDWARN) \ + pedwarn (LOCATION, OPT, RE, QUALS); \ + else \ + warning_at (LOCATION, OPT, RE, QUALS); \ + break; \ + default: \ + gcc_unreachable (); \ + } \ + } while (0) + + /* This macro is used to emit diagnostics to ensure that all format + strings are complete sentences, visible to gettext and checked at + compile time. It is the same as PEDWARN_FOR_ASSIGNMENT but with an + extra parameter to enumerate qualifiers. */ +#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \ + WARNING_FOR_QUALIFIERS (true, LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) + + + if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) + rhs = TREE_OPERAND (rhs, 0); + + rhstype = TREE_TYPE (rhs); + coder = TREE_CODE (rhstype); + + if (coder == ERROR_MARK) + return error_mark_node; + + if (c_dialect_objc ()) + { + int parmno; + + switch (errtype) + { + case ic_return: + parmno = 0; + break; + + case ic_assign: + parmno = -1; + break; + + case ic_init: + case ic_init_const: + parmno = -2; + break; + + default: + parmno = parmnum; + break; + } + + objc_ok = objc_compare_types (type, rhstype, parmno, rname); + } + + if (warn_cxx_compat) + { + tree checktype = origtype != NULL_TREE ? origtype : rhstype; + if (checktype != error_mark_node + && TREE_CODE (type) == ENUMERAL_TYPE + && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) + switch (errtype) + { + case ic_argpass: + if (pedwarn (expr_loc, OPT_Wc___compat, "enum conversion when " + "passing argument %d of %qE is invalid in C++", + parmnum, rname)) + inform ((fundecl && !DECL_IS_UNDECLARED_BUILTIN (fundecl)) + ? DECL_SOURCE_LOCATION (fundecl) : expr_loc, + "expected %qT but argument is of type %qT", + type, rhstype); + break; + case ic_assign: + pedwarn (location, OPT_Wc___compat, "enum conversion from %qT to " + "%qT in assignment is invalid in C++", rhstype, type); + break; + case ic_init: + case ic_init_const: + pedwarn_init (location, OPT_Wc___compat, "enum conversion from " + "%qT to %qT in initialization is invalid in C++", + rhstype, type); + break; + case ic_return: + pedwarn (location, OPT_Wc___compat, "enum conversion from %qT to " + "%qT in return is invalid in C++", rhstype, type); + break; + default: + gcc_unreachable (); + } + } + + if (warn_enum_conversion) + { + tree checktype = origtype != NULL_TREE ? origtype : rhstype; + if (checktype != error_mark_node + && TREE_CODE (checktype) == ENUMERAL_TYPE + && TREE_CODE (type) == ENUMERAL_TYPE + && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) + { + gcc_rich_location loc (location); + warning_at (&loc, OPT_Wenum_conversion, + "implicit conversion from %qT to %qT", + checktype, type); + } + } + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)) + { + warn_for_address_or_pointer_of_packed_member (type, orig_rhs); + return rhs; + } + + if (coder == VOID_TYPE) + { + /* Except for passing an argument to an unprototyped function, + this is a constraint violation. When passing an argument to + an unprototyped function, it is compile-time undefined; + making it a constraint in that case was rejected in + DR#252. */ + const char msg[] = "void value not ignored as it ought to be"; + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); + return error_mark_node; + } + rhs = require_complete_type (location, rhs); + if (rhs == error_mark_node) + return error_mark_node; + + if (coder == POINTER_TYPE && reject_gcc_builtin (rhs)) + return error_mark_node; + + /* A non-reference type can convert to a reference. This handles + va_start, va_copy and possibly port built-ins. */ + if (codel == REFERENCE_TYPE && coder != REFERENCE_TYPE) + { + if (!lvalue_p (rhs)) + { + const char msg[] = "cannot pass rvalue to reference parameter"; + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); + return error_mark_node; + } + if (!c_mark_addressable (rhs)) + return error_mark_node; + rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs); + SET_EXPR_LOCATION (rhs, location); + + rhs = convert_for_assignment (location, expr_loc, + build_pointer_type (TREE_TYPE (type)), + rhs, origtype, errtype, + null_pointer_constant, fundecl, function, + parmnum, warnopt); + if (rhs == error_mark_node) + return error_mark_node; + + rhs = build1 (NOP_EXPR, type, rhs); + SET_EXPR_LOCATION (rhs, location); + return rhs; + } + /* Some types can interconvert without explicit casts. */ + else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE + && vector_types_convertible_p (type, TREE_TYPE (rhs), true)) + return convert (type, rhs); + /* Arithmetic types all interconvert, and enum is treated like int. */ + else if ((codel == INTEGER_TYPE || codel == REAL_TYPE + || codel == FIXED_POINT_TYPE + || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE + || codel == BOOLEAN_TYPE) + && (coder == INTEGER_TYPE || coder == REAL_TYPE + || coder == FIXED_POINT_TYPE + || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE + || coder == BOOLEAN_TYPE)) + { + if (warnopt && errtype == ic_argpass) + maybe_warn_builtin_no_proto_arg (expr_loc, fundecl, parmnum, type, + rhstype); + + bool save = in_late_binary_op; + if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE + || (coder == REAL_TYPE + && (codel == INTEGER_TYPE || codel == ENUMERAL_TYPE) + && sanitize_flags_p (SANITIZE_FLOAT_CAST))) + in_late_binary_op = true; + tree ret = convert_and_check (expr_loc != UNKNOWN_LOCATION + ? expr_loc : location, type, orig_rhs, + errtype == ic_init_const); + in_late_binary_op = save; + return ret; + } + + /* Aggregates in different TUs might need conversion. */ + if ((codel == RECORD_TYPE || codel == UNION_TYPE) + && codel == coder + && comptypes (type, rhstype)) + return convert_and_check (expr_loc != UNKNOWN_LOCATION + ? expr_loc : location, type, rhs); + + /* Conversion to a transparent union or record from its member types. + This applies only to function arguments. */ + if (((codel == UNION_TYPE || codel == RECORD_TYPE) + && TYPE_TRANSPARENT_AGGR (type)) + && errtype == ic_argpass) + { + tree memb, marginal_memb = NULL_TREE; + + for (memb = TYPE_FIELDS (type); memb ; memb = DECL_CHAIN (memb)) + { + tree memb_type = TREE_TYPE (memb); + + if (comptypes (TYPE_MAIN_VARIANT (memb_type), + TYPE_MAIN_VARIANT (rhstype))) + break; + + if (TREE_CODE (memb_type) != POINTER_TYPE) + continue; + + if (coder == POINTER_TYPE) + { + tree ttl = TREE_TYPE (memb_type); + tree ttr = TREE_TYPE (rhstype); + + /* Any non-function converts to a [const][volatile] void * + and vice versa; otherwise, targets must be the same. + Meanwhile, the lhs target must have all the qualifiers of + the rhs. */ + if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl)) + || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr)) + || comp_target_types (location, memb_type, rhstype)) + { + int lquals = TYPE_QUALS (ttl) & ~TYPE_QUAL_ATOMIC; + int rquals = TYPE_QUALS (ttr) & ~TYPE_QUAL_ATOMIC; + /* If this type won't generate any warnings, use it. */ + if (lquals == rquals + || ((TREE_CODE (ttr) == FUNCTION_TYPE + && TREE_CODE (ttl) == FUNCTION_TYPE) + ? ((lquals | rquals) == rquals) + : ((lquals | rquals) == lquals))) + break; + + /* Keep looking for a better type, but remember this one. */ + if (!marginal_memb) + marginal_memb = memb; + } + } + + /* Can convert integer zero to any pointer type. */ + if (null_pointer_constant) + { + rhs = null_pointer_node; + break; + } + } + + if (memb || marginal_memb) + { + if (!memb) + { + /* We have only a marginally acceptable member type; + it needs a warning. */ + tree ttl = TREE_TYPE (TREE_TYPE (marginal_memb)); + tree ttr = TREE_TYPE (rhstype); + + /* Const and volatile mean something different for function + types, so the usual warnings are not appropriate. */ + if (TREE_CODE (ttr) == FUNCTION_TYPE + && TREE_CODE (ttl) == FUNCTION_TYPE) + { + /* Because const and volatile on functions are + restrictions that say the function will not do + certain things, it is okay to use a const or volatile + function where an ordinary one is wanted, but not + vice-versa. */ + if (TYPE_QUALS_NO_ADDR_SPACE (ttl) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) + PEDWARN_FOR_QUALIFIERS (location, expr_loc, + OPT_Wdiscarded_qualifiers, + G_("passing argument %d of %qE " + "makes %q#v qualified function " + "pointer from unqualified"), + G_("assignment makes %q#v qualified " + "function pointer from " + "unqualified"), + G_("initialization makes %q#v qualified " + "function pointer from " + "unqualified"), + G_("return makes %q#v qualified function " + "pointer from unqualified"), + TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)); + } + else if (TYPE_QUALS_NO_ADDR_SPACE (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) + PEDWARN_FOR_QUALIFIERS (location, expr_loc, + OPT_Wdiscarded_qualifiers, + G_("passing argument %d of %qE discards " + "%qv qualifier from pointer target type"), + G_("assignment discards %qv qualifier " + "from pointer target type"), + G_("initialization discards %qv qualifier " + "from pointer target type"), + G_("return discards %qv qualifier from " + "pointer target type"), + TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); + + memb = marginal_memb; + } + + if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl)) + pedwarn (location, OPT_Wpedantic, + "ISO C prohibits argument conversion to union type"); + + rhs = fold_convert_loc (location, TREE_TYPE (memb), rhs); + return build_constructor_single (type, memb, rhs); + } + } + + /* Conversions among pointers */ + else if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE) + && (coder == codel)) + { + /* If RHS refers to a built-in declared without a prototype + BLTIN is the declaration of the built-in with a prototype + and RHSTYPE is set to the actual type of the built-in. */ + tree bltin; + rhstype = type_or_builtin_type (rhs, &bltin); + + tree ttl = TREE_TYPE (type); + tree ttr = TREE_TYPE (rhstype); + tree mvl = ttl; + tree mvr = ttr; + bool is_opaque_pointer; + int target_cmp = 0; /* Cache comp_target_types () result. */ + addr_space_t asl; + addr_space_t asr; + + if (TREE_CODE (mvl) != ARRAY_TYPE) + mvl = (TYPE_ATOMIC (mvl) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (mvl)); + if (TREE_CODE (mvr) != ARRAY_TYPE) + mvr = (TYPE_ATOMIC (mvr) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (mvr)); + /* Opaque pointers are treated like void pointers. */ + is_opaque_pointer = vector_targets_convertible_p (ttl, ttr); + + /* The Plan 9 compiler permits a pointer to a struct to be + automatically converted into a pointer to an anonymous field + within the struct. */ + if (flag_plan9_extensions + && RECORD_OR_UNION_TYPE_P (mvl) + && RECORD_OR_UNION_TYPE_P (mvr) + && mvl != mvr) + { + tree new_rhs = convert_to_anonymous_field (location, type, rhs); + if (new_rhs != NULL_TREE) + { + rhs = new_rhs; + rhstype = TREE_TYPE (rhs); + coder = TREE_CODE (rhstype); + ttr = TREE_TYPE (rhstype); + mvr = TYPE_MAIN_VARIANT (ttr); + } + } + + /* C++ does not allow the implicit conversion void* -> T*. However, + for the purpose of reducing the number of false positives, we + tolerate the special case of + + int *p = NULL; + + where NULL is typically defined in C to be '(void *) 0'. */ + if (VOID_TYPE_P (ttr) && rhs != null_pointer_node && !VOID_TYPE_P (ttl)) + warning_at (errtype == ic_argpass ? expr_loc : location, + OPT_Wc___compat, + "request for implicit conversion " + "from %qT to %qT not permitted in C++", rhstype, type); + + /* See if the pointers point to incompatible address spaces. */ + asl = TYPE_ADDR_SPACE (ttl); + asr = TYPE_ADDR_SPACE (ttr); + if (!null_pointer_constant_p (rhs) + && asr != asl && !targetm.addr_space.subset_p (asr, asl)) + { + switch (errtype) + { + case ic_argpass: + { + const char msg[] = G_("passing argument %d of %qE from " + "pointer to non-enclosed address space"); + if (warnopt) + warning_at (expr_loc, warnopt, msg, parmnum, rname); + else + error_at (expr_loc, msg, parmnum, rname); + break; + } + case ic_assign: + { + const char msg[] = G_("assignment from pointer to " + "non-enclosed address space"); + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); + break; + } + case ic_init: + case ic_init_const: + { + const char msg[] = G_("initialization from pointer to " + "non-enclosed address space"); + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); + break; + } + case ic_return: + { + const char msg[] = G_("return from pointer to " + "non-enclosed address space"); + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); + break; + } + default: + gcc_unreachable (); + } + return error_mark_node; + } + + /* Check if the right-hand side has a format attribute but the + left-hand side doesn't. */ + if (warn_suggest_attribute_format + && check_missing_format_attribute (type, rhstype)) + { + switch (errtype) + { + case ic_argpass: + warning_at (expr_loc, OPT_Wsuggest_attribute_format, + "argument %d of %qE might be " + "a candidate for a format attribute", + parmnum, rname); + break; + case ic_assign: + warning_at (location, OPT_Wsuggest_attribute_format, + "assignment left-hand side might be " + "a candidate for a format attribute"); + break; + case ic_init: + case ic_init_const: + warning_at (location, OPT_Wsuggest_attribute_format, + "initialization left-hand side might be " + "a candidate for a format attribute"); + break; + case ic_return: + warning_at (location, OPT_Wsuggest_attribute_format, + "return type might be " + "a candidate for a format attribute"); + break; + default: + gcc_unreachable (); + } + } + + /* See if the pointers point to incompatible scalar storage orders. */ + if (warn_scalar_storage_order + && (AGGREGATE_TYPE_P (ttl) && TYPE_REVERSE_STORAGE_ORDER (ttl)) + != (AGGREGATE_TYPE_P (ttr) && TYPE_REVERSE_STORAGE_ORDER (ttr))) + { + tree t; + + switch (errtype) + { + case ic_argpass: + /* Do not warn for built-in functions, for example memcpy, since we + control how they behave and they can be useful in this area. */ + if (TREE_CODE (rname) != FUNCTION_DECL + || !fndecl_built_in_p (rname)) + warning_at (location, OPT_Wscalar_storage_order, + "passing argument %d of %qE from incompatible " + "scalar storage order", parmnum, rname); + break; + case ic_assign: + /* Do not warn if the RHS is a call to a function that returns a + pointer that is not an alias. */ + if (TREE_CODE (rhs) != CALL_EXPR + || (t = get_callee_fndecl (rhs)) == NULL_TREE + || !DECL_IS_MALLOC (t)) + warning_at (location, OPT_Wscalar_storage_order, + "assignment to %qT from pointer type %qT with " + "incompatible scalar storage order", type, rhstype); + break; + case ic_init: + case ic_init_const: + /* Likewise. */ + if (TREE_CODE (rhs) != CALL_EXPR + || (t = get_callee_fndecl (rhs)) == NULL_TREE + || !DECL_IS_MALLOC (t)) + warning_at (location, OPT_Wscalar_storage_order, + "initialization of %qT from pointer type %qT with " + "incompatible scalar storage order", type, rhstype); + break; + case ic_return: + warning_at (location, OPT_Wscalar_storage_order, + "returning %qT from pointer type with incompatible " + "scalar storage order %qT", rhstype, type); + break; + default: + gcc_unreachable (); + } + } + + /* Any non-function converts to a [const][volatile] void * + and vice versa; otherwise, targets must be the same. + Meanwhile, the lhs target must have all the qualifiers of the rhs. */ + if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl)) + || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr)) + || (target_cmp = comp_target_types (location, type, rhstype)) + || is_opaque_pointer + || ((c_common_unsigned_type (mvl) + == c_common_unsigned_type (mvr)) + && (c_common_signed_type (mvl) + == c_common_signed_type (mvr)) + && TYPE_ATOMIC (mvl) == TYPE_ATOMIC (mvr))) + { + /* Warn about loss of qualifers from pointers to arrays with + qualifiers on the element type. */ + if (TREE_CODE (ttr) == ARRAY_TYPE) + { + ttr = strip_array_types (ttr); + ttl = strip_array_types (ttl); + + if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl)) + WARNING_FOR_QUALIFIERS (flag_isoc2x, + location, expr_loc, + OPT_Wdiscarded_array_qualifiers, + G_("passing argument %d of %qE discards " + "%qv qualifier from pointer target type"), + G_("assignment discards %qv qualifier " + "from pointer target type"), + G_("initialization discards %qv qualifier " + "from pointer target type"), + G_("return discards %qv qualifier from " + "pointer target type"), + TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); + } + else if (pedantic + && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE) + || + (VOID_TYPE_P (ttr) + && !null_pointer_constant + && TREE_CODE (ttl) == FUNCTION_TYPE))) + PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpedantic, + G_("ISO C forbids passing argument %d of " + "%qE between function pointer " + "and %"), + G_("ISO C forbids assignment between " + "function pointer and %"), + G_("ISO C forbids initialization between " + "function pointer and %"), + G_("ISO C forbids return between function " + "pointer and %")); + /* Const and volatile mean something different for function types, + so the usual warnings are not appropriate. */ + else if (TREE_CODE (ttr) != FUNCTION_TYPE + && TREE_CODE (ttl) != FUNCTION_TYPE) + { + /* Assignments between atomic and non-atomic objects are OK. */ + bool warn_quals_ped = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl); + bool warn_quals = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (strip_array_types (ttl)); + + /* Don't warn about loss of qualifier for conversions from + qualified void* to pointers to arrays with corresponding + qualifier on the element type (except for pedantic before C23). */ + if (warn_quals || (warn_quals_ped && pedantic && !flag_isoc2x)) + PEDWARN_FOR_QUALIFIERS (location, expr_loc, + OPT_Wdiscarded_qualifiers, + G_("passing argument %d of %qE discards " + "%qv qualifier from pointer target type"), + G_("assignment discards %qv qualifier " + "from pointer target type"), + G_("initialization discards %qv qualifier " + "from pointer target type"), + G_("return discards %qv qualifier from " + "pointer target type"), + TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); + else if (warn_quals_ped) + pedwarn_c11 (location, OPT_Wc11_c2x_compat, + "array with qualifier on the element is not qualified before C2X"); + + /* If this is not a case of ignoring a mismatch in signedness, + no warning. */ + else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr) + || target_cmp) + ; + /* If there is a mismatch, do warn. */ + else if (warn_pointer_sign) + switch (errtype) + { + case ic_argpass: + { + auto_diagnostic_group d; + range_label_for_type_mismatch rhs_label (rhstype, type); + gcc_rich_location richloc (expr_loc, &rhs_label); + if (pedwarn (&richloc, OPT_Wpointer_sign, + "pointer targets in passing argument %d of " + "%qE differ in signedness", parmnum, rname)) + inform_for_arg (fundecl, expr_loc, parmnum, type, + rhstype); + } + break; + case ic_assign: + pedwarn (location, OPT_Wpointer_sign, + "pointer targets in assignment from %qT to %qT " + "differ in signedness", rhstype, type); + break; + case ic_init: + case ic_init_const: + pedwarn_init (location, OPT_Wpointer_sign, + "pointer targets in initialization of %qT " + "from %qT differ in signedness", type, + rhstype); + break; + case ic_return: + pedwarn (location, OPT_Wpointer_sign, "pointer targets in " + "returning %qT from a function with return type " + "%qT differ in signedness", rhstype, type); + break; + default: + gcc_unreachable (); + } + } + else if (TREE_CODE (ttl) == FUNCTION_TYPE + && TREE_CODE (ttr) == FUNCTION_TYPE) + { + /* Because const and volatile on functions are restrictions + that say the function will not do certain things, + it is okay to use a const or volatile function + where an ordinary one is wanted, but not vice-versa. */ + if (TYPE_QUALS_NO_ADDR_SPACE (ttl) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) + PEDWARN_FOR_QUALIFIERS (location, expr_loc, + OPT_Wdiscarded_qualifiers, + G_("passing argument %d of %qE makes " + "%q#v qualified function pointer " + "from unqualified"), + G_("assignment makes %q#v qualified function " + "pointer from unqualified"), + G_("initialization makes %q#v qualified " + "function pointer from unqualified"), + G_("return makes %q#v qualified function " + "pointer from unqualified"), + TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)); + } + } + /* Avoid warning about the volatile ObjC EH puts on decls. */ + else if (!objc_ok) + { + switch (errtype) + { + case ic_argpass: + { + auto_diagnostic_group d; + range_label_for_type_mismatch rhs_label (rhstype, type); + gcc_rich_location richloc (expr_loc, &rhs_label); + if (pedwarn (&richloc, OPT_Wincompatible_pointer_types, + "passing argument %d of %qE from incompatible " + "pointer type", parmnum, rname)) + inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype); + } + break; + case ic_assign: + if (bltin) + pedwarn (location, OPT_Wincompatible_pointer_types, + "assignment to %qT from pointer to " + "%qD with incompatible type %qT", + type, bltin, rhstype); + else + pedwarn (location, OPT_Wincompatible_pointer_types, + "assignment to %qT from incompatible pointer type %qT", + type, rhstype); + break; + case ic_init: + case ic_init_const: + if (bltin) + pedwarn_init (location, OPT_Wincompatible_pointer_types, + "initialization of %qT from pointer to " + "%qD with incompatible type %qT", + type, bltin, rhstype); + else + pedwarn_init (location, OPT_Wincompatible_pointer_types, + "initialization of %qT from incompatible " + "pointer type %qT", + type, rhstype); + break; + case ic_return: + if (bltin) + pedwarn (location, OPT_Wincompatible_pointer_types, + "returning pointer to %qD of type %qT from " + "a function with incompatible type %qT", + bltin, rhstype, type); + else + pedwarn (location, OPT_Wincompatible_pointer_types, + "returning %qT from a function with incompatible " + "return type %qT", rhstype, type); + break; + default: + gcc_unreachable (); + } + } + + /* If RHS isn't an address, check pointer or array of packed + struct or union. */ + warn_for_address_or_pointer_of_packed_member (type, orig_rhs); + + return convert (type, rhs); + } + else if (codel == POINTER_TYPE && coder == ARRAY_TYPE) + { + /* ??? This should not be an error when inlining calls to + unprototyped functions. */ + const char msg[] = "invalid use of non-lvalue array"; + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); + return error_mark_node; + } + else if (codel == POINTER_TYPE && coder == INTEGER_TYPE) + { + /* An explicit constant 0 can convert to a pointer, + or one that results from arithmetic, even including + a cast to integer type. */ + if (!null_pointer_constant) + switch (errtype) + { + case ic_argpass: + { + auto_diagnostic_group d; + range_label_for_type_mismatch rhs_label (rhstype, type); + gcc_rich_location richloc (expr_loc, &rhs_label); + if (pedwarn (&richloc, OPT_Wint_conversion, + "passing argument %d of %qE makes pointer from " + "integer without a cast", parmnum, rname)) + inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype); + } + break; + case ic_assign: + pedwarn (location, OPT_Wint_conversion, + "assignment to %qT from %qT makes pointer from integer " + "without a cast", type, rhstype); + break; + case ic_init: + case ic_init_const: + pedwarn_init (location, OPT_Wint_conversion, + "initialization of %qT from %qT makes pointer from " + "integer without a cast", type, rhstype); + break; + case ic_return: + pedwarn (location, OPT_Wint_conversion, "returning %qT from a " + "function with return type %qT makes pointer from " + "integer without a cast", rhstype, type); + break; + default: + gcc_unreachable (); + } + + return convert (type, rhs); + } + else if (codel == INTEGER_TYPE && coder == POINTER_TYPE) + { + switch (errtype) + { + case ic_argpass: + { + auto_diagnostic_group d; + range_label_for_type_mismatch rhs_label (rhstype, type); + gcc_rich_location richloc (expr_loc, &rhs_label); + if (pedwarn (&richloc, OPT_Wint_conversion, + "passing argument %d of %qE makes integer from " + "pointer without a cast", parmnum, rname)) + inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype); + } + break; + case ic_assign: + pedwarn (location, OPT_Wint_conversion, + "assignment to %qT from %qT makes integer from pointer " + "without a cast", type, rhstype); + break; + case ic_init: + case ic_init_const: + pedwarn_init (location, OPT_Wint_conversion, + "initialization of %qT from %qT makes integer from " + "pointer without a cast", type, rhstype); + break; + case ic_return: + pedwarn (location, OPT_Wint_conversion, "returning %qT from a " + "function with return type %qT makes integer from " + "pointer without a cast", rhstype, type); + break; + default: + gcc_unreachable (); + } + + return convert (type, rhs); + } + else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE) + { + tree ret; + bool save = in_late_binary_op; + in_late_binary_op = true; + ret = convert (type, rhs); + in_late_binary_op = save; + return ret; + } + + switch (errtype) + { + case ic_argpass: + { + auto_diagnostic_group d; + range_label_for_type_mismatch rhs_label (rhstype, type); + gcc_rich_location richloc (expr_loc, &rhs_label); + const char msg[] = G_("incompatible type for argument %d of %qE"); + if (warnopt) + warning_at (expr_loc, warnopt, msg, parmnum, rname); + else + error_at (&richloc, msg, parmnum, rname); + inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype); + } + break; + case ic_assign: + { + const char msg[] + = G_("incompatible types when assigning to type %qT from type %qT"); + if (warnopt) + warning_at (expr_loc, 0, msg, type, rhstype); + else + error_at (expr_loc, msg, type, rhstype); + break; + } + case ic_init: + case ic_init_const: + { + const char msg[] + = G_("incompatible types when initializing type %qT using type %qT"); + if (warnopt) + warning_at (location, 0, msg, type, rhstype); + else + error_at (location, msg, type, rhstype); + break; + } + case ic_return: + { + const char msg[] + = G_("incompatible types when returning type %qT but %qT was expected"); + if (warnopt) + warning_at (location, 0, msg, rhstype, type); + else + error_at (location, msg, rhstype, type); + break; + } + default: + gcc_unreachable (); + } + + return error_mark_node; +} + +/* If VALUE is a compound expr all of whose expressions are constant, then + return its value. Otherwise, return error_mark_node. + + This is for handling COMPOUND_EXPRs as initializer elements + which is allowed with a warning when -pedantic is specified. */ + +static tree +valid_compound_expr_initializer (tree value, tree endtype) +{ + if (TREE_CODE (value) == COMPOUND_EXPR) + { + if (valid_compound_expr_initializer (TREE_OPERAND (value, 0), endtype) + == error_mark_node) + return error_mark_node; + return valid_compound_expr_initializer (TREE_OPERAND (value, 1), + endtype); + } + else if (!initializer_constant_valid_p (value, endtype)) + return error_mark_node; + else + return value; +} + +/* Perform appropriate conversions on the initial value of a variable, + store it in the declaration DECL, + and print any error messages that are appropriate. + If ORIGTYPE is not NULL_TREE, it is the original type of INIT. + If the init is invalid, store an ERROR_MARK. + + INIT_LOC is the location of the initial value. */ + +void +store_init_value (location_t init_loc, tree decl, tree init, tree origtype) +{ + tree value, type; + bool npc = false; + + /* If variable's type was invalidly declared, just ignore it. */ + + type = TREE_TYPE (decl); + if (TREE_CODE (type) == ERROR_MARK) + return; + + /* Digest the specified initializer into an expression. */ + + if (init) + npc = null_pointer_constant_p (init); + value = digest_init (init_loc, type, init, origtype, npc, + true, TREE_STATIC (decl)); + + /* Store the expression if valid; else report error. */ + + if (!in_system_header_at (input_location) + && AGGREGATE_TYPE_P (TREE_TYPE (decl)) && !TREE_STATIC (decl)) + warning (OPT_Wtraditional, "traditional C rejects automatic " + "aggregate initialization"); + + if (value != error_mark_node || TREE_CODE (decl) != FUNCTION_DECL) + DECL_INITIAL (decl) = value; + + /* ANSI wants warnings about out-of-range constant initializers. */ + STRIP_TYPE_NOPS (value); + if (TREE_STATIC (decl)) + constant_expression_warning (value); + + /* Check if we need to set array size from compound literal size. */ + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) == NULL_TREE + && value != error_mark_node) + { + tree inside_init = init; + + STRIP_TYPE_NOPS (inside_init); + inside_init = fold (inside_init); + + if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) + { + tree cldecl = COMPOUND_LITERAL_EXPR_DECL (inside_init); + + if (TYPE_DOMAIN (TREE_TYPE (cldecl))) + { + /* For int foo[] = (int [3]){1}; we need to set array size + now since later on array initializer will be just the + brace enclosed list of the compound literal. */ + tree etype = strip_array_types (TREE_TYPE (decl)); + type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + TYPE_DOMAIN (type) = TYPE_DOMAIN (TREE_TYPE (cldecl)); + layout_type (type); + layout_decl (cldecl, 0); + TREE_TYPE (decl) + = c_build_qualified_type (type, TYPE_QUALS (etype)); + } + } + } +} + +/* Methods for storing and printing names for error messages. */ + +/* Implement a spelling stack that allows components of a name to be pushed + and popped. Each element on the stack is this structure. */ + +struct spelling +{ + int kind; + union + { + unsigned HOST_WIDE_INT i; + const char *s; + } u; +}; + +#define SPELLING_STRING 1 +#define SPELLING_MEMBER 2 +#define SPELLING_BOUNDS 3 + +static struct spelling *spelling; /* Next stack element (unused). */ +static struct spelling *spelling_base; /* Spelling stack base. */ +static int spelling_size; /* Size of the spelling stack. */ + +/* Macros to save and restore the spelling stack around push_... functions. + Alternative to SAVE_SPELLING_STACK. */ + +#define SPELLING_DEPTH() (spelling - spelling_base) +#define RESTORE_SPELLING_DEPTH(DEPTH) (spelling = spelling_base + (DEPTH)) + +/* Push an element on the spelling stack with type KIND and assign VALUE + to MEMBER. */ + +#define PUSH_SPELLING(KIND, VALUE, MEMBER) \ +{ \ + int depth = SPELLING_DEPTH (); \ + \ + if (depth >= spelling_size) \ + { \ + spelling_size += 10; \ + spelling_base = XRESIZEVEC (struct spelling, spelling_base, \ + spelling_size); \ + RESTORE_SPELLING_DEPTH (depth); \ + } \ + \ + spelling->kind = (KIND); \ + spelling->MEMBER = (VALUE); \ + spelling++; \ +} + +/* Push STRING on the stack. Printed literally. */ + +static void +push_string (const char *string) +{ + PUSH_SPELLING (SPELLING_STRING, string, u.s); +} + +/* Push a member name on the stack. Printed as '.' STRING. */ + +static void +push_member_name (tree decl) +{ + const char *const string + = (DECL_NAME (decl) + ? identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (decl))) + : _("")); + PUSH_SPELLING (SPELLING_MEMBER, string, u.s); +} + +/* Push an array bounds on the stack. Printed as [BOUNDS]. */ + +static void +push_array_bounds (unsigned HOST_WIDE_INT bounds) +{ + PUSH_SPELLING (SPELLING_BOUNDS, bounds, u.i); +} + +/* Compute the maximum size in bytes of the printed spelling. */ + +static int +spelling_length (void) +{ + int size = 0; + struct spelling *p; + + for (p = spelling_base; p < spelling; p++) + { + if (p->kind == SPELLING_BOUNDS) + size += 25; + else + size += strlen (p->u.s) + 1; + } + + return size; +} + +/* Print the spelling to BUFFER and return it. */ + +static char * +print_spelling (char *buffer) +{ + char *d = buffer; + struct spelling *p; + + for (p = spelling_base; p < spelling; p++) + if (p->kind == SPELLING_BOUNDS) + { + sprintf (d, "[" HOST_WIDE_INT_PRINT_UNSIGNED "]", p->u.i); + d += strlen (d); + } + else + { + const char *s; + if (p->kind == SPELLING_MEMBER) + *d++ = '.'; + for (s = p->u.s; (*d = *s++); d++) + ; + } + *d++ = '\0'; + return buffer; +} + +/* Digest the parser output INIT as an initializer for type TYPE. + Return a C expression of type TYPE to represent the initial value. + + If ORIGTYPE is not NULL_TREE, it is the original type of INIT. + + NULL_POINTER_CONSTANT is true if INIT is a null pointer constant. + + If INIT is a string constant, STRICT_STRING is true if it is + unparenthesized or we should not warn here for it being parenthesized. + For other types of INIT, STRICT_STRING is not used. + + INIT_LOC is the location of the INIT. + + REQUIRE_CONSTANT requests an error if non-constant initializers or + elements are seen. */ + +static tree +digest_init (location_t init_loc, tree type, tree init, tree origtype, + bool null_pointer_constant, bool strict_string, + int require_constant) +{ + enum tree_code code = TREE_CODE (type); + tree inside_init = init; + tree semantic_type = NULL_TREE; + bool maybe_const = true; + + if (type == error_mark_node + || !init + || error_operand_p (init)) + return error_mark_node; + + STRIP_TYPE_NOPS (inside_init); + + if (!c_in_omp_for) + { + if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR) + { + semantic_type = TREE_TYPE (inside_init); + inside_init = TREE_OPERAND (inside_init, 0); + } + inside_init = c_fully_fold (inside_init, require_constant, &maybe_const); + } + + /* Initialization of an array of chars from a string constant + optionally enclosed in braces. */ + + if (code == ARRAY_TYPE && inside_init + && TREE_CODE (inside_init) == STRING_CST) + { + tree typ1 + = (TYPE_ATOMIC (TREE_TYPE (type)) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (TREE_TYPE (type)), + TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (TREE_TYPE (type))); + /* Note that an array could be both an array of character type + and an array of wchar_t if wchar_t is signed char or unsigned + char. */ + bool char_array = (typ1 == char_type_node + || typ1 == signed_char_type_node + || typ1 == unsigned_char_type_node); + bool wchar_array = !!comptypes (typ1, wchar_type_node); + bool char16_array = !!comptypes (typ1, char16_type_node); + bool char32_array = !!comptypes (typ1, char32_type_node); + + if (char_array || wchar_array || char16_array || char32_array) + { + struct c_expr expr; + tree typ2 = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init))); + bool incompat_string_cst = false; + expr.value = inside_init; + expr.original_code = (strict_string ? STRING_CST : ERROR_MARK); + expr.original_type = NULL; + maybe_warn_string_init (init_loc, type, expr); + + if (TYPE_DOMAIN (type) && !TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + pedwarn_init (init_loc, OPT_Wpedantic, + "initialization of a flexible array member"); + + if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), + TYPE_MAIN_VARIANT (type))) + return inside_init; + + if (char_array) + { + if (typ2 != char_type_node) + incompat_string_cst = true; + } + else if (!comptypes (typ1, typ2)) + incompat_string_cst = true; + + if (incompat_string_cst) + { + error_init (init_loc, "cannot initialize array of %qT from " + "a string literal with type array of %qT", + typ1, typ2); + return error_mark_node; + } + + if (TYPE_DOMAIN (type) != NULL_TREE + && TYPE_SIZE (type) != NULL_TREE + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST) + { + unsigned HOST_WIDE_INT len = TREE_STRING_LENGTH (inside_init); + unsigned unit = TYPE_PRECISION (typ1) / BITS_PER_UNIT; + + /* Subtract the size of a single (possibly wide) character + because it's ok to ignore the terminating null char + that is counted in the length of the constant. */ + if (compare_tree_int (TYPE_SIZE_UNIT (type), len - unit) < 0) + pedwarn_init (init_loc, 0, + ("initializer-string for array of %qT " + "is too long"), typ1); + else if (warn_cxx_compat + && compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0) + warning_at (init_loc, OPT_Wc___compat, + ("initializer-string for array of %qT " + "is too long for C++"), typ1); + if (compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0) + { + unsigned HOST_WIDE_INT size + = tree_to_uhwi (TYPE_SIZE_UNIT (type)); + const char *p = TREE_STRING_POINTER (inside_init); + + inside_init = build_string (size, p); + } + } + + TREE_TYPE (inside_init) = type; + return inside_init; + } + else if (INTEGRAL_TYPE_P (typ1)) + { + error_init (init_loc, "array of inappropriate type initialized " + "from string constant"); + return error_mark_node; + } + } + + /* Build a VECTOR_CST from a *constant* vector constructor. If the + vector constructor is not constant (e.g. {1,2,3,foo()}) then punt + below and handle as a constructor. */ + if (code == VECTOR_TYPE + && VECTOR_TYPE_P (TREE_TYPE (inside_init)) + && vector_types_convertible_p (TREE_TYPE (inside_init), type, true) + && TREE_CONSTANT (inside_init)) + { + if (TREE_CODE (inside_init) == VECTOR_CST + && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), + TYPE_MAIN_VARIANT (type))) + return inside_init; + + if (TREE_CODE (inside_init) == CONSTRUCTOR) + { + unsigned HOST_WIDE_INT ix; + tree value; + bool constant_p = true; + + /* Iterate through elements and check if all constructor + elements are *_CSTs. */ + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (inside_init), ix, value) + if (!CONSTANT_CLASS_P (value)) + { + constant_p = false; + break; + } + + if (constant_p) + return build_vector_from_ctor (type, + CONSTRUCTOR_ELTS (inside_init)); + } + } + + if (warn_sequence_point) + verify_sequence_points (inside_init); + + /* Any type can be initialized + from an expression of the same type, optionally with braces. */ + + if (inside_init && TREE_TYPE (inside_init) != NULL_TREE + && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), + TYPE_MAIN_VARIANT (type)) + || (code == ARRAY_TYPE + && comptypes (TREE_TYPE (inside_init), type)) + || (gnu_vector_type_p (type) + && comptypes (TREE_TYPE (inside_init), type)) + || (code == POINTER_TYPE + && TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE + && comptypes (TREE_TYPE (TREE_TYPE (inside_init)), + TREE_TYPE (type))))) + { + if (code == POINTER_TYPE) + { + if (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE) + { + if (TREE_CODE (inside_init) == STRING_CST + || TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) + inside_init = array_to_pointer_conversion + (init_loc, inside_init); + else + { + error_init (init_loc, "invalid use of non-lvalue array"); + return error_mark_node; + } + } + } + + if (code == VECTOR_TYPE) + /* Although the types are compatible, we may require a + conversion. */ + inside_init = convert (type, inside_init); + + if (require_constant + && TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) + { + /* As an extension, allow initializing objects with static storage + duration with compound literals (which are then treated just as + the brace enclosed list they contain). Also allow this for + vectors, as we can only assign them with compound literals. */ + if (flag_isoc99 && code != VECTOR_TYPE) + pedwarn_init (init_loc, OPT_Wpedantic, "initializer element " + "is not constant"); + tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init); + inside_init = DECL_INITIAL (decl); + } + + if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST + && TREE_CODE (inside_init) != CONSTRUCTOR) + { + error_init (init_loc, "array initialized from non-constant array " + "expression"); + return error_mark_node; + } + + /* Compound expressions can only occur here if -Wpedantic or + -pedantic-errors is specified. In the later case, we always want + an error. In the former case, we simply want a warning. */ + if (require_constant && pedantic + && TREE_CODE (inside_init) == COMPOUND_EXPR) + { + inside_init + = valid_compound_expr_initializer (inside_init, + TREE_TYPE (inside_init)); + if (inside_init == error_mark_node) + error_init (init_loc, "initializer element is not constant"); + else + pedwarn_init (init_loc, OPT_Wpedantic, + "initializer element is not constant"); + if (flag_pedantic_errors) + inside_init = error_mark_node; + } + else if (require_constant + && !initializer_constant_valid_p (inside_init, + TREE_TYPE (inside_init))) + { + error_init (init_loc, "initializer element is not constant"); + inside_init = error_mark_node; + } + else if (require_constant && !maybe_const) + pedwarn_init (init_loc, OPT_Wpedantic, + "initializer element is not a constant expression"); + + /* Added to enable additional -Wsuggest-attribute=format warnings. */ + if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE) + inside_init = convert_for_assignment (init_loc, UNKNOWN_LOCATION, + type, inside_init, origtype, + (require_constant + ? ic_init_const + : ic_init), null_pointer_constant, + NULL_TREE, NULL_TREE, 0); + return inside_init; + } + + /* Handle scalar types, including conversions. */ + + if (code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE + || code == POINTER_TYPE || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE + || code == COMPLEX_TYPE || code == VECTOR_TYPE) + { + if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE + && (TREE_CODE (init) == STRING_CST + || TREE_CODE (init) == COMPOUND_LITERAL_EXPR)) + inside_init = init = array_to_pointer_conversion (init_loc, init); + if (semantic_type) + inside_init = build1 (EXCESS_PRECISION_EXPR, semantic_type, + inside_init); + inside_init + = convert_for_assignment (init_loc, UNKNOWN_LOCATION, type, + inside_init, origtype, + require_constant ? ic_init_const : ic_init, + null_pointer_constant, NULL_TREE, NULL_TREE, + 0); + + /* Check to see if we have already given an error message. */ + if (inside_init == error_mark_node) + ; + else if (require_constant && !TREE_CONSTANT (inside_init)) + { + error_init (init_loc, "initializer element is not constant"); + inside_init = error_mark_node; + } + else if (require_constant + && !initializer_constant_valid_p (inside_init, + TREE_TYPE (inside_init))) + { + error_init (init_loc, "initializer element is not computable at " + "load time"); + inside_init = error_mark_node; + } + else if (require_constant && !maybe_const) + pedwarn_init (init_loc, OPT_Wpedantic, + "initializer element is not a constant expression"); + + return inside_init; + } + + /* Come here only for records and arrays. */ + + if (COMPLETE_TYPE_P (type) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + error_init (init_loc, "variable-sized object may not be initialized"); + return error_mark_node; + } + + error_init (init_loc, "invalid initializer"); + return error_mark_node; +} + +/* Handle initializers that use braces. */ + +/* Type of object we are accumulating a constructor for. + This type is always a RECORD_TYPE, UNION_TYPE or ARRAY_TYPE. */ +static tree constructor_type; + +/* For a RECORD_TYPE or UNION_TYPE, this is the chain of fields + left to fill. */ +static tree constructor_fields; + +/* For an ARRAY_TYPE, this is the specified index + at which to store the next element we get. */ +static tree constructor_index; + +/* For an ARRAY_TYPE, this is the maximum index. */ +static tree constructor_max_index; + +/* For a RECORD_TYPE, this is the first field not yet written out. */ +static tree constructor_unfilled_fields; + +/* For an ARRAY_TYPE, this is the index of the first element + not yet written out. */ +static tree constructor_unfilled_index; + +/* In a RECORD_TYPE, the byte index of the next consecutive field. + This is so we can generate gaps between fields, when appropriate. */ +static tree constructor_bit_index; + +/* If we are saving up the elements rather than allocating them, + this is the list of elements so far (in reverse order, + most recent first). */ +static vec *constructor_elements; + +/* 1 if constructor should be incrementally stored into a constructor chain, + 0 if all the elements should be kept in AVL tree. */ +static int constructor_incremental; + +/* 1 if so far this constructor's elements are all compile-time constants. */ +static int constructor_constant; + +/* 1 if so far this constructor's elements are all valid address constants. */ +static int constructor_simple; + +/* 1 if this constructor has an element that cannot be part of a + constant expression. */ +static int constructor_nonconst; + +/* 1 if this constructor is erroneous so far. */ +static int constructor_erroneous; + +/* 1 if this constructor is the universal zero initializer { 0 }. */ +static int constructor_zeroinit; + +/* Structure for managing pending initializer elements, organized as an + AVL tree. */ + +struct init_node +{ + struct init_node *left, *right; + struct init_node *parent; + int balance; + tree purpose; + tree value; + tree origtype; +}; + +/* Tree of pending elements at this constructor level. + These are elements encountered out of order + which belong at places we haven't reached yet in actually + writing the output. + Will never hold tree nodes across GC runs. */ +static struct init_node *constructor_pending_elts; + +/* The SPELLING_DEPTH of this constructor. */ +static int constructor_depth; + +/* DECL node for which an initializer is being read. + 0 means we are reading a constructor expression + such as (struct foo) {...}. */ +static tree constructor_decl; + +/* Nonzero if this is an initializer for a top-level decl. */ +static int constructor_top_level; + +/* Nonzero if there were any member designators in this initializer. */ +static int constructor_designated; + +/* Nesting depth of designator list. */ +static int designator_depth; + +/* Nonzero if there were diagnosed errors in this designator list. */ +static int designator_erroneous; + + +/* This stack has a level for each implicit or explicit level of + structuring in the initializer, including the outermost one. It + saves the values of most of the variables above. */ + +struct constructor_range_stack; + +struct constructor_stack +{ + struct constructor_stack *next; + tree type; + tree fields; + tree index; + tree max_index; + tree unfilled_index; + tree unfilled_fields; + tree bit_index; + vec *elements; + struct init_node *pending_elts; + int offset; + int depth; + /* If value nonzero, this value should replace the entire + constructor at this level. */ + struct c_expr replacement_value; + struct constructor_range_stack *range_stack; + char constant; + char simple; + char nonconst; + char implicit; + char erroneous; + char outer; + char incremental; + char designated; + int designator_depth; +}; + +static struct constructor_stack *constructor_stack; + +/* This stack represents designators from some range designator up to + the last designator in the list. */ + +struct constructor_range_stack +{ + struct constructor_range_stack *next, *prev; + struct constructor_stack *stack; + tree range_start; + tree index; + tree range_end; + tree fields; +}; + +static struct constructor_range_stack *constructor_range_stack; + +/* This stack records separate initializers that are nested. + Nested initializers can't happen in ANSI C, but GNU C allows them + in cases like { ... (struct foo) { ... } ... }. */ + +struct initializer_stack +{ + struct initializer_stack *next; + tree decl; + struct constructor_stack *constructor_stack; + struct constructor_range_stack *constructor_range_stack; + vec *elements; + struct spelling *spelling; + struct spelling *spelling_base; + int spelling_size; + char top_level; + char require_constant_value; + char require_constant_elements; + rich_location *missing_brace_richloc; +}; + +static struct initializer_stack *initializer_stack; + +/* Prepare to parse and output the initializer for variable DECL. */ + +void +start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level, + rich_location *richloc) +{ + const char *locus; + struct initializer_stack *p = XNEW (struct initializer_stack); + + p->decl = constructor_decl; + p->require_constant_value = require_constant_value; + p->require_constant_elements = require_constant_elements; + p->constructor_stack = constructor_stack; + p->constructor_range_stack = constructor_range_stack; + p->elements = constructor_elements; + p->spelling = spelling; + p->spelling_base = spelling_base; + p->spelling_size = spelling_size; + p->top_level = constructor_top_level; + p->next = initializer_stack; + p->missing_brace_richloc = richloc; + initializer_stack = p; + + constructor_decl = decl; + constructor_designated = 0; + constructor_top_level = top_level; + + if (decl != NULL_TREE && decl != error_mark_node) + { + require_constant_value = TREE_STATIC (decl); + require_constant_elements + = ((TREE_STATIC (decl) || (pedantic && !flag_isoc99)) + /* For a scalar, you can always use any value to initialize, + even within braces. */ + && AGGREGATE_TYPE_P (TREE_TYPE (decl))); + locus = identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (decl))); + } + else + { + require_constant_value = 0; + require_constant_elements = 0; + locus = _("(anonymous)"); + } + + constructor_stack = 0; + constructor_range_stack = 0; + + found_missing_braces = 0; + + spelling_base = 0; + spelling_size = 0; + RESTORE_SPELLING_DEPTH (0); + + if (locus) + push_string (locus); +} + +void +finish_init (void) +{ + struct initializer_stack *p = initializer_stack; + + /* Free the whole constructor stack of this initializer. */ + while (constructor_stack) + { + struct constructor_stack *q = constructor_stack; + constructor_stack = q->next; + XDELETE (q); + } + + gcc_assert (!constructor_range_stack); + + /* Pop back to the data of the outer initializer (if any). */ + XDELETE (spelling_base); + + constructor_decl = p->decl; + require_constant_value = p->require_constant_value; + require_constant_elements = p->require_constant_elements; + constructor_stack = p->constructor_stack; + constructor_range_stack = p->constructor_range_stack; + constructor_elements = p->elements; + spelling = p->spelling; + spelling_base = p->spelling_base; + spelling_size = p->spelling_size; + constructor_top_level = p->top_level; + initializer_stack = p->next; + XDELETE (p); +} + +/* Call here when we see the initializer is surrounded by braces. + This is instead of a call to push_init_level; + it is matched by a call to pop_init_level. + + TYPE is the type to initialize, for a constructor expression. + For an initializer for a decl, TYPE is zero. */ + +void +really_start_incremental_init (tree type) +{ + struct constructor_stack *p = XNEW (struct constructor_stack); + + if (type == NULL_TREE) + type = TREE_TYPE (constructor_decl); + + if (VECTOR_TYPE_P (type) + && TYPE_VECTOR_OPAQUE (type)) + error ("opaque vector types cannot be initialized"); + + p->type = constructor_type; + p->fields = constructor_fields; + p->index = constructor_index; + p->max_index = constructor_max_index; + p->unfilled_index = constructor_unfilled_index; + p->unfilled_fields = constructor_unfilled_fields; + p->bit_index = constructor_bit_index; + p->elements = constructor_elements; + p->constant = constructor_constant; + p->simple = constructor_simple; + p->nonconst = constructor_nonconst; + p->erroneous = constructor_erroneous; + p->pending_elts = constructor_pending_elts; + p->depth = constructor_depth; + p->replacement_value.value = 0; + p->replacement_value.original_code = ERROR_MARK; + p->replacement_value.original_type = NULL; + p->implicit = 0; + p->range_stack = 0; + p->outer = 0; + p->incremental = constructor_incremental; + p->designated = constructor_designated; + p->designator_depth = designator_depth; + p->next = 0; + constructor_stack = p; + + constructor_constant = 1; + constructor_simple = 1; + constructor_nonconst = 0; + constructor_depth = SPELLING_DEPTH (); + constructor_elements = NULL; + constructor_pending_elts = 0; + constructor_type = type; + constructor_incremental = 1; + constructor_designated = 0; + constructor_zeroinit = 1; + designator_depth = 0; + designator_erroneous = 0; + + if (RECORD_OR_UNION_TYPE_P (constructor_type)) + { + constructor_fields = TYPE_FIELDS (constructor_type); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_fields != NULL_TREE + && DECL_UNNAMED_BIT_FIELD (constructor_fields)) + constructor_fields = DECL_CHAIN (constructor_fields); + + constructor_unfilled_fields = constructor_fields; + constructor_bit_index = bitsize_zero_node; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (TYPE_DOMAIN (constructor_type)) + { + constructor_max_index + = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); + + /* Detect non-empty initializations of zero-length arrays. */ + if (constructor_max_index == NULL_TREE + && TYPE_SIZE (constructor_type)) + constructor_max_index = integer_minus_one_node; + + /* constructor_max_index needs to be an INTEGER_CST. Attempts + to initialize VLAs will cause a proper error; avoid tree + checking errors as well by setting a safe value. */ + if (constructor_max_index + && TREE_CODE (constructor_max_index) != INTEGER_CST) + constructor_max_index = integer_minus_one_node; + + constructor_index + = convert (bitsizetype, + TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); + } + else + { + constructor_index = bitsize_zero_node; + constructor_max_index = NULL_TREE; + } + + constructor_unfilled_index = constructor_index; + } + else if (gnu_vector_type_p (constructor_type)) + { + /* Vectors are like simple fixed-size arrays. */ + constructor_max_index = + bitsize_int (TYPE_VECTOR_SUBPARTS (constructor_type) - 1); + constructor_index = bitsize_zero_node; + constructor_unfilled_index = constructor_index; + } + else + { + /* Handle the case of int x = {5}; */ + constructor_fields = constructor_type; + constructor_unfilled_fields = constructor_type; + } +} + +extern location_t last_init_list_comma; + +/* Called when we see an open brace for a nested initializer. Finish + off any pending levels with implicit braces. */ +void +finish_implicit_inits (location_t loc, struct obstack *braced_init_obstack) +{ + while (constructor_stack->implicit) + { + if (RECORD_OR_UNION_TYPE_P (constructor_type) + && constructor_fields == NULL_TREE) + process_init_element (input_location, + pop_init_level (loc, 1, braced_init_obstack, + last_init_list_comma), + true, braced_init_obstack); + else if (TREE_CODE (constructor_type) == ARRAY_TYPE + && constructor_max_index + && tree_int_cst_lt (constructor_max_index, + constructor_index)) + process_init_element (input_location, + pop_init_level (loc, 1, braced_init_obstack, + last_init_list_comma), + true, braced_init_obstack); + else + break; + } +} + +/* Push down into a subobject, for initialization. + If this is for an explicit set of braces, IMPLICIT is 0. + If it is because the next element belongs at a lower level, + IMPLICIT is 1 (or 2 if the push is because of designator list). */ + +void +push_init_level (location_t loc, int implicit, + struct obstack *braced_init_obstack) +{ + struct constructor_stack *p; + tree value = NULL_TREE; + + /* Unless this is an explicit brace, we need to preserve previous + content if any. */ + if (implicit) + { + if (RECORD_OR_UNION_TYPE_P (constructor_type) && constructor_fields) + value = find_init_member (constructor_fields, braced_init_obstack); + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + value = find_init_member (constructor_index, braced_init_obstack); + } + + p = XNEW (struct constructor_stack); + p->type = constructor_type; + p->fields = constructor_fields; + p->index = constructor_index; + p->max_index = constructor_max_index; + p->unfilled_index = constructor_unfilled_index; + p->unfilled_fields = constructor_unfilled_fields; + p->bit_index = constructor_bit_index; + p->elements = constructor_elements; + p->constant = constructor_constant; + p->simple = constructor_simple; + p->nonconst = constructor_nonconst; + p->erroneous = constructor_erroneous; + p->pending_elts = constructor_pending_elts; + p->depth = constructor_depth; + p->replacement_value.value = NULL_TREE; + p->replacement_value.original_code = ERROR_MARK; + p->replacement_value.original_type = NULL; + p->implicit = implicit; + p->outer = 0; + p->incremental = constructor_incremental; + p->designated = constructor_designated; + p->designator_depth = designator_depth; + p->next = constructor_stack; + p->range_stack = 0; + constructor_stack = p; + + constructor_constant = 1; + constructor_simple = 1; + constructor_nonconst = 0; + constructor_depth = SPELLING_DEPTH (); + constructor_elements = NULL; + constructor_incremental = 1; + constructor_designated = 0; + constructor_pending_elts = 0; + if (!implicit) + { + p->range_stack = constructor_range_stack; + constructor_range_stack = 0; + designator_depth = 0; + designator_erroneous = 0; + } + + /* Don't die if an entire brace-pair level is superfluous + in the containing level. */ + if (constructor_type == NULL_TREE) + ; + else if (RECORD_OR_UNION_TYPE_P (constructor_type)) + { + /* Don't die if there are extra init elts at the end. */ + if (constructor_fields == NULL_TREE) + constructor_type = NULL_TREE; + else + { + constructor_type = TREE_TYPE (constructor_fields); + push_member_name (constructor_fields); + constructor_depth++; + } + /* If upper initializer is designated, then mark this as + designated too to prevent bogus warnings. */ + constructor_designated = p->designated; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + constructor_type = TREE_TYPE (constructor_type); + push_array_bounds (tree_to_uhwi (constructor_index)); + constructor_depth++; + } + + if (constructor_type == NULL_TREE) + { + error_init (loc, "extra brace group at end of initializer"); + constructor_fields = NULL_TREE; + constructor_unfilled_fields = NULL_TREE; + return; + } + + if (value && TREE_CODE (value) == CONSTRUCTOR) + { + constructor_constant = TREE_CONSTANT (value); + constructor_simple = TREE_STATIC (value); + constructor_nonconst = CONSTRUCTOR_NON_CONST (value); + constructor_elements = CONSTRUCTOR_ELTS (value); + if (!vec_safe_is_empty (constructor_elements) + && (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == ARRAY_TYPE)) + set_nonincremental_init (braced_init_obstack); + } + + if (implicit == 1) + { + found_missing_braces = 1; + if (initializer_stack->missing_brace_richloc) + initializer_stack->missing_brace_richloc->add_fixit_insert_before + (loc, "{"); + } + + if (RECORD_OR_UNION_TYPE_P (constructor_type)) + { + constructor_fields = TYPE_FIELDS (constructor_type); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_fields != NULL_TREE + && DECL_UNNAMED_BIT_FIELD (constructor_fields)) + constructor_fields = DECL_CHAIN (constructor_fields); + + constructor_unfilled_fields = constructor_fields; + constructor_bit_index = bitsize_zero_node; + } + else if (gnu_vector_type_p (constructor_type)) + { + /* Vectors are like simple fixed-size arrays. */ + constructor_max_index = + bitsize_int (TYPE_VECTOR_SUBPARTS (constructor_type) - 1); + constructor_index = bitsize_int (0); + constructor_unfilled_index = constructor_index; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (TYPE_DOMAIN (constructor_type)) + { + constructor_max_index + = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); + + /* Detect non-empty initializations of zero-length arrays. */ + if (constructor_max_index == NULL_TREE + && TYPE_SIZE (constructor_type)) + constructor_max_index = integer_minus_one_node; + + /* constructor_max_index needs to be an INTEGER_CST. Attempts + to initialize VLAs will cause a proper error; avoid tree + checking errors as well by setting a safe value. */ + if (constructor_max_index + && TREE_CODE (constructor_max_index) != INTEGER_CST) + constructor_max_index = integer_minus_one_node; + + constructor_index + = convert (bitsizetype, + TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); + } + else + constructor_index = bitsize_zero_node; + + constructor_unfilled_index = constructor_index; + if (value && TREE_CODE (value) == STRING_CST) + { + /* We need to split the char/wchar array into individual + characters, so that we don't have to special case it + everywhere. */ + set_nonincremental_init_from_string (value, braced_init_obstack); + } + } + else + { + if (constructor_type != error_mark_node) + warning_init (input_location, 0, "braces around scalar initializer"); + constructor_fields = constructor_type; + constructor_unfilled_fields = constructor_type; + } +} + +/* At the end of an implicit or explicit brace level, + finish up that level of constructor. If a single expression + with redundant braces initialized that level, return the + c_expr structure for that expression. Otherwise, the original_code + element is set to ERROR_MARK. + If we were outputting the elements as they are read, return 0 as the value + from inner levels (process_init_element ignores that), + but return error_mark_node as the value from the outermost level + (that's what we want to put in DECL_INITIAL). + Otherwise, return a CONSTRUCTOR expression as the value. */ + +struct c_expr +pop_init_level (location_t loc, int implicit, + struct obstack *braced_init_obstack, + location_t insert_before) +{ + struct constructor_stack *p; + struct c_expr ret; + ret.value = NULL_TREE; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + + if (implicit == 0) + { + /* When we come to an explicit close brace, + pop any inner levels that didn't have explicit braces. */ + while (constructor_stack->implicit) + process_init_element (input_location, + pop_init_level (loc, 1, braced_init_obstack, + insert_before), + true, braced_init_obstack); + gcc_assert (!constructor_range_stack); + } + else + if (initializer_stack->missing_brace_richloc) + initializer_stack->missing_brace_richloc->add_fixit_insert_before + (insert_before, "}"); + + /* Now output all pending elements. */ + constructor_incremental = 1; + output_pending_init_elements (1, braced_init_obstack); + + p = constructor_stack; + + /* Error for initializing a flexible array member, or a zero-length + array member in an inappropriate context. */ + if (constructor_type && constructor_fields + && TREE_CODE (constructor_type) == ARRAY_TYPE + && TYPE_DOMAIN (constructor_type) + && !TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type))) + { + /* Silently discard empty initializations. The parser will + already have pedwarned for empty brackets. */ + if (integer_zerop (constructor_unfilled_index)) + constructor_type = NULL_TREE; + else + { + gcc_assert (!TYPE_SIZE (constructor_type)); + + if (constructor_depth > 2) + error_init (loc, "initialization of flexible array member in a nested context"); + else + pedwarn_init (loc, OPT_Wpedantic, + "initialization of a flexible array member"); + + /* We have already issued an error message for the existence + of a flexible array member not at the end of the structure. + Discard the initializer so that we do not die later. */ + if (DECL_CHAIN (constructor_fields) != NULL_TREE) + constructor_type = NULL_TREE; + } + } + + switch (vec_safe_length (constructor_elements)) + { + case 0: + /* Initialization with { } counts as zeroinit. */ + constructor_zeroinit = 1; + break; + case 1: + /* This might be zeroinit as well. */ + if (integer_zerop ((*constructor_elements)[0].value)) + constructor_zeroinit = 1; + break; + default: + /* If the constructor has more than one element, it can't be { 0 }. */ + constructor_zeroinit = 0; + break; + } + + /* Warn when some structs are initialized with direct aggregation. */ + if (!implicit && found_missing_braces && warn_missing_braces + && !constructor_zeroinit) + { + gcc_assert (initializer_stack->missing_brace_richloc); + warning_at (initializer_stack->missing_brace_richloc, + OPT_Wmissing_braces, + "missing braces around initializer"); + } + + /* Warn when some struct elements are implicitly initialized to zero. */ + if (warn_missing_field_initializers + && constructor_type + && TREE_CODE (constructor_type) == RECORD_TYPE + && constructor_unfilled_fields) + { + /* Do not warn for flexible array members or zero-length arrays. */ + while (constructor_unfilled_fields + && (!DECL_SIZE (constructor_unfilled_fields) + || integer_zerop (DECL_SIZE (constructor_unfilled_fields)))) + constructor_unfilled_fields = DECL_CHAIN (constructor_unfilled_fields); + + if (constructor_unfilled_fields + /* Do not warn if this level of the initializer uses member + designators; it is likely to be deliberate. */ + && !constructor_designated + /* Do not warn about initializing with { 0 } or with { }. */ + && !constructor_zeroinit) + { + if (warning_at (input_location, OPT_Wmissing_field_initializers, + "missing initializer for field %qD of %qT", + constructor_unfilled_fields, + constructor_type)) + inform (DECL_SOURCE_LOCATION (constructor_unfilled_fields), + "%qD declared here", constructor_unfilled_fields); + } + } + + /* Pad out the end of the structure. */ + if (p->replacement_value.value) + /* If this closes a superfluous brace pair, + just pass out the element between them. */ + ret = p->replacement_value; + else if (constructor_type == NULL_TREE) + ; + else if (!RECORD_OR_UNION_TYPE_P (constructor_type) + && TREE_CODE (constructor_type) != ARRAY_TYPE + && !gnu_vector_type_p (constructor_type)) + { + /* A nonincremental scalar initializer--just return + the element, after verifying there is just one. */ + if (vec_safe_is_empty (constructor_elements)) + { + if (!constructor_erroneous && constructor_type != error_mark_node) + error_init (loc, "empty scalar initializer"); + ret.value = error_mark_node; + } + else if (vec_safe_length (constructor_elements) != 1) + { + error_init (loc, "extra elements in scalar initializer"); + ret.value = (*constructor_elements)[0].value; + } + else + ret.value = (*constructor_elements)[0].value; + } + else + { + if (constructor_erroneous) + ret.value = error_mark_node; + else + { + ret.value = build_constructor (constructor_type, + constructor_elements); + if (constructor_constant) + TREE_CONSTANT (ret.value) = 1; + if (constructor_constant && constructor_simple) + TREE_STATIC (ret.value) = 1; + if (constructor_nonconst) + CONSTRUCTOR_NON_CONST (ret.value) = 1; + } + } + + if (ret.value && TREE_CODE (ret.value) != CONSTRUCTOR) + { + if (constructor_nonconst) + ret.original_code = C_MAYBE_CONST_EXPR; + else if (ret.original_code == C_MAYBE_CONST_EXPR) + ret.original_code = ERROR_MARK; + } + + constructor_type = p->type; + constructor_fields = p->fields; + constructor_index = p->index; + constructor_max_index = p->max_index; + constructor_unfilled_index = p->unfilled_index; + constructor_unfilled_fields = p->unfilled_fields; + constructor_bit_index = p->bit_index; + constructor_elements = p->elements; + constructor_constant = p->constant; + constructor_simple = p->simple; + constructor_nonconst = p->nonconst; + constructor_erroneous = p->erroneous; + constructor_incremental = p->incremental; + constructor_designated = p->designated; + designator_depth = p->designator_depth; + constructor_pending_elts = p->pending_elts; + constructor_depth = p->depth; + if (!p->implicit) + constructor_range_stack = p->range_stack; + RESTORE_SPELLING_DEPTH (constructor_depth); + + constructor_stack = p->next; + XDELETE (p); + + if (ret.value == NULL_TREE && constructor_stack == 0) + ret.value = error_mark_node; + return ret; +} + +/* Common handling for both array range and field name designators. + ARRAY argument is nonzero for array ranges. Returns false for success. */ + +static bool +set_designator (location_t loc, bool array, + struct obstack *braced_init_obstack) +{ + tree subtype; + enum tree_code subcode; + + /* Don't die if an entire brace-pair level is superfluous + in the containing level, or for an erroneous type. */ + if (constructor_type == NULL_TREE || constructor_type == error_mark_node) + return true; + + /* If there were errors in this designator list already, bail out + silently. */ + if (designator_erroneous) + return true; + + /* Likewise for an initializer for a variable-size type. Those are + diagnosed in digest_init. */ + if (COMPLETE_TYPE_P (constructor_type) + && TREE_CODE (TYPE_SIZE (constructor_type)) != INTEGER_CST) + return true; + + if (!designator_depth) + { + gcc_assert (!constructor_range_stack); + + /* Designator list starts at the level of closest explicit + braces. */ + while (constructor_stack->implicit) + process_init_element (input_location, + pop_init_level (loc, 1, braced_init_obstack, + last_init_list_comma), + true, braced_init_obstack); + constructor_designated = 1; + return false; + } + + switch (TREE_CODE (constructor_type)) + { + case RECORD_TYPE: + case UNION_TYPE: + subtype = TREE_TYPE (constructor_fields); + if (subtype != error_mark_node) + subtype = TYPE_MAIN_VARIANT (subtype); + break; + case ARRAY_TYPE: + subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type)); + break; + default: + gcc_unreachable (); + } + + subcode = TREE_CODE (subtype); + if (array && subcode != ARRAY_TYPE) + { + error_init (loc, "array index in non-array initializer"); + return true; + } + else if (!array && subcode != RECORD_TYPE && subcode != UNION_TYPE) + { + error_init (loc, "field name not in record or union initializer"); + return true; + } + + constructor_designated = 1; + finish_implicit_inits (loc, braced_init_obstack); + push_init_level (loc, 2, braced_init_obstack); + return false; +} + +/* If there are range designators in designator list, push a new designator + to constructor_range_stack. RANGE_END is end of such stack range or + NULL_TREE if there is no range designator at this level. */ + +static void +push_range_stack (tree range_end, struct obstack * braced_init_obstack) +{ + struct constructor_range_stack *p; + + p = (struct constructor_range_stack *) + obstack_alloc (braced_init_obstack, + sizeof (struct constructor_range_stack)); + p->prev = constructor_range_stack; + p->next = 0; + p->fields = constructor_fields; + p->range_start = constructor_index; + p->index = constructor_index; + p->stack = constructor_stack; + p->range_end = range_end; + if (constructor_range_stack) + constructor_range_stack->next = p; + constructor_range_stack = p; +} + +/* Within an array initializer, specify the next index to be initialized. + FIRST is that index. If LAST is nonzero, then initialize a range + of indices, running from FIRST through LAST. */ + +void +set_init_index (location_t loc, tree first, tree last, + struct obstack *braced_init_obstack) +{ + if (set_designator (loc, true, braced_init_obstack)) + return; + + designator_erroneous = 1; + + if (!INTEGRAL_TYPE_P (TREE_TYPE (first)) + || (last && !INTEGRAL_TYPE_P (TREE_TYPE (last)))) + { + error_init (loc, "array index in initializer not of integer type"); + return; + } + + if (TREE_CODE (first) != INTEGER_CST) + { + first = c_fully_fold (first, false, NULL); + if (TREE_CODE (first) == INTEGER_CST) + pedwarn_init (loc, OPT_Wpedantic, + "array index in initializer is not " + "an integer constant expression"); + } + + if (last && TREE_CODE (last) != INTEGER_CST) + { + last = c_fully_fold (last, false, NULL); + if (TREE_CODE (last) == INTEGER_CST) + pedwarn_init (loc, OPT_Wpedantic, + "array index in initializer is not " + "an integer constant expression"); + } + + if (TREE_CODE (first) != INTEGER_CST) + error_init (loc, "nonconstant array index in initializer"); + else if (last != NULL_TREE && TREE_CODE (last) != INTEGER_CST) + error_init (loc, "nonconstant array index in initializer"); + else if (TREE_CODE (constructor_type) != ARRAY_TYPE) + error_init (loc, "array index in non-array initializer"); + else if (tree_int_cst_sgn (first) == -1) + error_init (loc, "array index in initializer exceeds array bounds"); + else if (constructor_max_index + && tree_int_cst_lt (constructor_max_index, first)) + error_init (loc, "array index in initializer exceeds array bounds"); + else + { + constant_expression_warning (first); + if (last) + constant_expression_warning (last); + constructor_index = convert (bitsizetype, first); + if (tree_int_cst_lt (constructor_index, first)) + { + constructor_index = copy_node (constructor_index); + TREE_OVERFLOW (constructor_index) = 1; + } + + if (last) + { + if (tree_int_cst_equal (first, last)) + last = NULL_TREE; + else if (tree_int_cst_lt (last, first)) + { + error_init (loc, "empty index range in initializer"); + last = NULL_TREE; + } + else + { + last = convert (bitsizetype, last); + if (constructor_max_index != NULL_TREE + && tree_int_cst_lt (constructor_max_index, last)) + { + error_init (loc, "array index range in initializer exceeds " + "array bounds"); + last = NULL_TREE; + } + } + } + + designator_depth++; + designator_erroneous = 0; + if (constructor_range_stack || last) + push_range_stack (last, braced_init_obstack); + } +} + +/* Within a struct initializer, specify the next field to be initialized. */ + +void +set_init_label (location_t loc, tree fieldname, location_t fieldname_loc, + struct obstack *braced_init_obstack) +{ + tree field; + + if (set_designator (loc, false, braced_init_obstack)) + return; + + designator_erroneous = 1; + + if (!RECORD_OR_UNION_TYPE_P (constructor_type)) + { + error_init (loc, "field name not in record or union initializer"); + return; + } + + field = lookup_field (constructor_type, fieldname); + + if (field == NULL_TREE) + { + tree guessed_id = lookup_field_fuzzy (constructor_type, fieldname); + if (guessed_id) + { + gcc_rich_location rich_loc (fieldname_loc); + rich_loc.add_fixit_misspelled_id (fieldname_loc, guessed_id); + error_at (&rich_loc, + "%qT has no member named %qE; did you mean %qE?", + constructor_type, fieldname, guessed_id); + } + else + error_at (fieldname_loc, "%qT has no member named %qE", + constructor_type, fieldname); + } + else + do + { + constructor_fields = TREE_VALUE (field); + designator_depth++; + designator_erroneous = 0; + if (constructor_range_stack) + push_range_stack (NULL_TREE, braced_init_obstack); + field = TREE_CHAIN (field); + if (field) + { + if (set_designator (loc, false, braced_init_obstack)) + return; + } + } + while (field != NULL_TREE); +} + +/* Add a new initializer to the tree of pending initializers. PURPOSE + identifies the initializer, either array index or field in a structure. + VALUE is the value of that index or field. If ORIGTYPE is not + NULL_TREE, it is the original type of VALUE. + + IMPLICIT is true if value comes from pop_init_level (1), + the new initializer has been merged with the existing one + and thus no warnings should be emitted about overriding an + existing initializer. */ + +static void +add_pending_init (location_t loc, tree purpose, tree value, tree origtype, + bool implicit, struct obstack *braced_init_obstack) +{ + struct init_node *p, **q, *r; + + q = &constructor_pending_elts; + p = 0; + + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + while (*q != 0) + { + p = *q; + if (tree_int_cst_lt (purpose, p->purpose)) + q = &p->left; + else if (tree_int_cst_lt (p->purpose, purpose)) + q = &p->right; + else + { + if (!implicit) + { + if (TREE_SIDE_EFFECTS (p->value)) + warning_init (loc, OPT_Woverride_init_side_effects, + "initialized field with side-effects " + "overwritten"); + else if (warn_override_init) + warning_init (loc, OPT_Woverride_init, + "initialized field overwritten"); + } + p->value = value; + p->origtype = origtype; + return; + } + } + } + else + { + tree bitpos; + + bitpos = bit_position (purpose); + while (*q != NULL) + { + p = *q; + if (tree_int_cst_lt (bitpos, bit_position (p->purpose))) + q = &p->left; + else if (p->purpose != purpose) + q = &p->right; + else + { + if (!implicit) + { + if (TREE_SIDE_EFFECTS (p->value)) + warning_init (loc, OPT_Woverride_init_side_effects, + "initialized field with side-effects " + "overwritten"); + else if (warn_override_init) + warning_init (loc, OPT_Woverride_init, + "initialized field overwritten"); + } + p->value = value; + p->origtype = origtype; + return; + } + } + } + + r = (struct init_node *) obstack_alloc (braced_init_obstack, + sizeof (struct init_node)); + r->purpose = purpose; + r->value = value; + r->origtype = origtype; + + *q = r; + r->parent = p; + r->left = 0; + r->right = 0; + r->balance = 0; + + while (p) + { + struct init_node *s; + + if (r == p->left) + { + if (p->balance == 0) + p->balance = -1; + else if (p->balance < 0) + { + if (r->balance < 0) + { + /* L rotation. */ + p->left = r->right; + if (p->left) + p->left->parent = p; + r->right = p; + + p->balance = 0; + r->balance = 0; + + s = p->parent; + p->parent = r; + r->parent = s; + if (s) + { + if (s->left == p) + s->left = r; + else + s->right = r; + } + else + constructor_pending_elts = r; + } + else + { + /* LR rotation. */ + struct init_node *t = r->right; + + r->right = t->left; + if (r->right) + r->right->parent = r; + t->left = r; + + p->left = t->right; + if (p->left) + p->left->parent = p; + t->right = p; + + p->balance = t->balance < 0; + r->balance = -(t->balance > 0); + t->balance = 0; + + s = p->parent; + p->parent = t; + r->parent = t; + t->parent = s; + if (s) + { + if (s->left == p) + s->left = t; + else + s->right = t; + } + else + constructor_pending_elts = t; + } + break; + } + else + { + /* p->balance == +1; growth of left side balances the node. */ + p->balance = 0; + break; + } + } + else /* r == p->right */ + { + if (p->balance == 0) + /* Growth propagation from right side. */ + p->balance++; + else if (p->balance > 0) + { + if (r->balance > 0) + { + /* R rotation. */ + p->right = r->left; + if (p->right) + p->right->parent = p; + r->left = p; + + p->balance = 0; + r->balance = 0; + + s = p->parent; + p->parent = r; + r->parent = s; + if (s) + { + if (s->left == p) + s->left = r; + else + s->right = r; + } + else + constructor_pending_elts = r; + } + else /* r->balance == -1 */ + { + /* RL rotation */ + struct init_node *t = r->left; + + r->left = t->right; + if (r->left) + r->left->parent = r; + t->right = r; + + p->right = t->left; + if (p->right) + p->right->parent = p; + t->left = p; + + r->balance = (t->balance < 0); + p->balance = -(t->balance > 0); + t->balance = 0; + + s = p->parent; + p->parent = t; + r->parent = t; + t->parent = s; + if (s) + { + if (s->left == p) + s->left = t; + else + s->right = t; + } + else + constructor_pending_elts = t; + } + break; + } + else + { + /* p->balance == -1; growth of right side balances the node. */ + p->balance = 0; + break; + } + } + + r = p; + p = p->parent; + } +} + +/* Build AVL tree from a sorted chain. */ + +static void +set_nonincremental_init (struct obstack * braced_init_obstack) +{ + unsigned HOST_WIDE_INT ix; + tree index, value; + + if (TREE_CODE (constructor_type) != RECORD_TYPE + && TREE_CODE (constructor_type) != ARRAY_TYPE) + return; + + FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value) + add_pending_init (input_location, index, value, NULL_TREE, true, + braced_init_obstack); + constructor_elements = NULL; + if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + constructor_unfilled_fields = TYPE_FIELDS (constructor_type); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_unfilled_fields != NULL_TREE + && DECL_UNNAMED_BIT_FIELD (constructor_unfilled_fields)) + constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields); + + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (TYPE_DOMAIN (constructor_type)) + constructor_unfilled_index + = convert (bitsizetype, + TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); + else + constructor_unfilled_index = bitsize_zero_node; + } + constructor_incremental = 0; +} + +/* Build AVL tree from a string constant. */ + +static void +set_nonincremental_init_from_string (tree str, + struct obstack * braced_init_obstack) +{ + tree value, purpose, type; + HOST_WIDE_INT val[2]; + const char *p, *end; + int byte, wchar_bytes, charwidth, bitpos; + + gcc_assert (TREE_CODE (constructor_type) == ARRAY_TYPE); + + wchar_bytes = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str))) / BITS_PER_UNIT; + charwidth = TYPE_PRECISION (char_type_node); + gcc_assert ((size_t) wchar_bytes * charwidth + <= ARRAY_SIZE (val) * HOST_BITS_PER_WIDE_INT); + type = TREE_TYPE (constructor_type); + p = TREE_STRING_POINTER (str); + end = p + TREE_STRING_LENGTH (str); + + for (purpose = bitsize_zero_node; + p < end + && !(constructor_max_index + && tree_int_cst_lt (constructor_max_index, purpose)); + purpose = size_binop (PLUS_EXPR, purpose, bitsize_one_node)) + { + if (wchar_bytes == 1) + { + val[0] = (unsigned char) *p++; + val[1] = 0; + } + else + { + val[1] = 0; + val[0] = 0; + for (byte = 0; byte < wchar_bytes; byte++) + { + if (BYTES_BIG_ENDIAN) + bitpos = (wchar_bytes - byte - 1) * charwidth; + else + bitpos = byte * charwidth; + val[bitpos / HOST_BITS_PER_WIDE_INT] + |= ((unsigned HOST_WIDE_INT) ((unsigned char) *p++)) + << (bitpos % HOST_BITS_PER_WIDE_INT); + } + } + + if (!TYPE_UNSIGNED (type)) + { + bitpos = ((wchar_bytes - 1) * charwidth) + HOST_BITS_PER_CHAR; + if (bitpos < HOST_BITS_PER_WIDE_INT) + { + if (val[0] & (HOST_WIDE_INT_1 << (bitpos - 1))) + { + val[0] |= HOST_WIDE_INT_M1U << bitpos; + val[1] = -1; + } + } + else if (bitpos == HOST_BITS_PER_WIDE_INT) + { + if (val[0] < 0) + val[1] = -1; + } + else if (val[1] & (HOST_WIDE_INT_1 + << (bitpos - 1 - HOST_BITS_PER_WIDE_INT))) + val[1] |= HOST_WIDE_INT_M1U << (bitpos - HOST_BITS_PER_WIDE_INT); + } + + value = wide_int_to_tree (type, + wide_int::from_array (val, 2, + HOST_BITS_PER_WIDE_INT * 2)); + add_pending_init (input_location, purpose, value, NULL_TREE, true, + braced_init_obstack); + } + + constructor_incremental = 0; +} + +/* Return value of FIELD in pending initializer or NULL_TREE if the field was + not initialized yet. */ + +static tree +find_init_member (tree field, struct obstack * braced_init_obstack) +{ + struct init_node *p; + + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (constructor_incremental + && tree_int_cst_lt (field, constructor_unfilled_index)) + set_nonincremental_init (braced_init_obstack); + + p = constructor_pending_elts; + while (p) + { + if (tree_int_cst_lt (field, p->purpose)) + p = p->left; + else if (tree_int_cst_lt (p->purpose, field)) + p = p->right; + else + return p->value; + } + } + else if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + tree bitpos = bit_position (field); + + if (constructor_incremental + && (!constructor_unfilled_fields + || tree_int_cst_lt (bitpos, + bit_position (constructor_unfilled_fields)))) + set_nonincremental_init (braced_init_obstack); + + p = constructor_pending_elts; + while (p) + { + if (field == p->purpose) + return p->value; + else if (tree_int_cst_lt (bitpos, bit_position (p->purpose))) + p = p->left; + else + p = p->right; + } + } + else if (TREE_CODE (constructor_type) == UNION_TYPE) + { + if (!vec_safe_is_empty (constructor_elements) + && (constructor_elements->last ().index == field)) + return constructor_elements->last ().value; + } + return NULL_TREE; +} + +/* "Output" the next constructor element. + At top level, really output it to assembler code now. + Otherwise, collect it in a list from which we will make a CONSTRUCTOR. + If ORIGTYPE is not NULL_TREE, it is the original type of VALUE. + TYPE is the data type that the containing data type wants here. + FIELD is the field (a FIELD_DECL) or the index that this element fills. + If VALUE is a string constant, STRICT_STRING is true if it is + unparenthesized or we should not warn here for it being parenthesized. + For other types of VALUE, STRICT_STRING is not used. + + PENDING if true means output pending elements that belong + right after this element. (PENDING is normally true; + it is false while outputting pending elements, to avoid recursion.) + + IMPLICIT is true if value comes from pop_init_level (1), + the new initializer has been merged with the existing one + and thus no warnings should be emitted about overriding an + existing initializer. */ + +static void +output_init_element (location_t loc, tree value, tree origtype, + bool strict_string, tree type, tree field, bool pending, + bool implicit, struct obstack * braced_init_obstack) +{ + tree semantic_type = NULL_TREE; + bool maybe_const = true; + bool npc; + + if (type == error_mark_node || value == error_mark_node) + { + constructor_erroneous = 1; + return; + } + if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE + && (TREE_CODE (value) == STRING_CST + || TREE_CODE (value) == COMPOUND_LITERAL_EXPR) + && !(TREE_CODE (value) == STRING_CST + && TREE_CODE (type) == ARRAY_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (type))) + && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)), + TYPE_MAIN_VARIANT (type))) + value = array_to_pointer_conversion (input_location, value); + + if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR + && require_constant_value && pending) + { + /* As an extension, allow initializing objects with static storage + duration with compound literals (which are then treated just as + the brace enclosed list they contain). */ + if (flag_isoc99) + pedwarn_init (loc, OPT_Wpedantic, "initializer element is not " + "constant"); + tree decl = COMPOUND_LITERAL_EXPR_DECL (value); + value = DECL_INITIAL (decl); + } + + npc = null_pointer_constant_p (value); + if (TREE_CODE (value) == EXCESS_PRECISION_EXPR) + { + semantic_type = TREE_TYPE (value); + value = TREE_OPERAND (value, 0); + } + value = c_fully_fold (value, require_constant_value, &maybe_const); + + if (value == error_mark_node) + constructor_erroneous = 1; + else if (!TREE_CONSTANT (value)) + constructor_constant = 0; + else if (!initializer_constant_valid_p (value, + TREE_TYPE (value), + AGGREGATE_TYPE_P (constructor_type) + && TYPE_REVERSE_STORAGE_ORDER + (constructor_type)) + || (RECORD_OR_UNION_TYPE_P (constructor_type) + && DECL_C_BIT_FIELD (field) + && TREE_CODE (value) != INTEGER_CST)) + constructor_simple = 0; + if (!maybe_const) + constructor_nonconst = 1; + + /* Digest the initializer and issue any errors about incompatible + types before issuing errors about non-constant initializers. */ + tree new_value = value; + if (semantic_type) + new_value = build1 (EXCESS_PRECISION_EXPR, semantic_type, value); + new_value = digest_init (loc, type, new_value, origtype, npc, strict_string, + require_constant_value); + if (new_value == error_mark_node) + { + constructor_erroneous = 1; + return; + } + if (require_constant_value || require_constant_elements) + constant_expression_warning (new_value); + + /* Proceed to check the constness of the original initializer. */ + if (!initializer_constant_valid_p (value, TREE_TYPE (value))) + { + if (require_constant_value) + { + error_init (loc, "initializer element is not constant"); + value = error_mark_node; + } + else if (require_constant_elements) + pedwarn (loc, OPT_Wpedantic, + "initializer element is not computable at load time"); + } + else if (!maybe_const + && (require_constant_value || require_constant_elements)) + pedwarn_init (loc, OPT_Wpedantic, + "initializer element is not a constant expression"); + + /* Issue -Wc++-compat warnings about initializing a bitfield with + enum type. */ + if (warn_cxx_compat + && field != NULL_TREE + && TREE_CODE (field) == FIELD_DECL + && DECL_BIT_FIELD_TYPE (field) != NULL_TREE + && (TYPE_MAIN_VARIANT (DECL_BIT_FIELD_TYPE (field)) + != TYPE_MAIN_VARIANT (type)) + && TREE_CODE (DECL_BIT_FIELD_TYPE (field)) == ENUMERAL_TYPE) + { + tree checktype = origtype != NULL_TREE ? origtype : TREE_TYPE (value); + if (checktype != error_mark_node + && (TYPE_MAIN_VARIANT (checktype) + != TYPE_MAIN_VARIANT (DECL_BIT_FIELD_TYPE (field)))) + warning_init (loc, OPT_Wc___compat, + "enum conversion in initialization is invalid in C++"); + } + + /* If this field is empty and does not have side effects (and is not at + the end of structure), don't do anything other than checking the + initializer. */ + if (field + && (TREE_TYPE (field) == error_mark_node + || (COMPLETE_TYPE_P (TREE_TYPE (field)) + && integer_zerop (TYPE_SIZE (TREE_TYPE (field))) + && !TREE_SIDE_EFFECTS (new_value) + && (TREE_CODE (constructor_type) == ARRAY_TYPE + || DECL_CHAIN (field))))) + return; + + /* Finally, set VALUE to the initializer value digested above. */ + value = new_value; + + /* If this element doesn't come next in sequence, + put it on constructor_pending_elts. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE + && (!constructor_incremental + || !tree_int_cst_equal (field, constructor_unfilled_index))) + { + if (constructor_incremental + && tree_int_cst_lt (field, constructor_unfilled_index)) + set_nonincremental_init (braced_init_obstack); + + add_pending_init (loc, field, value, origtype, implicit, + braced_init_obstack); + return; + } + else if (TREE_CODE (constructor_type) == RECORD_TYPE + && (!constructor_incremental + || field != constructor_unfilled_fields)) + { + /* We do this for records but not for unions. In a union, + no matter which field is specified, it can be initialized + right away since it starts at the beginning of the union. */ + if (constructor_incremental) + { + if (!constructor_unfilled_fields) + set_nonincremental_init (braced_init_obstack); + else + { + tree bitpos, unfillpos; + + bitpos = bit_position (field); + unfillpos = bit_position (constructor_unfilled_fields); + + if (tree_int_cst_lt (bitpos, unfillpos)) + set_nonincremental_init (braced_init_obstack); + } + } + + add_pending_init (loc, field, value, origtype, implicit, + braced_init_obstack); + return; + } + else if (TREE_CODE (constructor_type) == UNION_TYPE + && !vec_safe_is_empty (constructor_elements)) + { + if (!implicit) + { + if (TREE_SIDE_EFFECTS (constructor_elements->last ().value)) + warning_init (loc, OPT_Woverride_init_side_effects, + "initialized field with side-effects overwritten"); + else if (warn_override_init) + warning_init (loc, OPT_Woverride_init, + "initialized field overwritten"); + } + + /* We can have just one union field set. */ + constructor_elements = NULL; + } + + /* Otherwise, output this element either to + constructor_elements or to the assembler file. */ + + constructor_elt celt = {field, value}; + vec_safe_push (constructor_elements, celt); + + /* Advance the variable that indicates sequential elements output. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + constructor_unfilled_index + = size_binop_loc (input_location, PLUS_EXPR, constructor_unfilled_index, + bitsize_one_node); + else if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + constructor_unfilled_fields + = DECL_CHAIN (constructor_unfilled_fields); + + /* Skip any nameless bit fields. */ + while (constructor_unfilled_fields != NULL_TREE + && DECL_UNNAMED_BIT_FIELD (constructor_unfilled_fields)) + constructor_unfilled_fields = + DECL_CHAIN (constructor_unfilled_fields); + } + else if (TREE_CODE (constructor_type) == UNION_TYPE) + constructor_unfilled_fields = NULL_TREE; + + /* Now output any pending elements which have become next. */ + if (pending) + output_pending_init_elements (0, braced_init_obstack); +} + +/* For two FIELD_DECLs in the same chain, return -1 if field1 + comes before field2, 1 if field1 comes after field2 and + 0 if field1 == field2. */ + +static int +init_field_decl_cmp (tree field1, tree field2) +{ + if (field1 == field2) + return 0; + + tree bitpos1 = bit_position (field1); + tree bitpos2 = bit_position (field2); + if (tree_int_cst_equal (bitpos1, bitpos2)) + { + /* If one of the fields has non-zero bitsize, then that + field must be the last one in a sequence of zero + sized fields, fields after it will have bigger + bit_position. */ + if (TREE_TYPE (field1) != error_mark_node + && COMPLETE_TYPE_P (TREE_TYPE (field1)) + && integer_nonzerop (TREE_TYPE (field1))) + return 1; + if (TREE_TYPE (field2) != error_mark_node + && COMPLETE_TYPE_P (TREE_TYPE (field2)) + && integer_nonzerop (TREE_TYPE (field2))) + return -1; + /* Otherwise, fallback to DECL_CHAIN walk to find out + which field comes earlier. Walk chains of both + fields, so that if field1 and field2 are close to each + other in either order, it is found soon even for large + sequences of zero sized fields. */ + tree f1 = field1, f2 = field2; + while (1) + { + f1 = DECL_CHAIN (f1); + f2 = DECL_CHAIN (f2); + if (f1 == NULL_TREE) + { + gcc_assert (f2); + return 1; + } + if (f2 == NULL_TREE) + return -1; + if (f1 == field2) + return -1; + if (f2 == field1) + return 1; + if (!tree_int_cst_equal (bit_position (f1), bitpos1)) + return 1; + if (!tree_int_cst_equal (bit_position (f2), bitpos1)) + return -1; + } + } + else if (tree_int_cst_lt (bitpos1, bitpos2)) + return -1; + else + return 1; +} + +/* Output any pending elements which have become next. + As we output elements, constructor_unfilled_{fields,index} + advances, which may cause other elements to become next; + if so, they too are output. + + If ALL is 0, we return when there are + no more pending elements to output now. + + If ALL is 1, we output space as necessary so that + we can output all the pending elements. */ +static void +output_pending_init_elements (int all, struct obstack * braced_init_obstack) +{ + struct init_node *elt = constructor_pending_elts; + tree next; + + retry: + + /* Look through the whole pending tree. + If we find an element that should be output now, + output it. Otherwise, set NEXT to the element + that comes first among those still pending. */ + + next = NULL_TREE; + while (elt) + { + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (tree_int_cst_equal (elt->purpose, + constructor_unfilled_index)) + output_init_element (input_location, elt->value, elt->origtype, + true, TREE_TYPE (constructor_type), + constructor_unfilled_index, false, false, + braced_init_obstack); + else if (tree_int_cst_lt (constructor_unfilled_index, + elt->purpose)) + { + /* Advance to the next smaller node. */ + if (elt->left) + elt = elt->left; + else + { + /* We have reached the smallest node bigger than the + current unfilled index. Fill the space first. */ + next = elt->purpose; + break; + } + } + else + { + /* Advance to the next bigger node. */ + if (elt->right) + elt = elt->right; + else + { + /* We have reached the biggest node in a subtree. Find + the parent of it, which is the next bigger node. */ + while (elt->parent && elt->parent->right == elt) + elt = elt->parent; + elt = elt->parent; + if (elt && tree_int_cst_lt (constructor_unfilled_index, + elt->purpose)) + { + next = elt->purpose; + break; + } + } + } + } + else if (RECORD_OR_UNION_TYPE_P (constructor_type)) + { + /* If the current record is complete we are done. */ + if (constructor_unfilled_fields == NULL_TREE) + break; + + int cmp = init_field_decl_cmp (constructor_unfilled_fields, + elt->purpose); + if (cmp == 0) + output_init_element (input_location, elt->value, elt->origtype, + true, TREE_TYPE (elt->purpose), + elt->purpose, false, false, + braced_init_obstack); + else if (cmp < 0) + { + /* Advance to the next smaller node. */ + if (elt->left) + elt = elt->left; + else + { + /* We have reached the smallest node bigger than the + current unfilled field. Fill the space first. */ + next = elt->purpose; + break; + } + } + else + { + /* Advance to the next bigger node. */ + if (elt->right) + elt = elt->right; + else + { + /* We have reached the biggest node in a subtree. Find + the parent of it, which is the next bigger node. */ + while (elt->parent && elt->parent->right == elt) + elt = elt->parent; + elt = elt->parent; + if (elt + && init_field_decl_cmp (constructor_unfilled_fields, + elt->purpose) < 0) + { + next = elt->purpose; + break; + } + } + } + } + } + + /* Ordinarily return, but not if we want to output all + and there are elements left. */ + if (!(all && next != NULL_TREE)) + return; + + /* If it's not incremental, just skip over the gap, so that after + jumping to retry we will output the next successive element. */ + if (RECORD_OR_UNION_TYPE_P (constructor_type)) + constructor_unfilled_fields = next; + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + constructor_unfilled_index = next; + + /* ELT now points to the node in the pending tree with the next + initializer to output. */ + goto retry; +} + +/* Expression VALUE coincides with the start of type TYPE in a braced + initializer. Return true if we should treat VALUE as initializing + the first element of TYPE, false if we should treat it as initializing + TYPE as a whole. + + If the initializer is clearly invalid, the question becomes: + which choice gives the best error message? */ + +static bool +initialize_elementwise_p (tree type, tree value) +{ + if (type == error_mark_node || value == error_mark_node) + return false; + + gcc_checking_assert (TYPE_MAIN_VARIANT (type) == type); + + tree value_type = TREE_TYPE (value); + if (value_type == error_mark_node) + return false; + + /* GNU vectors can be initialized elementwise. However, treat any + kind of vector value as initializing the vector type as a whole, + regardless of whether the value is a GNU vector. Such initializers + are valid if and only if they would have been valid in a non-braced + initializer like: + + TYPE foo = VALUE; + + so recursing into the vector type would be at best confusing or at + worst wrong. For example, when -flax-vector-conversions is in effect, + it's possible to initialize a V8HI from a V4SI, even though the vectors + have different element types and different numbers of elements. */ + if (gnu_vector_type_p (type)) + return !VECTOR_TYPE_P (value_type); + + if (AGGREGATE_TYPE_P (type)) + return type != TYPE_MAIN_VARIANT (value_type); + + return false; +} + +/* Add one non-braced element to the current constructor level. + This adjusts the current position within the constructor's type. + This may also start or terminate implicit levels + to handle a partly-braced initializer. + + Once this has found the correct level for the new element, + it calls output_init_element. + + IMPLICIT is true if value comes from pop_init_level (1), + the new initializer has been merged with the existing one + and thus no warnings should be emitted about overriding an + existing initializer. */ + +void +process_init_element (location_t loc, struct c_expr value, bool implicit, + struct obstack * braced_init_obstack) +{ + tree orig_value = value.value; + int string_flag + = (orig_value != NULL_TREE && TREE_CODE (orig_value) == STRING_CST); + bool strict_string = value.original_code == STRING_CST; + bool was_designated = designator_depth != 0; + + designator_depth = 0; + designator_erroneous = 0; + + if (!implicit && value.value && !integer_zerop (value.value)) + constructor_zeroinit = 0; + + /* Handle superfluous braces around string cst as in + char x[] = {"foo"}; */ + if (string_flag + && constructor_type + && !was_designated + && TREE_CODE (constructor_type) == ARRAY_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (constructor_type)) + && integer_zerop (constructor_unfilled_index)) + { + if (constructor_stack->replacement_value.value) + error_init (loc, "excess elements in % array initializer"); + constructor_stack->replacement_value = value; + return; + } + + if (constructor_stack->replacement_value.value != NULL_TREE) + { + error_init (loc, "excess elements in struct initializer"); + return; + } + + /* Ignore elements of a brace group if it is entirely superfluous + and has already been diagnosed, or if the type is erroneous. */ + if (constructor_type == NULL_TREE || constructor_type == error_mark_node) + return; + + /* Ignore elements of an initializer for a variable-size type. + Those are diagnosed in digest_init. */ + if (COMPLETE_TYPE_P (constructor_type) + && !poly_int_tree_p (TYPE_SIZE (constructor_type))) + return; + + if (!implicit && warn_designated_init && !was_designated + && TREE_CODE (constructor_type) == RECORD_TYPE + && lookup_attribute ("designated_init", + TYPE_ATTRIBUTES (constructor_type))) + warning_init (loc, + OPT_Wdesignated_init, + "positional initialization of field " + "in % declared with % attribute"); + + /* If we've exhausted any levels that didn't have braces, + pop them now. */ + while (constructor_stack->implicit) + { + if (RECORD_OR_UNION_TYPE_P (constructor_type) + && constructor_fields == NULL_TREE) + process_init_element (loc, + pop_init_level (loc, 1, braced_init_obstack, + last_init_list_comma), + true, braced_init_obstack); + else if ((TREE_CODE (constructor_type) == ARRAY_TYPE + || gnu_vector_type_p (constructor_type)) + && constructor_max_index + && tree_int_cst_lt (constructor_max_index, + constructor_index)) + process_init_element (loc, + pop_init_level (loc, 1, braced_init_obstack, + last_init_list_comma), + true, braced_init_obstack); + else + break; + } + + /* In the case of [LO ... HI] = VALUE, only evaluate VALUE once. */ + if (constructor_range_stack) + { + /* If value is a compound literal and we'll be just using its + content, don't put it into a SAVE_EXPR. */ + if (TREE_CODE (value.value) != COMPOUND_LITERAL_EXPR + || !require_constant_value) + { + tree semantic_type = NULL_TREE; + if (TREE_CODE (value.value) == EXCESS_PRECISION_EXPR) + { + semantic_type = TREE_TYPE (value.value); + value.value = TREE_OPERAND (value.value, 0); + } + value.value = save_expr (value.value); + if (semantic_type) + value.value = build1 (EXCESS_PRECISION_EXPR, semantic_type, + value.value); + } + } + + while (1) + { + if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + tree fieldtype; + enum tree_code fieldcode; + + if (constructor_fields == NULL_TREE) + { + pedwarn_init (loc, 0, "excess elements in struct initializer"); + break; + } + + fieldtype = TREE_TYPE (constructor_fields); + if (fieldtype != error_mark_node) + fieldtype = TYPE_MAIN_VARIANT (fieldtype); + fieldcode = TREE_CODE (fieldtype); + + /* Error for non-static initialization of a flexible array member. */ + if (fieldcode == ARRAY_TYPE + && !require_constant_value + && TYPE_SIZE (fieldtype) == NULL_TREE + && DECL_CHAIN (constructor_fields) == NULL_TREE) + { + error_init (loc, "non-static initialization of a flexible " + "array member"); + break; + } + + /* Error for initialization of a flexible array member with + a string constant if the structure is in an array. E.g.: + struct S { int x; char y[]; }; + struct S s[] = { { 1, "foo" } }; + is invalid. */ + if (string_flag + && fieldcode == ARRAY_TYPE + && constructor_depth > 1 + && TYPE_SIZE (fieldtype) == NULL_TREE + && DECL_CHAIN (constructor_fields) == NULL_TREE) + { + bool in_array_p = false; + for (struct constructor_stack *p = constructor_stack; + p && p->type; p = p->next) + if (TREE_CODE (p->type) == ARRAY_TYPE) + { + in_array_p = true; + break; + } + if (in_array_p) + { + error_init (loc, "initialization of flexible array " + "member in a nested context"); + break; + } + } + + /* Accept a string constant to initialize a subarray. */ + if (value.value != NULL_TREE + && fieldcode == ARRAY_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype)) + && string_flag) + value.value = orig_value; + /* Otherwise, if we have come to a subaggregate, + and we don't have an element of its type, push into it. */ + else if (value.value != NULL_TREE + && initialize_elementwise_p (fieldtype, value.value)) + { + push_init_level (loc, 1, braced_init_obstack); + continue; + } + + if (value.value) + { + push_member_name (constructor_fields); + output_init_element (loc, value.value, value.original_type, + strict_string, fieldtype, + constructor_fields, true, implicit, + braced_init_obstack); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + else + /* Do the bookkeeping for an element that was + directly output as a constructor. */ + { + /* For a record, keep track of end position of last field. */ + if (DECL_SIZE (constructor_fields)) + constructor_bit_index + = size_binop_loc (input_location, PLUS_EXPR, + bit_position (constructor_fields), + DECL_SIZE (constructor_fields)); + + /* If the current field was the first one not yet written out, + it isn't now, so update. */ + if (constructor_unfilled_fields == constructor_fields) + { + constructor_unfilled_fields = DECL_CHAIN (constructor_fields); + /* Skip any nameless bit fields. */ + while (constructor_unfilled_fields != 0 + && (DECL_UNNAMED_BIT_FIELD + (constructor_unfilled_fields))) + constructor_unfilled_fields = + DECL_CHAIN (constructor_unfilled_fields); + } + } + + constructor_fields = DECL_CHAIN (constructor_fields); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_fields != NULL_TREE + && DECL_UNNAMED_BIT_FIELD (constructor_fields)) + constructor_fields = DECL_CHAIN (constructor_fields); + } + else if (TREE_CODE (constructor_type) == UNION_TYPE) + { + tree fieldtype; + enum tree_code fieldcode; + + if (constructor_fields == NULL_TREE) + { + pedwarn_init (loc, 0, + "excess elements in union initializer"); + break; + } + + fieldtype = TREE_TYPE (constructor_fields); + if (fieldtype != error_mark_node) + fieldtype = TYPE_MAIN_VARIANT (fieldtype); + fieldcode = TREE_CODE (fieldtype); + + /* Warn that traditional C rejects initialization of unions. + We skip the warning if the value is zero. This is done + under the assumption that the zero initializer in user + code appears conditioned on e.g. __STDC__ to avoid + "missing initializer" warnings and relies on default + initialization to zero in the traditional C case. + We also skip the warning if the initializer is designated, + again on the assumption that this must be conditional on + __STDC__ anyway (and we've already complained about the + member-designator already). */ + if (!in_system_header_at (input_location) && !constructor_designated + && !(value.value && (integer_zerop (value.value) + || real_zerop (value.value)))) + warning (OPT_Wtraditional, "traditional C rejects initialization " + "of unions"); + + /* Accept a string constant to initialize a subarray. */ + if (value.value != NULL_TREE + && fieldcode == ARRAY_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype)) + && string_flag) + value.value = orig_value; + /* Otherwise, if we have come to a subaggregate, + and we don't have an element of its type, push into it. */ + else if (value.value != NULL_TREE + && initialize_elementwise_p (fieldtype, value.value)) + { + push_init_level (loc, 1, braced_init_obstack); + continue; + } + + if (value.value) + { + push_member_name (constructor_fields); + output_init_element (loc, value.value, value.original_type, + strict_string, fieldtype, + constructor_fields, true, implicit, + braced_init_obstack); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + else + /* Do the bookkeeping for an element that was + directly output as a constructor. */ + { + constructor_bit_index = DECL_SIZE (constructor_fields); + constructor_unfilled_fields = DECL_CHAIN (constructor_fields); + } + + constructor_fields = NULL_TREE; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type)); + enum tree_code eltcode = TREE_CODE (elttype); + + /* Accept a string constant to initialize a subarray. */ + if (value.value != NULL_TREE + && eltcode == ARRAY_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (elttype)) + && string_flag) + value.value = orig_value; + /* Otherwise, if we have come to a subaggregate, + and we don't have an element of its type, push into it. */ + else if (value.value != NULL_TREE + && initialize_elementwise_p (elttype, value.value)) + { + push_init_level (loc, 1, braced_init_obstack); + continue; + } + + if (constructor_max_index != NULL_TREE + && (tree_int_cst_lt (constructor_max_index, constructor_index) + || integer_all_onesp (constructor_max_index))) + { + pedwarn_init (loc, 0, + "excess elements in array initializer"); + break; + } + + /* Now output the actual element. */ + if (value.value) + { + push_array_bounds (tree_to_uhwi (constructor_index)); + output_init_element (loc, value.value, value.original_type, + strict_string, elttype, + constructor_index, true, implicit, + braced_init_obstack); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + + constructor_index + = size_binop_loc (input_location, PLUS_EXPR, + constructor_index, bitsize_one_node); + + if (!value.value) + /* If we are doing the bookkeeping for an element that was + directly output as a constructor, we must update + constructor_unfilled_index. */ + constructor_unfilled_index = constructor_index; + } + else if (gnu_vector_type_p (constructor_type)) + { + tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type)); + + /* Do a basic check of initializer size. Note that vectors + always have a fixed size derived from their type. */ + if (tree_int_cst_lt (constructor_max_index, constructor_index)) + { + pedwarn_init (loc, 0, + "excess elements in vector initializer"); + break; + } + + /* Now output the actual element. */ + if (value.value) + { + if (TREE_CODE (value.value) == VECTOR_CST) + elttype = TYPE_MAIN_VARIANT (constructor_type); + output_init_element (loc, value.value, value.original_type, + strict_string, elttype, + constructor_index, true, implicit, + braced_init_obstack); + } + + constructor_index + = size_binop_loc (input_location, + PLUS_EXPR, constructor_index, bitsize_one_node); + + if (!value.value) + /* If we are doing the bookkeeping for an element that was + directly output as a constructor, we must update + constructor_unfilled_index. */ + constructor_unfilled_index = constructor_index; + } + + /* Handle the sole element allowed in a braced initializer + for a scalar variable. */ + else if (constructor_type != error_mark_node + && constructor_fields == NULL_TREE) + { + pedwarn_init (loc, 0, + "excess elements in scalar initializer"); + break; + } + else + { + if (value.value) + output_init_element (loc, value.value, value.original_type, + strict_string, constructor_type, + NULL_TREE, true, implicit, + braced_init_obstack); + constructor_fields = NULL_TREE; + } + + /* Handle range initializers either at this level or anywhere higher + in the designator stack. */ + if (constructor_range_stack) + { + struct constructor_range_stack *p, *range_stack; + int finish = 0; + + range_stack = constructor_range_stack; + constructor_range_stack = 0; + while (constructor_stack != range_stack->stack) + { + gcc_assert (constructor_stack->implicit); + process_init_element (loc, + pop_init_level (loc, 1, + braced_init_obstack, + last_init_list_comma), + true, braced_init_obstack); + } + for (p = range_stack; + !p->range_end || tree_int_cst_equal (p->index, p->range_end); + p = p->prev) + { + gcc_assert (constructor_stack->implicit); + process_init_element (loc, + pop_init_level (loc, 1, + braced_init_obstack, + last_init_list_comma), + true, braced_init_obstack); + } + + p->index = size_binop_loc (input_location, + PLUS_EXPR, p->index, bitsize_one_node); + if (tree_int_cst_equal (p->index, p->range_end) && !p->prev) + finish = 1; + + while (1) + { + constructor_index = p->index; + constructor_fields = p->fields; + if (finish && p->range_end && p->index == p->range_start) + { + finish = 0; + p->prev = 0; + } + p = p->next; + if (!p) + break; + finish_implicit_inits (loc, braced_init_obstack); + push_init_level (loc, 2, braced_init_obstack); + p->stack = constructor_stack; + if (p->range_end && tree_int_cst_equal (p->index, p->range_end)) + p->index = p->range_start; + } + + if (!finish) + constructor_range_stack = range_stack; + continue; + } + + break; + } + + constructor_range_stack = 0; +} + +/* Build a complete asm-statement, whose components are a CV_QUALIFIER + (guaranteed to be 'volatile' or null) and ARGS (represented using + an ASM_EXPR node). */ +tree +build_asm_stmt (bool is_volatile, tree args) +{ + if (is_volatile) + ASM_VOLATILE_P (args) = 1; + return add_stmt (args); +} + +/* Build an asm-expr, whose components are a STRING, some OUTPUTS, + some INPUTS, and some CLOBBERS. The latter three may be NULL. + SIMPLE indicates whether there was anything at all after the + string in the asm expression -- asm("blah") and asm("blah" : ) + are subtly different. We use a ASM_EXPR node to represent this. + LOC is the location of the asm, and IS_INLINE says whether this + is asm inline. */ +tree +build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, + tree clobbers, tree labels, bool simple, bool is_inline) +{ + tree tail; + tree args; + int i; + const char *constraint; + const char **oconstraints; + bool allows_mem, allows_reg, is_inout; + int ninputs, noutputs; + + ninputs = list_length (inputs); + noutputs = list_length (outputs); + oconstraints = (const char **) alloca (noutputs * sizeof (const char *)); + + string = resolve_asm_operand_names (string, outputs, inputs, labels); + + /* Remove output conversions that change the type but not the mode. */ + for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail)) + { + tree output = TREE_VALUE (tail); + + output = c_fully_fold (output, false, NULL, true); + + /* ??? Really, this should not be here. Users should be using a + proper lvalue, dammit. But there's a long history of using casts + in the output operands. In cases like longlong.h, this becomes a + primitive form of typechecking -- if the cast can be removed, then + the output operand had a type of the proper width; otherwise we'll + get an error. Gross, but ... */ + STRIP_NOPS (output); + + if (!lvalue_or_else (loc, output, lv_asm)) + output = error_mark_node; + + if (output != error_mark_node + && (TREE_READONLY (output) + || TYPE_READONLY (TREE_TYPE (output)) + || (RECORD_OR_UNION_TYPE_P (TREE_TYPE (output)) + && C_TYPE_FIELDS_READONLY (TREE_TYPE (output))))) + readonly_error (loc, output, lv_asm); + + constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); + oconstraints[i] = constraint; + + if (parse_output_constraint (&constraint, i, ninputs, noutputs, + &allows_mem, &allows_reg, &is_inout)) + { + /* If the operand is going to end up in memory, + mark it addressable. */ + if (!allows_reg && !c_mark_addressable (output)) + output = error_mark_node; + if (!(!allows_reg && allows_mem) + && output != error_mark_node + && VOID_TYPE_P (TREE_TYPE (output))) + { + error_at (loc, "invalid use of void expression"); + output = error_mark_node; + } + } + else + output = error_mark_node; + + TREE_VALUE (tail) = output; + } + + for (i = 0, tail = inputs; tail; ++i, tail = TREE_CHAIN (tail)) + { + tree input; + + constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); + input = TREE_VALUE (tail); + + if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0, + oconstraints, &allows_mem, &allows_reg)) + { + /* If the operand is going to end up in memory, + mark it addressable. */ + if (!allows_reg && allows_mem) + { + input = c_fully_fold (input, false, NULL, true); + + /* Strip the nops as we allow this case. FIXME, this really + should be rejected or made deprecated. */ + STRIP_NOPS (input); + if (!c_mark_addressable (input)) + input = error_mark_node; + } + else + { + struct c_expr expr; + memset (&expr, 0, sizeof (expr)); + expr.value = input; + expr = convert_lvalue_to_rvalue (loc, expr, true, false); + input = c_fully_fold (expr.value, false, NULL); + + if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input))) + { + error_at (loc, "invalid use of void expression"); + input = error_mark_node; + } + } + } + else + input = error_mark_node; + + TREE_VALUE (tail) = input; + } + + args = build_stmt (loc, ASM_EXPR, string, outputs, inputs, clobbers, labels); + + /* asm statements without outputs, including simple ones, are treated + as volatile. */ + ASM_INPUT_P (args) = simple; + ASM_VOLATILE_P (args) = (noutputs == 0); + ASM_INLINE_P (args) = is_inline; + + return args; +} + +/* Generate a goto statement to LABEL. LOC is the location of the + GOTO. */ + +tree +c_finish_goto_label (location_t loc, tree label) +{ + tree decl = lookup_label_for_goto (loc, label); + if (!decl) + return NULL_TREE; + TREE_USED (decl) = 1; + { + add_stmt (build_predict_expr (PRED_GOTO, NOT_TAKEN)); + tree t = build1 (GOTO_EXPR, void_type_node, decl); + SET_EXPR_LOCATION (t, loc); + return add_stmt (t); + } +} + +/* Generate a computed goto statement to EXPR. LOC is the location of + the GOTO. */ + +tree +c_finish_goto_ptr (location_t loc, c_expr val) +{ + tree expr = val.value; + tree t; + pedwarn (loc, OPT_Wpedantic, "ISO C forbids %"); + if (expr != error_mark_node + && !POINTER_TYPE_P (TREE_TYPE (expr)) + && !null_pointer_constant_p (expr)) + { + error_at (val.get_location (), + "computed goto must be pointer type"); + expr = build_zero_cst (ptr_type_node); + } + expr = c_fully_fold (expr, false, NULL); + expr = convert (ptr_type_node, expr); + t = build1 (GOTO_EXPR, void_type_node, expr); + SET_EXPR_LOCATION (t, loc); + return add_stmt (t); +} + +/* Generate a C `return' statement. RETVAL is the expression for what + to return, or a null pointer for `return;' with no value. LOC is + the location of the return statement, or the location of the expression, + if the statement has any. If ORIGTYPE is not NULL_TREE, it + is the original type of RETVAL. */ + +tree +c_finish_return (location_t loc, tree retval, tree origtype) +{ + tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)), ret_stmt; + bool no_warning = false; + bool npc = false; + + /* Use the expansion point to handle cases such as returning NULL + in a function returning void. */ + location_t xloc = expansion_point_location_if_in_system_header (loc); + + if (TREE_THIS_VOLATILE (current_function_decl)) + warning_at (xloc, 0, + "function declared % has a % statement"); + + if (retval) + { + tree semantic_type = NULL_TREE; + npc = null_pointer_constant_p (retval); + if (TREE_CODE (retval) == EXCESS_PRECISION_EXPR) + { + semantic_type = TREE_TYPE (retval); + retval = TREE_OPERAND (retval, 0); + } + retval = c_fully_fold (retval, false, NULL); + if (semantic_type + && valtype != NULL_TREE + && TREE_CODE (valtype) != VOID_TYPE) + retval = build1 (EXCESS_PRECISION_EXPR, semantic_type, retval); + } + + if (!retval) + { + current_function_returns_null = 1; + if ((warn_return_type >= 0 || flag_isoc99) + && valtype != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE) + { + bool warned_here; + if (flag_isoc99) + warned_here = pedwarn + (loc, warn_return_type >= 0 ? OPT_Wreturn_type : 0, + "% with no value, in function returning non-void"); + else + warned_here = warning_at + (loc, OPT_Wreturn_type, + "% with no value, in function returning non-void"); + no_warning = true; + if (warned_here) + inform (DECL_SOURCE_LOCATION (current_function_decl), + "declared here"); + } + } + else if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE) + { + current_function_returns_null = 1; + bool warned_here; + if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) + warned_here = pedwarn + (xloc, warn_return_type >= 0 ? OPT_Wreturn_type : 0, + "% with a value, in function returning void"); + else + warned_here = pedwarn + (xloc, OPT_Wpedantic, "ISO C forbids " + "% with expression, in function returning void"); + if (warned_here) + inform (DECL_SOURCE_LOCATION (current_function_decl), + "declared here"); + } + else + { + tree t = convert_for_assignment (loc, UNKNOWN_LOCATION, valtype, + retval, origtype, ic_return, + npc, NULL_TREE, NULL_TREE, 0); + tree res = DECL_RESULT (current_function_decl); + tree inner; + bool save; + + current_function_returns_value = 1; + if (t == error_mark_node) + return NULL_TREE; + + save = in_late_binary_op; + if (TREE_CODE (TREE_TYPE (res)) == BOOLEAN_TYPE + || TREE_CODE (TREE_TYPE (res)) == COMPLEX_TYPE + || (TREE_CODE (TREE_TYPE (t)) == REAL_TYPE + && (TREE_CODE (TREE_TYPE (res)) == INTEGER_TYPE + || TREE_CODE (TREE_TYPE (res)) == ENUMERAL_TYPE) + && sanitize_flags_p (SANITIZE_FLOAT_CAST))) + in_late_binary_op = true; + inner = t = convert (TREE_TYPE (res), t); + in_late_binary_op = save; + + /* Strip any conversions, additions, and subtractions, and see if + we are returning the address of a local variable. Warn if so. */ + while (1) + { + switch (TREE_CODE (inner)) + { + CASE_CONVERT: + case NON_LVALUE_EXPR: + case PLUS_EXPR: + case POINTER_PLUS_EXPR: + inner = TREE_OPERAND (inner, 0); + continue; + + case MINUS_EXPR: + /* If the second operand of the MINUS_EXPR has a pointer + type (or is converted from it), this may be valid, so + don't give a warning. */ + { + tree op1 = TREE_OPERAND (inner, 1); + + while (!POINTER_TYPE_P (TREE_TYPE (op1)) + && (CONVERT_EXPR_P (op1) + || TREE_CODE (op1) == NON_LVALUE_EXPR)) + op1 = TREE_OPERAND (op1, 0); + + if (POINTER_TYPE_P (TREE_TYPE (op1))) + break; + + inner = TREE_OPERAND (inner, 0); + continue; + } + + case ADDR_EXPR: + inner = TREE_OPERAND (inner, 0); + + while (REFERENCE_CLASS_P (inner) + && !INDIRECT_REF_P (inner)) + inner = TREE_OPERAND (inner, 0); + + if (DECL_P (inner) + && !DECL_EXTERNAL (inner) + && !TREE_STATIC (inner) + && DECL_CONTEXT (inner) == current_function_decl + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))) + { + if (TREE_CODE (inner) == LABEL_DECL) + warning_at (loc, OPT_Wreturn_local_addr, + "function returns address of label"); + else + { + warning_at (loc, OPT_Wreturn_local_addr, + "function returns address of local variable"); + tree zero = build_zero_cst (TREE_TYPE (res)); + t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero); + } + } + break; + + default: + break; + } + + break; + } + + retval = build2 (MODIFY_EXPR, TREE_TYPE (res), res, t); + SET_EXPR_LOCATION (retval, loc); + + if (warn_sequence_point) + verify_sequence_points (retval); + } + + ret_stmt = build_stmt (loc, RETURN_EXPR, retval); + if (no_warning) + suppress_warning (ret_stmt, OPT_Wreturn_type); + return add_stmt (ret_stmt); +} + +struct c_switch { + /* The SWITCH_STMT being built. */ + tree switch_stmt; + + /* The original type of the testing expression, i.e. before the + default conversion is applied. */ + tree orig_type; + + /* A splay-tree mapping the low element of a case range to the high + element, or NULL_TREE if there is no high element. Used to + determine whether or not a new case label duplicates an old case + label. We need a tree, rather than simply a hash table, because + of the GNU case range extension. */ + splay_tree cases; + + /* The bindings at the point of the switch. This is used for + warnings crossing decls when branching to a case label. */ + struct c_spot_bindings *bindings; + + /* Whether the switch includes any break statements. */ + bool break_stmt_seen_p; + + /* The next node on the stack. */ + struct c_switch *next; + + /* Remember whether the controlling expression had boolean type + before integer promotions for the sake of -Wswitch-bool. */ + bool bool_cond_p; +}; + +/* A stack of the currently active switch statements. The innermost + switch statement is on the top of the stack. There is no need to + mark the stack for garbage collection because it is only active + during the processing of the body of a function, and we never + collect at that point. */ + +struct c_switch *c_switch_stack; + +/* Start a C switch statement, testing expression EXP. Return the new + SWITCH_STMT. SWITCH_LOC is the location of the `switch'. + SWITCH_COND_LOC is the location of the switch's condition. + EXPLICIT_CAST_P is true if the expression EXP has an explicit cast. */ + +tree +c_start_switch (location_t switch_loc, + location_t switch_cond_loc, + tree exp, bool explicit_cast_p) +{ + tree orig_type = error_mark_node; + bool bool_cond_p = false; + struct c_switch *cs; + + if (exp != error_mark_node) + { + orig_type = TREE_TYPE (exp); + + if (!INTEGRAL_TYPE_P (orig_type)) + { + if (orig_type != error_mark_node) + { + error_at (switch_cond_loc, "switch quantity not an integer"); + orig_type = error_mark_node; + } + exp = integer_zero_node; + } + else + { + tree type = TYPE_MAIN_VARIANT (orig_type); + tree e = exp; + + /* Warn if the condition has boolean value. */ + while (TREE_CODE (e) == COMPOUND_EXPR) + e = TREE_OPERAND (e, 1); + + if ((TREE_CODE (type) == BOOLEAN_TYPE + || truth_value_p (TREE_CODE (e))) + /* Explicit cast to int suppresses this warning. */ + && !(TREE_CODE (type) == INTEGER_TYPE + && explicit_cast_p)) + bool_cond_p = true; + + if (!in_system_header_at (input_location) + && (type == long_integer_type_node + || type == long_unsigned_type_node)) + warning_at (switch_cond_loc, + OPT_Wtraditional, "% switch expression not " + "converted to % in ISO C"); + + exp = c_fully_fold (exp, false, NULL); + exp = default_conversion (exp); + + if (warn_sequence_point) + verify_sequence_points (exp); + } + } + + /* Add this new SWITCH_STMT to the stack. */ + cs = XNEW (struct c_switch); + cs->switch_stmt = build_stmt (switch_loc, SWITCH_STMT, exp, + NULL_TREE, orig_type, NULL_TREE); + cs->orig_type = orig_type; + cs->cases = splay_tree_new (case_compare, NULL, NULL); + cs->bindings = c_get_switch_bindings (); + cs->break_stmt_seen_p = false; + cs->bool_cond_p = bool_cond_p; + cs->next = c_switch_stack; + c_switch_stack = cs; + + return add_stmt (cs->switch_stmt); +} + +/* Process a case label at location LOC. */ + +tree +do_case (location_t loc, tree low_value, tree high_value) +{ + tree label = NULL_TREE; + + if (low_value && TREE_CODE (low_value) != INTEGER_CST) + { + low_value = c_fully_fold (low_value, false, NULL); + if (TREE_CODE (low_value) == INTEGER_CST) + pedwarn (loc, OPT_Wpedantic, + "case label is not an integer constant expression"); + } + + if (high_value && TREE_CODE (high_value) != INTEGER_CST) + { + high_value = c_fully_fold (high_value, false, NULL); + if (TREE_CODE (high_value) == INTEGER_CST) + pedwarn (input_location, OPT_Wpedantic, + "case label is not an integer constant expression"); + } + + if (c_switch_stack == NULL) + { + if (low_value) + error_at (loc, "case label not within a switch statement"); + else + error_at (loc, "% label not within a switch statement"); + return NULL_TREE; + } + + if (c_check_switch_jump_warnings (c_switch_stack->bindings, + EXPR_LOCATION (c_switch_stack->switch_stmt), + loc)) + return NULL_TREE; + + label = c_add_case_label (loc, c_switch_stack->cases, + SWITCH_STMT_COND (c_switch_stack->switch_stmt), + low_value, high_value); + if (label == error_mark_node) + label = NULL_TREE; + return label; +} + +/* Finish the switch statement. TYPE is the original type of the + controlling expression of the switch, or NULL_TREE. */ + +void +c_finish_switch (tree body, tree type) +{ + struct c_switch *cs = c_switch_stack; + location_t switch_location; + + SWITCH_STMT_BODY (cs->switch_stmt) = body; + + /* Emit warnings as needed. */ + switch_location = EXPR_LOCATION (cs->switch_stmt); + c_do_switch_warnings (cs->cases, switch_location, + type ? type : SWITCH_STMT_TYPE (cs->switch_stmt), + SWITCH_STMT_COND (cs->switch_stmt), cs->bool_cond_p); + if (c_switch_covers_all_cases_p (cs->cases, + SWITCH_STMT_TYPE (cs->switch_stmt))) + SWITCH_STMT_ALL_CASES_P (cs->switch_stmt) = 1; + SWITCH_STMT_NO_BREAK_P (cs->switch_stmt) = !cs->break_stmt_seen_p; + + /* Pop the stack. */ + c_switch_stack = cs->next; + splay_tree_delete (cs->cases); + c_release_switch_bindings (cs->bindings); + XDELETE (cs); +} + +/* Emit an if statement. IF_LOCUS is the location of the 'if'. COND, + THEN_BLOCK and ELSE_BLOCK are expressions to be used; ELSE_BLOCK + may be null. */ + +void +c_finish_if_stmt (location_t if_locus, tree cond, tree then_block, + tree else_block) +{ + tree stmt; + + stmt = build3 (COND_EXPR, void_type_node, cond, then_block, else_block); + SET_EXPR_LOCATION (stmt, if_locus); + add_stmt (stmt); +} + +tree +c_finish_bc_stmt (location_t loc, tree label, bool is_break) +{ + /* In switch statements break is sometimes stylistically used after + a return statement. This can lead to spurious warnings about + control reaching the end of a non-void function when it is + inlined. Note that we are calling block_may_fallthru with + language specific tree nodes; this works because + block_may_fallthru returns true when given something it does not + understand. */ + bool skip = !block_may_fallthru (cur_stmt_list); + + if (is_break) + switch (in_statement) + { + case 0: + error_at (loc, "break statement not within loop or switch"); + return NULL_TREE; + case IN_OMP_BLOCK: + error_at (loc, "invalid exit from OpenMP structured block"); + return NULL_TREE; + case IN_OMP_FOR: + error_at (loc, "break statement used with OpenMP for loop"); + return NULL_TREE; + case IN_ITERATION_STMT: + case IN_OBJC_FOREACH: + break; + default: + gcc_assert (in_statement & IN_SWITCH_STMT); + c_switch_stack->break_stmt_seen_p = true; + break; + } + else + switch (in_statement & ~IN_SWITCH_STMT) + { + case 0: + error_at (loc, "continue statement not within a loop"); + return NULL_TREE; + case IN_OMP_BLOCK: + error_at (loc, "invalid exit from OpenMP structured block"); + return NULL_TREE; + case IN_ITERATION_STMT: + case IN_OMP_FOR: + case IN_OBJC_FOREACH: + break; + default: + gcc_unreachable (); + } + + if (skip) + return NULL_TREE; + else if ((in_statement & IN_OBJC_FOREACH) + && !(is_break && (in_statement & IN_SWITCH_STMT))) + { + /* The foreach expander produces low-level code using gotos instead + of a structured loop construct. */ + gcc_assert (label); + return add_stmt (build_stmt (loc, GOTO_EXPR, label)); + } + return add_stmt (build_stmt (loc, (is_break ? BREAK_STMT : CONTINUE_STMT))); +} + +/* A helper routine for c_process_expr_stmt and c_finish_stmt_expr. */ + +static void +emit_side_effect_warnings (location_t loc, tree expr) +{ + maybe_warn_nodiscard (loc, expr); + if (!warn_unused_value) + return; + if (expr == error_mark_node) + ; + else if (!TREE_SIDE_EFFECTS (expr)) + { + if (!VOID_TYPE_P (TREE_TYPE (expr)) + && !warning_suppressed_p (expr, OPT_Wunused_value)) + warning_at (loc, OPT_Wunused_value, "statement with no effect"); + } + else if (TREE_CODE (expr) == COMPOUND_EXPR) + { + tree r = expr; + location_t cloc = loc; + while (TREE_CODE (r) == COMPOUND_EXPR) + { + if (EXPR_HAS_LOCATION (r)) + cloc = EXPR_LOCATION (r); + r = TREE_OPERAND (r, 1); + } + if (!TREE_SIDE_EFFECTS (r) + && !VOID_TYPE_P (TREE_TYPE (r)) + && !CONVERT_EXPR_P (r) + && !warning_suppressed_p (r, OPT_Wunused_value) + && !warning_suppressed_p (expr, OPT_Wunused_value)) + warning_at (cloc, OPT_Wunused_value, + "right-hand operand of comma expression has no effect"); + } + else + warn_if_unused_value (expr, loc); +} + +/* Process an expression as if it were a complete statement. Emit + diagnostics, but do not call ADD_STMT. LOC is the location of the + statement. */ + +tree +c_process_expr_stmt (location_t loc, tree expr) +{ + tree exprv; + + if (!expr) + return NULL_TREE; + + expr = c_fully_fold (expr, false, NULL); + + if (warn_sequence_point) + verify_sequence_points (expr); + + if (TREE_TYPE (expr) != error_mark_node + && !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr)) + && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE) + error_at (loc, "expression statement has incomplete type"); + + /* If we're not processing a statement expression, warn about unused values. + Warnings for statement expressions will be emitted later, once we figure + out which is the result. */ + if (!STATEMENT_LIST_STMT_EXPR (cur_stmt_list) + && (warn_unused_value || warn_unused_result)) + emit_side_effect_warnings (EXPR_LOC_OR_LOC (expr, loc), expr); + + exprv = expr; + while (TREE_CODE (exprv) == COMPOUND_EXPR) + exprv = TREE_OPERAND (exprv, 1); + while (CONVERT_EXPR_P (exprv)) + exprv = TREE_OPERAND (exprv, 0); + if (DECL_P (exprv) + || handled_component_p (exprv) + || TREE_CODE (exprv) == ADDR_EXPR) + mark_exp_read (exprv); + + /* If the expression is not of a type to which we cannot assign a line + number, wrap the thing in a no-op NOP_EXPR. */ + if (DECL_P (expr) || CONSTANT_CLASS_P (expr)) + { + expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr); + SET_EXPR_LOCATION (expr, loc); + } + + return expr; +} + +/* Emit an expression as a statement. LOC is the location of the + expression. */ + +tree +c_finish_expr_stmt (location_t loc, tree expr) +{ + if (expr) + return add_stmt (c_process_expr_stmt (loc, expr)); + else + return NULL; +} + +/* Do the opposite and emit a statement as an expression. To begin, + create a new binding level and return it. */ + +tree +c_begin_stmt_expr (void) +{ + tree ret; + + /* We must force a BLOCK for this level so that, if it is not expanded + later, there is a way to turn off the entire subtree of blocks that + are contained in it. */ + keep_next_level (); + ret = c_begin_compound_stmt (true); + + c_bindings_start_stmt_expr (c_switch_stack == NULL + ? NULL + : c_switch_stack->bindings); + + /* Mark the current statement list as belonging to a statement list. */ + STATEMENT_LIST_STMT_EXPR (ret) = 1; + + return ret; +} + +/* LOC is the location of the compound statement to which this body + belongs. */ + +tree +c_finish_stmt_expr (location_t loc, tree body) +{ + tree last, type, tmp, val; + tree *last_p; + + body = c_end_compound_stmt (loc, body, true); + + c_bindings_end_stmt_expr (c_switch_stack == NULL + ? NULL + : c_switch_stack->bindings); + + /* Locate the last statement in BODY. See c_end_compound_stmt + about always returning a BIND_EXPR. */ + last_p = &BIND_EXPR_BODY (body); + last = BIND_EXPR_BODY (body); + + continue_searching: + if (TREE_CODE (last) == STATEMENT_LIST) + { + tree_stmt_iterator l = tsi_last (last); + + while (!tsi_end_p (l) && TREE_CODE (tsi_stmt (l)) == DEBUG_BEGIN_STMT) + tsi_prev (&l); + + /* This can happen with degenerate cases like ({ }). No value. */ + if (tsi_end_p (l)) + return body; + + /* If we're supposed to generate side effects warnings, process + all of the statements except the last. */ + if (warn_unused_value || warn_unused_result) + { + for (tree_stmt_iterator i = tsi_start (last); + tsi_stmt (i) != tsi_stmt (l); tsi_next (&i)) + { + location_t tloc; + tree t = tsi_stmt (i); + + tloc = EXPR_HAS_LOCATION (t) ? EXPR_LOCATION (t) : loc; + emit_side_effect_warnings (tloc, t); + } + } + last_p = tsi_stmt_ptr (l); + last = *last_p; + } + + /* If the end of the list is exception related, then the list was split + by a call to push_cleanup. Continue searching. */ + if (TREE_CODE (last) == TRY_FINALLY_EXPR + || TREE_CODE (last) == TRY_CATCH_EXPR) + { + last_p = &TREE_OPERAND (last, 0); + last = *last_p; + goto continue_searching; + } + + if (last == error_mark_node) + return last; + + /* In the case that the BIND_EXPR is not necessary, return the + expression out from inside it. */ + if ((last == BIND_EXPR_BODY (body) + /* Skip nested debug stmts. */ + || last == expr_first (BIND_EXPR_BODY (body))) + && BIND_EXPR_VARS (body) == NULL) + { + /* Even if this looks constant, do not allow it in a constant + expression. */ + last = c_wrap_maybe_const (last, true); + /* Do not warn if the return value of a statement expression is + unused. */ + suppress_warning (last, OPT_Wunused); + return last; + } + + /* Extract the type of said expression. */ + type = TREE_TYPE (last); + + /* If we're not returning a value at all, then the BIND_EXPR that + we already have is a fine expression to return. */ + if (!type || VOID_TYPE_P (type)) + return body; + + /* Now that we've located the expression containing the value, it seems + silly to make voidify_wrapper_expr repeat the process. Create a + temporary of the appropriate type and stick it in a TARGET_EXPR. */ + tmp = create_tmp_var_raw (type); + + /* Unwrap a no-op NOP_EXPR as added by c_finish_expr_stmt. This avoids + tree_expr_nonnegative_p giving up immediately. */ + val = last; + if (TREE_CODE (val) == NOP_EXPR + && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0))) + val = TREE_OPERAND (val, 0); + + *last_p = build2 (MODIFY_EXPR, void_type_node, tmp, val); + SET_EXPR_LOCATION (*last_p, EXPR_LOCATION (last)); + + { + tree t = build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE); + SET_EXPR_LOCATION (t, loc); + return t; + } +} + +/* Begin and end compound statements. This is as simple as pushing + and popping new statement lists from the tree. */ + +tree +c_begin_compound_stmt (bool do_scope) +{ + tree stmt = push_stmt_list (); + if (do_scope) + push_scope (); + return stmt; +} + +/* End a compound statement. STMT is the statement. LOC is the + location of the compound statement-- this is usually the location + of the opening brace. */ + +tree +c_end_compound_stmt (location_t loc, tree stmt, bool do_scope) +{ + tree block = NULL; + + if (do_scope) + { + if (c_dialect_objc ()) + objc_clear_super_receiver (); + block = pop_scope (); + } + + stmt = pop_stmt_list (stmt); + stmt = c_build_bind_expr (loc, block, stmt); + + /* If this compound statement is nested immediately inside a statement + expression, then force a BIND_EXPR to be created. Otherwise we'll + do the wrong thing for ({ { 1; } }) or ({ 1; { } }). In particular, + STATEMENT_LISTs merge, and thus we can lose track of what statement + was really last. */ + if (building_stmt_list_p () + && STATEMENT_LIST_STMT_EXPR (cur_stmt_list) + && TREE_CODE (stmt) != BIND_EXPR) + { + stmt = build3 (BIND_EXPR, void_type_node, NULL, stmt, NULL); + TREE_SIDE_EFFECTS (stmt) = 1; + SET_EXPR_LOCATION (stmt, loc); + } + + return stmt; +} + +/* Queue a cleanup. CLEANUP is an expression/statement to be executed + when the current scope is exited. EH_ONLY is true when this is not + meant to apply to normal control flow transfer. */ + +void +push_cleanup (tree decl, tree cleanup, bool eh_only) +{ + enum tree_code code; + tree stmt, list; + bool stmt_expr; + + code = eh_only ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR; + stmt = build_stmt (DECL_SOURCE_LOCATION (decl), code, NULL, cleanup); + add_stmt (stmt); + stmt_expr = STATEMENT_LIST_STMT_EXPR (cur_stmt_list); + list = push_stmt_list (); + TREE_OPERAND (stmt, 0) = list; + STATEMENT_LIST_STMT_EXPR (list) = stmt_expr; +} + +/* Build a vector comparison of ARG0 and ARG1 using CODE opcode + into a value of TYPE type. Comparison is done via VEC_COND_EXPR. */ + +static tree +build_vec_cmp (tree_code code, tree type, + tree arg0, tree arg1) +{ + tree zero_vec = build_zero_cst (type); + tree minus_one_vec = build_minus_one_cst (type); + tree cmp_type = truth_type_for (type); + tree cmp = build2 (code, cmp_type, arg0, arg1); + return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec); +} + +/* Possibly warn about an address of OP never being NULL in a comparison + operation CODE involving null. */ + +static void +maybe_warn_for_null_address (location_t loc, tree op, tree_code code) +{ + /* Prevent warnings issued for macro expansion. */ + if (!warn_address + || warning_suppressed_p (op, OPT_Waddress) + || from_macro_expansion_at (loc)) + return; + + if (TREE_CODE (op) == NOP_EXPR) + { + /* Allow casts to intptr_t to suppress the warning. */ + tree type = TREE_TYPE (op); + if (TREE_CODE (type) == INTEGER_TYPE) + return; + op = TREE_OPERAND (op, 0); + } + + if (TREE_CODE (op) == POINTER_PLUS_EXPR) + { + /* Allow a cast to void* to suppress the warning. */ + tree type = TREE_TYPE (TREE_TYPE (op)); + if (VOID_TYPE_P (type)) + return; + + /* Adding any value to a null pointer, including zero, is undefined + in C. This includes the expression &p[0] where p is the null + pointer, although &p[0] will have been folded to p by this point + and so not diagnosed. */ + if (code == EQ_EXPR) + warning_at (loc, OPT_Waddress, + "the comparison will always evaluate as % " + "for the pointer operand in %qE must not be NULL", + op); + else + warning_at (loc, OPT_Waddress, + "the comparison will always evaluate as % " + "for the pointer operand in %qE must not be NULL", + op); + + return; + } + + if (TREE_CODE (op) != ADDR_EXPR) + return; + + op = TREE_OPERAND (op, 0); + + if (TREE_CODE (op) == IMAGPART_EXPR + || TREE_CODE (op) == REALPART_EXPR) + { + /* The address of either complex part may not be null. */ + if (code == EQ_EXPR) + warning_at (loc, OPT_Waddress, + "the comparison will always evaluate as % " + "for the address of %qE will never be NULL", + op); + else + warning_at (loc, OPT_Waddress, + "the comparison will always evaluate as % " + "for the address of %qE will never be NULL", + op); + return; + } + + /* Set to true in the loop below if OP dereferences is operand. + In such a case the ultimate target need not be a decl for + the null [in]equality test to be constant. */ + bool deref = false; + + /* Get the outermost array or object, or member. */ + while (handled_component_p (op)) + { + if (TREE_CODE (op) == COMPONENT_REF) + { + /* Get the member (its address is never null). */ + op = TREE_OPERAND (op, 1); + break; + } + + /* Get the outer array/object to refer to in the warning. */ + op = TREE_OPERAND (op, 0); + deref = true; + } + + if ((!deref && !decl_with_nonnull_addr_p (op)) + || from_macro_expansion_at (loc)) + return; + + if (code == EQ_EXPR) + warning_at (loc, OPT_Waddress, + "the comparison will always evaluate as % " + "for the address of %qE will never be NULL", + op); + else + warning_at (loc, OPT_Waddress, + "the comparison will always evaluate as % " + "for the address of %qE will never be NULL", + op); + + if (DECL_P (op)) + inform (DECL_SOURCE_LOCATION (op), "%qD declared here", op); +} + +/* Build a binary-operation expression without default conversions. + CODE is the kind of expression to build. + LOCATION is the operator's location. + This function differs from `build' in several ways: + the data type of the result is computed and recorded in it, + warnings are generated if arg data types are invalid, + special handling for addition and subtraction of pointers is known, + and some optimization is done (operations on narrow ints + are done in the narrower type when that gives the same result). + Constant folding is also done before the result is returned. + + Note that the operands will never have enumeral types, or function + or array types, because either they will have the default conversions + performed or they have both just been converted to some other type in which + the arithmetic is to be done. */ + +tree +build_binary_op (location_t location, enum tree_code code, + tree orig_op0, tree orig_op1, bool convert_p) +{ + tree type0, type1, orig_type0, orig_type1; + tree eptype; + enum tree_code code0, code1; + tree op0, op1; + tree ret = error_mark_node; + const char *invalid_op_diag; + bool op0_int_operands, op1_int_operands; + bool int_const, int_const_or_overflow, int_operands; + + /* Expression code to give to the expression when it is built. + Normally this is CODE, which is what the caller asked for, + but in some special cases we change it. */ + enum tree_code resultcode = code; + + /* Data type in which the computation is to be performed. + In the simplest cases this is the common type of the arguments. */ + tree result_type = NULL; + + /* When the computation is in excess precision, the type of the + final EXCESS_PRECISION_EXPR. */ + tree semantic_result_type = NULL; + + /* Nonzero means operands have already been type-converted + in whatever way is necessary. + Zero means they need to be converted to RESULT_TYPE. */ + int converted = 0; + + /* Nonzero means create the expression with this type, rather than + RESULT_TYPE. */ + tree build_type = NULL_TREE; + + /* Nonzero means after finally constructing the expression + convert it to this type. */ + tree final_type = NULL_TREE; + + /* Nonzero if this is an operation like MIN or MAX which can + safely be computed in short if both args are promoted shorts. + Also implies COMMON. + -1 indicates a bitwise operation; this makes a difference + in the exact conditions for when it is safe to do the operation + in a narrower mode. */ + int shorten = 0; + + /* Nonzero if this is a comparison operation; + if both args are promoted shorts, compare the original shorts. + Also implies COMMON. */ + int short_compare = 0; + + /* Nonzero if this is a right-shift operation, which can be computed on the + original short and then promoted if the operand is a promoted short. */ + int short_shift = 0; + + /* Nonzero means set RESULT_TYPE to the common type of the args. */ + int common = 0; + + /* True means types are compatible as far as ObjC is concerned. */ + bool objc_ok; + + /* True means this is an arithmetic operation that may need excess + precision. */ + bool may_need_excess_precision; + + /* True means this is a boolean operation that converts both its + operands to truth-values. */ + bool boolean_op = false; + + /* Remember whether we're doing / or %. */ + bool doing_div_or_mod = false; + + /* Remember whether we're doing << or >>. */ + bool doing_shift = false; + + /* Tree holding instrumentation expression. */ + tree instrument_expr = NULL; + + if (location == UNKNOWN_LOCATION) + location = input_location; + + op0 = orig_op0; + op1 = orig_op1; + + op0_int_operands = EXPR_INT_CONST_OPERANDS (orig_op0); + if (op0_int_operands) + op0 = remove_c_maybe_const_expr (op0); + op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1); + if (op1_int_operands) + op1 = remove_c_maybe_const_expr (op1); + int_operands = (op0_int_operands && op1_int_operands); + if (int_operands) + { + int_const_or_overflow = (TREE_CODE (orig_op0) == INTEGER_CST + && TREE_CODE (orig_op1) == INTEGER_CST); + int_const = (int_const_or_overflow + && !TREE_OVERFLOW (orig_op0) + && !TREE_OVERFLOW (orig_op1)); + } + else + int_const = int_const_or_overflow = false; + + /* Do not apply default conversion in mixed vector/scalar expression. */ + if (convert_p + && VECTOR_TYPE_P (TREE_TYPE (op0)) == VECTOR_TYPE_P (TREE_TYPE (op1))) + { + op0 = default_conversion (op0); + op1 = default_conversion (op1); + } + + orig_type0 = type0 = TREE_TYPE (op0); + + orig_type1 = type1 = TREE_TYPE (op1); + + /* The expression codes of the data types of the arguments tell us + whether the arguments are integers, floating, pointers, etc. */ + code0 = TREE_CODE (type0); + code1 = TREE_CODE (type1); + + /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (op0); + STRIP_TYPE_NOPS (op1); + + /* If an error was already reported for one of the arguments, + avoid reporting another error. */ + + if (code0 == ERROR_MARK || code1 == ERROR_MARK) + return error_mark_node; + + if (code0 == POINTER_TYPE + && reject_gcc_builtin (op0, EXPR_LOCATION (orig_op0))) + return error_mark_node; + + if (code1 == POINTER_TYPE + && reject_gcc_builtin (op1, EXPR_LOCATION (orig_op1))) + return error_mark_node; + + if ((invalid_op_diag + = targetm.invalid_binary_op (code, type0, type1))) + { + error_at (location, invalid_op_diag); + return error_mark_node; + } + + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + may_need_excess_precision = true; + break; + + case EQ_EXPR: + case NE_EXPR: + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + /* Excess precision for implicit conversions of integers to + floating point in C11 and later. */ + may_need_excess_precision = (flag_isoc11 + && (ANY_INTEGRAL_TYPE_P (type0) + || ANY_INTEGRAL_TYPE_P (type1))); + break; + + default: + may_need_excess_precision = false; + break; + } + if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR) + { + op0 = TREE_OPERAND (op0, 0); + type0 = TREE_TYPE (op0); + } + else if (may_need_excess_precision + && (eptype = excess_precision_type (type0)) != NULL_TREE) + { + type0 = eptype; + op0 = convert (eptype, op0); + } + if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR) + { + op1 = TREE_OPERAND (op1, 0); + type1 = TREE_TYPE (op1); + } + else if (may_need_excess_precision + && (eptype = excess_precision_type (type1)) != NULL_TREE) + { + type1 = eptype; + op1 = convert (eptype, op1); + } + + objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE); + + /* In case when one of the operands of the binary operation is + a vector and another is a scalar -- convert scalar to vector. */ + if ((gnu_vector_type_p (type0) && code1 != VECTOR_TYPE) + || (gnu_vector_type_p (type1) && code0 != VECTOR_TYPE)) + { + enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1, + true); + + switch (convert_flag) + { + case stv_error: + return error_mark_node; + case stv_firstarg: + { + bool maybe_const = true; + tree sc; + sc = c_fully_fold (op0, false, &maybe_const); + sc = save_expr (sc); + sc = convert (TREE_TYPE (type1), sc); + op0 = build_vector_from_val (type1, sc); + if (!maybe_const) + op0 = c_wrap_maybe_const (op0, true); + orig_type0 = type0 = TREE_TYPE (op0); + code0 = TREE_CODE (type0); + converted = 1; + break; + } + case stv_secondarg: + { + bool maybe_const = true; + tree sc; + sc = c_fully_fold (op1, false, &maybe_const); + sc = save_expr (sc); + sc = convert (TREE_TYPE (type0), sc); + op1 = build_vector_from_val (type0, sc); + if (!maybe_const) + op1 = c_wrap_maybe_const (op1, true); + orig_type1 = type1 = TREE_TYPE (op1); + code1 = TREE_CODE (type1); + converted = 1; + break; + } + default: + break; + } + } + + switch (code) + { + case PLUS_EXPR: + /* Handle the pointer + int case. */ + if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + ret = pointer_int_sum (location, PLUS_EXPR, op0, op1); + goto return_build_binary_op; + } + else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE) + { + ret = pointer_int_sum (location, PLUS_EXPR, op1, op0); + goto return_build_binary_op; + } + else + common = 1; + break; + + case MINUS_EXPR: + /* Subtraction of two similar pointers. + We must subtract them as integers, then divide by object size. */ + if (code0 == POINTER_TYPE && code1 == POINTER_TYPE + && comp_target_types (location, type0, type1)) + { + ret = pointer_diff (location, op0, op1, &instrument_expr); + goto return_build_binary_op; + } + /* Handle pointer minus int. Just like pointer plus int. */ + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + ret = pointer_int_sum (location, MINUS_EXPR, op0, op1); + goto return_build_binary_op; + } + else + common = 1; + break; + + case MULT_EXPR: + common = 1; + break; + + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + doing_div_or_mod = true; + warn_for_div_by_zero (location, op1); + + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + || code0 == FIXED_POINT_TYPE + || code0 == COMPLEX_TYPE + || gnu_vector_type_p (type0)) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == FIXED_POINT_TYPE + || code1 == COMPLEX_TYPE + || gnu_vector_type_p (type1))) + { + enum tree_code tcode0 = code0, tcode1 = code1; + + if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE) + tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0))); + if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE) + tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1))); + + if (!((tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE) + || (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE))) + resultcode = RDIV_EXPR; + else + /* Although it would be tempting to shorten always here, that + loses on some targets, since the modulo instruction is + undefined if the quotient can't be represented in the + computation mode. We shorten only if unsigned or if + dividing by something we know != -1. */ + shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0)) + || (TREE_CODE (op1) == INTEGER_CST + && !integer_all_onesp (op1))); + common = 1; + } + break; + + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + shorten = -1; + /* Allow vector types which are not floating point types. */ + else if (gnu_vector_type_p (type0) + && gnu_vector_type_p (type1) + && !VECTOR_FLOAT_TYPE_P (type0) + && !VECTOR_FLOAT_TYPE_P (type1)) + common = 1; + break; + + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: + doing_div_or_mod = true; + warn_for_div_by_zero (location, op1); + + if (gnu_vector_type_p (type0) + && gnu_vector_type_p (type1) + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) + common = 1; + else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + /* Although it would be tempting to shorten always here, that loses + on some targets, since the modulo instruction is undefined if the + quotient can't be represented in the computation mode. We shorten + only if unsigned or if dividing by something we know != -1. */ + shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0)) + || (TREE_CODE (op1) == INTEGER_CST + && !integer_all_onesp (op1))); + common = 1; + } + break; + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE + || code0 == REAL_TYPE || code0 == COMPLEX_TYPE + || code0 == FIXED_POINT_TYPE) + && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE + || code1 == REAL_TYPE || code1 == COMPLEX_TYPE + || code1 == FIXED_POINT_TYPE)) + { + /* Result of these operations is always an int, + but that does not mean the operands should be + converted to ints! */ + result_type = integer_type_node; + if (op0_int_operands) + { + op0 = c_objc_common_truthvalue_conversion (location, orig_op0); + op0 = remove_c_maybe_const_expr (op0); + } + else + op0 = c_objc_common_truthvalue_conversion (location, op0); + if (op1_int_operands) + { + op1 = c_objc_common_truthvalue_conversion (location, orig_op1); + op1 = remove_c_maybe_const_expr (op1); + } + else + op1 = c_objc_common_truthvalue_conversion (location, op1); + converted = 1; + boolean_op = true; + } + if (code == TRUTH_ANDIF_EXPR) + { + int_const_or_overflow = (int_operands + && TREE_CODE (orig_op0) == INTEGER_CST + && (op0 == truthvalue_false_node + || TREE_CODE (orig_op1) == INTEGER_CST)); + int_const = (int_const_or_overflow + && !TREE_OVERFLOW (orig_op0) + && (op0 == truthvalue_false_node + || !TREE_OVERFLOW (orig_op1))); + } + else if (code == TRUTH_ORIF_EXPR) + { + int_const_or_overflow = (int_operands + && TREE_CODE (orig_op0) == INTEGER_CST + && (op0 == truthvalue_true_node + || TREE_CODE (orig_op1) == INTEGER_CST)); + int_const = (int_const_or_overflow + && !TREE_OVERFLOW (orig_op0) + && (op0 == truthvalue_true_node + || !TREE_OVERFLOW (orig_op1))); + } + break; + + /* Shift operations: result has same type as first operand; + always convert second operand to int. + Also set SHORT_SHIFT if shifting rightward. */ + + case RSHIFT_EXPR: + if (gnu_vector_type_p (type0) + && gnu_vector_type_p (type1) + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE + && known_eq (TYPE_VECTOR_SUBPARTS (type0), + TYPE_VECTOR_SUBPARTS (type1))) + { + result_type = type0; + converted = 1; + } + else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE + || (gnu_vector_type_p (type0) + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)) + && code1 == INTEGER_TYPE) + { + doing_shift = true; + if (TREE_CODE (op1) == INTEGER_CST) + { + if (tree_int_cst_sgn (op1) < 0) + { + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning_at (location, OPT_Wshift_count_negative, + "right shift count is negative"); + } + else if (code0 == VECTOR_TYPE) + { + if (compare_tree_int (op1, + TYPE_PRECISION (TREE_TYPE (type0))) + >= 0) + { + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning_at (location, OPT_Wshift_count_overflow, + "right shift count >= width of vector element"); + } + } + else + { + if (!integer_zerop (op1)) + short_shift = 1; + + if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0) + { + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning_at (location, OPT_Wshift_count_overflow, + "right shift count >= width of type"); + } + } + } + + /* Use the type of the value to be shifted. */ + result_type = type0; + /* Avoid converting op1 to result_type later. */ + converted = 1; + } + break; + + case LSHIFT_EXPR: + if (gnu_vector_type_p (type0) + && gnu_vector_type_p (type1) + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE + && known_eq (TYPE_VECTOR_SUBPARTS (type0), + TYPE_VECTOR_SUBPARTS (type1))) + { + result_type = type0; + converted = 1; + } + else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE + || (gnu_vector_type_p (type0) + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)) + && code1 == INTEGER_TYPE) + { + doing_shift = true; + if (TREE_CODE (op0) == INTEGER_CST + && tree_int_cst_sgn (op0) < 0) + { + /* Don't reject a left shift of a negative value in a context + where a constant expression is needed in C90. */ + if (flag_isoc99) + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning_at (location, OPT_Wshift_negative_value, + "left shift of negative value"); + } + if (TREE_CODE (op1) == INTEGER_CST) + { + if (tree_int_cst_sgn (op1) < 0) + { + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning_at (location, OPT_Wshift_count_negative, + "left shift count is negative"); + } + else if (code0 == VECTOR_TYPE) + { + if (compare_tree_int (op1, + TYPE_PRECISION (TREE_TYPE (type0))) + >= 0) + { + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning_at (location, OPT_Wshift_count_overflow, + "left shift count >= width of vector element"); + } + } + else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0) + { + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning_at (location, OPT_Wshift_count_overflow, + "left shift count >= width of type"); + } + else if (TREE_CODE (op0) == INTEGER_CST + && maybe_warn_shift_overflow (location, op0, op1) + && flag_isoc99) + int_const = false; + } + + /* Use the type of the value to be shifted. */ + result_type = type0; + /* Avoid converting op1 to result_type later. */ + converted = 1; + } + break; + + case EQ_EXPR: + case NE_EXPR: + if (gnu_vector_type_p (type0) && gnu_vector_type_p (type1)) + { + tree intt; + if (!vector_types_compatible_elements_p (type0, type1)) + { + error_at (location, "comparing vectors with different " + "element types"); + return error_mark_node; + } + + if (maybe_ne (TYPE_VECTOR_SUBPARTS (type0), + TYPE_VECTOR_SUBPARTS (type1))) + { + error_at (location, "comparing vectors with different " + "number of elements"); + return error_mark_node; + } + + /* It's not precisely specified how the usual arithmetic + conversions apply to the vector types. Here, we use + the unsigned type if one of the operands is signed and + the other one is unsigned. */ + if (TYPE_UNSIGNED (type0) != TYPE_UNSIGNED (type1)) + { + if (!TYPE_UNSIGNED (type0)) + op0 = build1 (VIEW_CONVERT_EXPR, type1, op0); + else + op1 = build1 (VIEW_CONVERT_EXPR, type0, op1); + warning_at (location, OPT_Wsign_compare, "comparison between " + "types %qT and %qT", type0, type1); + } + + /* Always construct signed integer vector type. */ + intt = c_common_type_for_size (GET_MODE_BITSIZE + (SCALAR_TYPE_MODE + (TREE_TYPE (type0))), 0); + if (!intt) + { + error_at (location, "could not find an integer type " + "of the same size as %qT", + TREE_TYPE (type0)); + return error_mark_node; + } + result_type = build_opaque_vector_type (intt, + TYPE_VECTOR_SUBPARTS (type0)); + converted = 1; + ret = build_vec_cmp (resultcode, result_type, op0, op1); + goto return_build_binary_op; + } + if (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1)) + warning_at (location, + OPT_Wfloat_equal, + "comparing floating-point with %<==%> or % is unsafe"); + /* Result of comparison is always int, + but don't convert the args to int! */ + build_type = integer_type_node; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) + { + maybe_warn_for_null_address (location, op0, code); + result_type = type0; + } + else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0)) + { + maybe_warn_for_null_address (location, op1, code); + result_type = type1; + } + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + tree tt0 = TREE_TYPE (type0); + tree tt1 = TREE_TYPE (type1); + addr_space_t as0 = TYPE_ADDR_SPACE (tt0); + addr_space_t as1 = TYPE_ADDR_SPACE (tt1); + addr_space_t as_common = ADDR_SPACE_GENERIC; + + /* Anything compares with void *. void * compares with anything. + Otherwise, the targets must be compatible + and both must be object or both incomplete. */ + if (comp_target_types (location, type0, type1)) + result_type = common_pointer_type (type0, type1); + else if (!addr_space_superset (as0, as1, &as_common)) + { + error_at (location, "comparison of pointers to " + "disjoint address spaces"); + return error_mark_node; + } + else if (VOID_TYPE_P (tt0) && !TYPE_ATOMIC (tt0)) + { + if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE) + pedwarn (location, OPT_Wpedantic, "ISO C forbids " + "comparison of % with function pointer"); + } + else if (VOID_TYPE_P (tt1) && !TYPE_ATOMIC (tt1)) + { + if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE) + pedwarn (location, OPT_Wpedantic, "ISO C forbids " + "comparison of % with function pointer"); + } + else + /* Avoid warning about the volatile ObjC EH puts on decls. */ + if (!objc_ok) + pedwarn (location, 0, + "comparison of distinct pointer types lacks a cast"); + + if (result_type == NULL_TREE) + { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); + } + } + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + pedwarn (location, 0, "comparison between pointer and integer"); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = type1; + pedwarn (location, 0, "comparison between pointer and integer"); + } + if ((TREE_CODE (TREE_TYPE (orig_op0)) == BOOLEAN_TYPE + || truth_value_p (TREE_CODE (orig_op0))) + ^ (TREE_CODE (TREE_TYPE (orig_op1)) == BOOLEAN_TYPE + || truth_value_p (TREE_CODE (orig_op1)))) + maybe_warn_bool_compare (location, code, orig_op0, orig_op1); + break; + + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + if (gnu_vector_type_p (type0) && gnu_vector_type_p (type1)) + { + tree intt; + if (!vector_types_compatible_elements_p (type0, type1)) + { + error_at (location, "comparing vectors with different " + "element types"); + return error_mark_node; + } + + if (maybe_ne (TYPE_VECTOR_SUBPARTS (type0), + TYPE_VECTOR_SUBPARTS (type1))) + { + error_at (location, "comparing vectors with different " + "number of elements"); + return error_mark_node; + } + + /* It's not precisely specified how the usual arithmetic + conversions apply to the vector types. Here, we use + the unsigned type if one of the operands is signed and + the other one is unsigned. */ + if (TYPE_UNSIGNED (type0) != TYPE_UNSIGNED (type1)) + { + if (!TYPE_UNSIGNED (type0)) + op0 = build1 (VIEW_CONVERT_EXPR, type1, op0); + else + op1 = build1 (VIEW_CONVERT_EXPR, type0, op1); + warning_at (location, OPT_Wsign_compare, "comparison between " + "types %qT and %qT", type0, type1); + } + + /* Always construct signed integer vector type. */ + intt = c_common_type_for_size (GET_MODE_BITSIZE + (SCALAR_TYPE_MODE + (TREE_TYPE (type0))), 0); + if (!intt) + { + error_at (location, "could not find an integer type " + "of the same size as %qT", + TREE_TYPE (type0)); + return error_mark_node; + } + result_type = build_opaque_vector_type (intt, + TYPE_VECTOR_SUBPARTS (type0)); + converted = 1; + ret = build_vec_cmp (resultcode, result_type, op0, op1); + goto return_build_binary_op; + } + build_type = integer_type_node; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + || code0 == FIXED_POINT_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == FIXED_POINT_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0)); + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); + addr_space_t as_common; + + if (comp_target_types (location, type0, type1)) + { + result_type = common_pointer_type (type0, type1); + if (!COMPLETE_TYPE_P (TREE_TYPE (type0)) + != !COMPLETE_TYPE_P (TREE_TYPE (type1))) + pedwarn_c99 (location, OPT_Wpedantic, + "comparison of complete and incomplete pointers"); + else if (TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE) + pedwarn (location, OPT_Wpedantic, "ISO C forbids " + "ordered comparisons of pointers to functions"); + else if (null_pointer_constant_p (orig_op0) + || null_pointer_constant_p (orig_op1)) + warning_at (location, OPT_Wextra, + "ordered comparison of pointer with null pointer"); + + } + else if (!addr_space_superset (as0, as1, &as_common)) + { + error_at (location, "comparison of pointers to " + "disjoint address spaces"); + return error_mark_node; + } + else + { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); + pedwarn (location, 0, + "comparison of distinct pointer types lacks a cast"); + } + } + else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) + { + result_type = type0; + if (pedantic) + pedwarn (location, OPT_Wpedantic, + "ordered comparison of pointer with integer zero"); + else if (extra_warnings) + warning_at (location, OPT_Wextra, + "ordered comparison of pointer with integer zero"); + } + else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0)) + { + result_type = type1; + if (pedantic) + pedwarn (location, OPT_Wpedantic, + "ordered comparison of pointer with integer zero"); + else if (extra_warnings) + warning_at (location, OPT_Wextra, + "ordered comparison of pointer with integer zero"); + } + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + pedwarn (location, 0, "comparison between pointer and integer"); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = type1; + pedwarn (location, 0, "comparison between pointer and integer"); + } + + if ((code0 == POINTER_TYPE || code1 == POINTER_TYPE) + && current_function_decl != NULL_TREE + && sanitize_flags_p (SANITIZE_POINTER_COMPARE)) + { + op0 = save_expr (op0); + op1 = save_expr (op1); + + tree tt = builtin_decl_explicit (BUILT_IN_ASAN_POINTER_COMPARE); + instrument_expr = build_call_expr_loc (location, tt, 2, op0, op1); + } + + if ((TREE_CODE (TREE_TYPE (orig_op0)) == BOOLEAN_TYPE + || truth_value_p (TREE_CODE (orig_op0))) + ^ (TREE_CODE (TREE_TYPE (orig_op1)) == BOOLEAN_TYPE + || truth_value_p (TREE_CODE (orig_op1)))) + maybe_warn_bool_compare (location, code, orig_op0, orig_op1); + break; + + case MIN_EXPR: + case MAX_EXPR: + /* Used for OpenMP atomics. */ + gcc_assert (flag_openmp); + common = 1; + break; + + default: + gcc_unreachable (); + } + + if (code0 == ERROR_MARK || code1 == ERROR_MARK) + return error_mark_node; + + if (gnu_vector_type_p (type0) + && gnu_vector_type_p (type1) + && (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1)) + || !vector_types_compatible_elements_p (type0, type1))) + { + gcc_rich_location richloc (location); + maybe_range_label_for_tree_type_mismatch + label_for_op0 (orig_op0, orig_op1), + label_for_op1 (orig_op1, orig_op0); + richloc.maybe_add_expr (orig_op0, &label_for_op0); + richloc.maybe_add_expr (orig_op1, &label_for_op1); + binary_op_error (&richloc, code, type0, type1); + return error_mark_node; + } + + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE + || code0 == FIXED_POINT_TYPE + || gnu_vector_type_p (type0)) + && + (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE + || code1 == FIXED_POINT_TYPE + || gnu_vector_type_p (type1))) + { + bool first_complex = (code0 == COMPLEX_TYPE); + bool second_complex = (code1 == COMPLEX_TYPE); + int none_complex = (!first_complex && !second_complex); + + if (shorten || common || short_compare) + { + result_type = c_common_type (type0, type1); + do_warn_double_promotion (result_type, type0, type1, + "implicit conversion from %qT to %qT " + "to match other operand of binary " + "expression", + location); + if (result_type == error_mark_node) + return error_mark_node; + } + + if (first_complex != second_complex + && (code == PLUS_EXPR + || code == MINUS_EXPR + || code == MULT_EXPR + || (code == TRUNC_DIV_EXPR && first_complex)) + && TREE_CODE (TREE_TYPE (result_type)) == REAL_TYPE + && flag_signed_zeros) + { + /* An operation on mixed real/complex operands must be + handled specially, but the language-independent code can + more easily optimize the plain complex arithmetic if + -fno-signed-zeros. */ + tree real_type = TREE_TYPE (result_type); + tree real, imag; + if (type0 != orig_type0 || type1 != orig_type1) + { + gcc_assert (may_need_excess_precision && common); + semantic_result_type = c_common_type (orig_type0, orig_type1); + } + if (first_complex) + { + if (TREE_TYPE (op0) != result_type) + op0 = convert_and_check (location, result_type, op0); + if (TREE_TYPE (op1) != real_type) + op1 = convert_and_check (location, real_type, op1); + } + else + { + if (TREE_TYPE (op0) != real_type) + op0 = convert_and_check (location, real_type, op0); + if (TREE_TYPE (op1) != result_type) + op1 = convert_and_check (location, result_type, op1); + } + if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK) + return error_mark_node; + if (first_complex) + { + op0 = save_expr (op0); + real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR, + op0, true); + imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR, + op0, true); + switch (code) + { + case MULT_EXPR: + case TRUNC_DIV_EXPR: + op1 = save_expr (op1); + imag = build2 (resultcode, real_type, imag, op1); + /* Fall through. */ + case PLUS_EXPR: + case MINUS_EXPR: + real = build2 (resultcode, real_type, real, op1); + break; + default: + gcc_unreachable(); + } + } + else + { + op1 = save_expr (op1); + real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR, + op1, true); + imag = build_unary_op (EXPR_LOCATION (orig_op1), IMAGPART_EXPR, + op1, true); + switch (code) + { + case MULT_EXPR: + op0 = save_expr (op0); + imag = build2 (resultcode, real_type, op0, imag); + /* Fall through. */ + case PLUS_EXPR: + real = build2 (resultcode, real_type, op0, real); + break; + case MINUS_EXPR: + real = build2 (resultcode, real_type, op0, real); + imag = build1 (NEGATE_EXPR, real_type, imag); + break; + default: + gcc_unreachable(); + } + } + ret = build2 (COMPLEX_EXPR, result_type, real, imag); + goto return_build_binary_op; + } + + /* For certain operations (which identify themselves by shorten != 0) + if both args were extended from the same smaller type, + do the arithmetic in that type and then extend. + + shorten !=0 and !=1 indicates a bitwise operation. + For them, this optimization is safe only if + both args are zero-extended or both are sign-extended. + Otherwise, we might change the result. + Eg, (short)-1 | (unsigned short)-1 is (int)-1 + but calculated in (unsigned short) it would be (unsigned short)-1. */ + + if (shorten && none_complex) + { + final_type = result_type; + result_type = shorten_binary_op (result_type, op0, op1, + shorten == -1); + } + + /* Shifts can be shortened if shifting right. */ + + if (short_shift) + { + int unsigned_arg; + tree arg0 = get_narrower (op0, &unsigned_arg); + + final_type = result_type; + + if (arg0 == op0 && final_type == TREE_TYPE (op0)) + unsigned_arg = TYPE_UNSIGNED (TREE_TYPE (op0)); + + if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type) + && tree_int_cst_sgn (op1) > 0 + /* We can shorten only if the shift count is less than the + number of bits in the smaller type size. */ + && compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0 + /* We cannot drop an unsigned shift after sign-extension. */ + && (!TYPE_UNSIGNED (final_type) || unsigned_arg)) + { + /* Do an unsigned shift if the operand was zero-extended. */ + result_type + = c_common_signed_or_unsigned_type (unsigned_arg, + TREE_TYPE (arg0)); + /* Convert value-to-be-shifted to that type. */ + if (TREE_TYPE (op0) != result_type) + op0 = convert (result_type, op0); + converted = 1; + } + } + + /* Comparison operations are shortened too but differently. + They identify themselves by setting short_compare = 1. */ + + if (short_compare) + { + /* Don't write &op0, etc., because that would prevent op0 + from being kept in a register. + Instead, make copies of the our local variables and + pass the copies by reference, then copy them back afterward. */ + tree xop0 = op0, xop1 = op1, xresult_type = result_type; + enum tree_code xresultcode = resultcode; + tree val + = shorten_compare (location, &xop0, &xop1, &xresult_type, + &xresultcode); + + if (val != NULL_TREE) + { + ret = val; + goto return_build_binary_op; + } + + op0 = xop0, op1 = xop1; + converted = 1; + resultcode = xresultcode; + + if (c_inhibit_evaluation_warnings == 0 && !c_in_omp_for) + { + bool op0_maybe_const = true; + bool op1_maybe_const = true; + tree orig_op0_folded, orig_op1_folded; + + if (in_late_binary_op) + { + orig_op0_folded = orig_op0; + orig_op1_folded = orig_op1; + } + else + { + /* Fold for the sake of possible warnings, as in + build_conditional_expr. This requires the + "original" values to be folded, not just op0 and + op1. */ + c_inhibit_evaluation_warnings++; + op0 = c_fully_fold (op0, require_constant_value, + &op0_maybe_const); + op1 = c_fully_fold (op1, require_constant_value, + &op1_maybe_const); + c_inhibit_evaluation_warnings--; + orig_op0_folded = c_fully_fold (orig_op0, + require_constant_value, + NULL); + orig_op1_folded = c_fully_fold (orig_op1, + require_constant_value, + NULL); + } + + if (warn_sign_compare) + warn_for_sign_compare (location, orig_op0_folded, + orig_op1_folded, op0, op1, + result_type, resultcode); + if (!in_late_binary_op && !int_operands) + { + if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST) + op0 = c_wrap_maybe_const (op0, !op0_maybe_const); + if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST) + op1 = c_wrap_maybe_const (op1, !op1_maybe_const); + } + } + } + } + + /* At this point, RESULT_TYPE must be nonzero to avoid an error message. + If CONVERTED is zero, both args will be converted to type RESULT_TYPE. + Then the expression will be built. + It will be given type FINAL_TYPE if that is nonzero; + otherwise, it will be given type RESULT_TYPE. */ + + if (!result_type) + { + /* Favor showing any expression locations that are available. */ + op_location_t oploc (location, UNKNOWN_LOCATION); + binary_op_rich_location richloc (oploc, orig_op0, orig_op1, true); + binary_op_error (&richloc, code, TREE_TYPE (op0), TREE_TYPE (op1)); + return error_mark_node; + } + + if (build_type == NULL_TREE) + { + build_type = result_type; + if ((type0 != orig_type0 || type1 != orig_type1) + && !boolean_op) + { + gcc_assert (may_need_excess_precision && common); + semantic_result_type = c_common_type (orig_type0, orig_type1); + } + } + + if (!converted) + { + op0 = ep_convert_and_check (location, result_type, op0, + semantic_result_type); + op1 = ep_convert_and_check (location, result_type, op1, + semantic_result_type); + + /* This can happen if one operand has a vector type, and the other + has a different type. */ + if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK) + return error_mark_node; + } + + if (sanitize_flags_p ((SANITIZE_SHIFT + | SANITIZE_DIVIDE + | SANITIZE_FLOAT_DIVIDE + | SANITIZE_SI_OVERFLOW)) + && current_function_decl != NULL_TREE + && (doing_div_or_mod || doing_shift) + && !require_constant_value) + { + /* OP0 and/or OP1 might have side-effects. */ + op0 = save_expr (op0); + op1 = save_expr (op1); + op0 = c_fully_fold (op0, false, NULL); + op1 = c_fully_fold (op1, false, NULL); + if (doing_div_or_mod && (sanitize_flags_p ((SANITIZE_DIVIDE + | SANITIZE_FLOAT_DIVIDE + | SANITIZE_SI_OVERFLOW)))) + instrument_expr = ubsan_instrument_division (location, op0, op1); + else if (doing_shift && sanitize_flags_p (SANITIZE_SHIFT)) + instrument_expr = ubsan_instrument_shift (location, code, op0, op1); + } + + /* Treat expressions in initializers specially as they can't trap. */ + if (int_const_or_overflow) + ret = (require_constant_value + ? fold_build2_initializer_loc (location, resultcode, build_type, + op0, op1) + : fold_build2_loc (location, resultcode, build_type, op0, op1)); + else + ret = build2 (resultcode, build_type, op0, op1); + if (final_type != NULL_TREE) + ret = convert (final_type, ret); + + return_build_binary_op: + gcc_assert (ret != error_mark_node); + if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret) && !int_const) + ret = (int_operands + ? note_integer_operands (ret) + : build1 (NOP_EXPR, TREE_TYPE (ret), ret)); + else if (TREE_CODE (ret) != INTEGER_CST && int_operands + && !in_late_binary_op) + ret = note_integer_operands (ret); + protected_set_expr_location (ret, location); + + if (instrument_expr != NULL) + ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret), + instrument_expr, ret); + + if (semantic_result_type) + ret = build1_loc (location, EXCESS_PRECISION_EXPR, + semantic_result_type, ret); + + return ret; +} + + +/* Convert EXPR to be a truth-value, validating its type for this + purpose. LOCATION is the source location for the expression. */ + +tree +c_objc_common_truthvalue_conversion (location_t location, tree expr) +{ + bool int_const, int_operands; + + switch (TREE_CODE (TREE_TYPE (expr))) + { + case ARRAY_TYPE: + error_at (location, "used array that cannot be converted to pointer where scalar is required"); + return error_mark_node; + + case RECORD_TYPE: + error_at (location, "used struct type value where scalar is required"); + return error_mark_node; + + case UNION_TYPE: + error_at (location, "used union type value where scalar is required"); + return error_mark_node; + + case VOID_TYPE: + error_at (location, "void value not ignored as it ought to be"); + return error_mark_node; + + case POINTER_TYPE: + if (reject_gcc_builtin (expr)) + return error_mark_node; + break; + + case FUNCTION_TYPE: + gcc_unreachable (); + + case VECTOR_TYPE: + error_at (location, "used vector type where scalar is required"); + return error_mark_node; + + default: + break; + } + + int_const = (TREE_CODE (expr) == INTEGER_CST && !TREE_OVERFLOW (expr)); + int_operands = EXPR_INT_CONST_OPERANDS (expr); + if (int_operands && TREE_CODE (expr) != INTEGER_CST) + { + expr = remove_c_maybe_const_expr (expr); + expr = build2 (NE_EXPR, integer_type_node, expr, + convert (TREE_TYPE (expr), integer_zero_node)); + expr = note_integer_operands (expr); + } + else + /* ??? Should we also give an error for vectors rather than leaving + those to give errors later? */ + expr = c_common_truthvalue_conversion (location, expr); + + if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const) + { + if (TREE_OVERFLOW (expr)) + return expr; + else + return note_integer_operands (expr); + } + if (TREE_CODE (expr) == INTEGER_CST && !int_const) + return build1 (NOP_EXPR, TREE_TYPE (expr), expr); + return expr; +} + + +/* Convert EXPR to a contained DECL, updating *TC, *TI and *SE as + required. */ + +tree +c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED, bool *se) +{ + if (TREE_CODE (expr) == COMPOUND_LITERAL_EXPR) + { + tree decl = COMPOUND_LITERAL_EXPR_DECL (expr); + /* Executing a compound literal inside a function reinitializes + it. */ + if (!TREE_STATIC (decl)) + *se = true; + return decl; + } + else + return expr; +} + +/* Generate OMP construct CODE, with BODY and CLAUSES as its compound + statement. LOC is the location of the construct. */ + +tree +c_finish_omp_construct (location_t loc, enum tree_code code, tree body, + tree clauses) +{ + body = c_end_compound_stmt (loc, body, true); + + tree stmt = make_node (code); + TREE_TYPE (stmt) = void_type_node; + OMP_BODY (stmt) = body; + OMP_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + +/* Generate OACC_DATA, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the OACC_DATA. */ + +tree +c_finish_oacc_data (location_t loc, tree clauses, tree block) +{ + tree stmt; + + block = c_end_compound_stmt (loc, block, true); + + stmt = make_node (OACC_DATA); + TREE_TYPE (stmt) = void_type_node; + OACC_DATA_CLAUSES (stmt) = clauses; + OACC_DATA_BODY (stmt) = block; + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + +/* Generate OACC_HOST_DATA, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the OACC_HOST_DATA. */ + +tree +c_finish_oacc_host_data (location_t loc, tree clauses, tree block) +{ + tree stmt; + + block = c_end_compound_stmt (loc, block, true); + + stmt = make_node (OACC_HOST_DATA); + TREE_TYPE (stmt) = void_type_node; + OACC_HOST_DATA_CLAUSES (stmt) = clauses; + OACC_HOST_DATA_BODY (stmt) = block; + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + +/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */ + +tree +c_begin_omp_parallel (void) +{ + tree block; + + keep_next_level (); + block = c_begin_compound_stmt (true); + + return block; +} + +/* Generate OMP_PARALLEL, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the OMP_PARALLEL. */ + +tree +c_finish_omp_parallel (location_t loc, tree clauses, tree block) +{ + tree stmt; + + block = c_end_compound_stmt (loc, block, true); + + stmt = make_node (OMP_PARALLEL); + TREE_TYPE (stmt) = void_type_node; + OMP_PARALLEL_CLAUSES (stmt) = clauses; + OMP_PARALLEL_BODY (stmt) = block; + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + +/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */ + +tree +c_begin_omp_task (void) +{ + tree block; + + keep_next_level (); + block = c_begin_compound_stmt (true); + + return block; +} + +/* Generate OMP_TASK, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the #pragma. */ + +tree +c_finish_omp_task (location_t loc, tree clauses, tree block) +{ + tree stmt; + + block = c_end_compound_stmt (loc, block, true); + + stmt = make_node (OMP_TASK); + TREE_TYPE (stmt) = void_type_node; + OMP_TASK_CLAUSES (stmt) = clauses; + OMP_TASK_BODY (stmt) = block; + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + +/* Generate GOMP_cancel call for #pragma omp cancel. */ + +void +c_finish_omp_cancel (location_t loc, tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL); + int mask = 0; + if (omp_find_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (omp_find_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (omp_find_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (omp_find_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error_at (loc, "%<#pragma omp cancel%> must specify one of " + "%, %, % or % " + "clauses"); + return; + } + tree ifc = omp_find_clause (clauses, OMP_CLAUSE_IF); + if (ifc != NULL_TREE) + { + if (OMP_CLAUSE_IF_MODIFIER (ifc) != ERROR_MARK + && OMP_CLAUSE_IF_MODIFIER (ifc) != VOID_CST) + error_at (OMP_CLAUSE_LOCATION (ifc), + "expected % % clause modifier"); + else + { + tree ifc2 = omp_find_clause (OMP_CLAUSE_CHAIN (ifc), OMP_CLAUSE_IF); + if (ifc2 != NULL_TREE) + { + gcc_assert (OMP_CLAUSE_IF_MODIFIER (ifc) == VOID_CST + && OMP_CLAUSE_IF_MODIFIER (ifc2) != ERROR_MARK + && OMP_CLAUSE_IF_MODIFIER (ifc2) != VOID_CST); + error_at (OMP_CLAUSE_LOCATION (ifc2), + "expected % % clause modifier"); + } + } + + tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc)); + ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR, + boolean_type_node, OMP_CLAUSE_IF_EXPR (ifc), + build_zero_cst (type)); + } + else + ifc = boolean_true_node; + tree stmt = build_call_expr_loc (loc, fn, 2, + build_int_cst (integer_type_node, mask), + ifc); + add_stmt (stmt); +} + +/* Generate GOMP_cancellation_point call for + #pragma omp cancellation point. */ + +void +c_finish_omp_cancellation_point (location_t loc, tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT); + int mask = 0; + if (omp_find_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (omp_find_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (omp_find_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (omp_find_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error_at (loc, "%<#pragma omp cancellation point%> must specify one of " + "%, %, % or % " + "clauses"); + return; + } + tree stmt = build_call_expr_loc (loc, fn, 1, + build_int_cst (integer_type_node, mask)); + add_stmt (stmt); +} + +/* Helper function for handle_omp_array_sections. Called recursively + to handle multiple array-section-subscripts. C is the clause, + T current expression (initially OMP_CLAUSE_DECL), which is either + a TREE_LIST for array-section-subscript (TREE_PURPOSE is low-bound + expression if specified, TREE_VALUE length expression if specified, + TREE_CHAIN is what it has been specified after, or some decl. + TYPES vector is populated with array section types, MAYBE_ZERO_LEN + set to true if any of the array-section-subscript could have length + of zero (explicit or implicit), FIRST_NON_ONE is the index of the + first array-section-subscript which is known not to have length + of one. Given say: + map(a[:b][2:1][:c][:2][:d][e:f][2:5]) + FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] + all are or may have length of 1, array-section-subscript [:2] is the + first one known not to have length 1. For array-section-subscript + <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't + 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we + can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above + case though, as some lengths could be zero. */ + +static tree +handle_omp_array_sections_1 (tree c, tree t, vec &types, + bool &maybe_zero_len, unsigned int &first_non_one, + enum c_omp_region_type ort) +{ + tree ret, low_bound, length, type; + if (TREE_CODE (t) != TREE_LIST) + { + if (error_operand_p (t)) + return error_mark_node; + ret = t; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TYPE_ATOMIC (strip_array_types (TREE_TYPE (t)))) + { + error_at (OMP_CLAUSE_LOCATION (c), "%<_Atomic%> %qE in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + while (TREE_CODE (t) == INDIRECT_REF) + { + t = TREE_OPERAND (t, 0); + STRIP_NOPS (t); + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + t = TREE_OPERAND (t, 0); + } + while (TREE_CODE (t) == COMPOUND_EXPR) + { + t = TREE_OPERAND (t, 1); + STRIP_NOPS (t); + } + if (TREE_CODE (t) == COMPONENT_REF + && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM)) + { + if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + while (TREE_CODE (t) == COMPONENT_REF) + { + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is a member of a union", t); + return error_mark_node; + } + t = TREE_OPERAND (t, 0); + while (TREE_CODE (t) == MEM_REF + || TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ARRAY_REF) + { + t = TREE_OPERAND (t, 0); + STRIP_NOPS (t); + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + t = TREE_OPERAND (t, 0); + } + if (ort == C_ORT_ACC && TREE_CODE (t) == MEM_REF) + { + if (maybe_ne (mem_ref_offset (t), 0)) + error_at (OMP_CLAUSE_LOCATION (c), + "cannot dereference %qE in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + t = TREE_OPERAND (t, 0); + } + } + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + if (DECL_P (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TYPE_ATOMIC (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), "%<_Atomic%> %qD in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && VAR_P (t) + && DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + && TYPE_ATOMIC (TREE_TYPE (t)) + && POINTER_TYPE_P (TREE_TYPE (t))) + { + /* If the array section is pointer based and the pointer + itself is _Atomic qualified, we need to atomically load + the pointer. */ + c_expr expr; + memset (&expr, 0, sizeof (expr)); + expr.value = ret; + expr = convert_lvalue_to_rvalue (OMP_CLAUSE_LOCATION (c), + expr, false, false); + ret = expr.value; + } + return ret; + } + + ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, + maybe_zero_len, first_non_one, ort); + if (ret == error_mark_node || ret == NULL_TREE) + return ret; + + type = TREE_TYPE (ret); + low_bound = TREE_PURPOSE (t); + length = TREE_VALUE (t); + + if (low_bound == error_mark_node || length == error_mark_node) + return error_mark_node; + + if (low_bound && !INTEGRAL_TYPE_P (TREE_TYPE (low_bound))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE of array section does not have integral type", + low_bound); + return error_mark_node; + } + if (length && !INTEGRAL_TYPE_P (TREE_TYPE (length))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE of array section does not have integral type", + length); + return error_mark_node; + } + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)) + { + if (length != integer_one_node) + { + error_at (OMP_CLAUSE_LOCATION (c), + "expected single pointer in %qs clause", + c_omp_map_clause_name (c, ort == C_ORT_ACC)); + return error_mark_node; + } + } + if (length != NULL_TREE) + { + if (!integer_nonzerop (length)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) + { + if (integer_zerop (length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + maybe_zero_len = true; + } + if (first_non_one == types.length () + && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) + first_non_one++; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (length == NULL_TREE + && (TYPE_DOMAIN (type) == NULL_TREE + || TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for unknown bound array type length expression must " + "be specified"); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST + && tree_int_cst_sgn (low_bound) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative low bound in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && tree_int_cst_sgn (length) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative length in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TYPE_DOMAIN (type) + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + == INTEGER_CST) + { + tree size + = fold_convert (sizetype, TYPE_MAX_VALUE (TYPE_DOMAIN (type))); + size = size_binop (PLUS_EXPR, size, size_one_node); + if (TREE_CODE (low_bound) == INTEGER_CST) + { + if (tree_int_cst_lt (size, low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE above array section size " + "in %qs clause", low_bound, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (tree_int_cst_equal (size, low_bound)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + maybe_zero_len = true; + } + else if (length == NULL_TREE + && first_non_one == types.length () + && tree_int_cst_equal + (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + low_bound)) + first_non_one++; + } + else if (length == NULL_TREE) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_IN_REDUCTION + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TASK_REDUCTION) + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + if (length && TREE_CODE (length) == INTEGER_CST) + { + if (tree_int_cst_lt (size, length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE above array section size " + "in %qs clause", length, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST) + { + tree lbpluslen + = size_binop (PLUS_EXPR, + fold_convert (sizetype, low_bound), + fold_convert (sizetype, length)); + if (TREE_CODE (lbpluslen) == INTEGER_CST + && tree_int_cst_lt (size, lbpluslen)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "high bound %qE above array section size " + "in %qs clause", lbpluslen, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + } + } + else if (length == NULL_TREE) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_IN_REDUCTION + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TASK_REDUCTION) + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + + /* For [lb:] we will need to evaluate lb more than once. */ + if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + { + tree lb = save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + } + } + else if (TREE_CODE (type) == POINTER_TYPE) + { + if (length == NULL_TREE) + { + if (TREE_CODE (ret) == PARM_DECL && C_ARRAY_PARAMETER (ret)) + error_at (OMP_CLAUSE_LOCATION (c), + "for array function parameter length expression " + "must be specified"); + else + error_at (OMP_CLAUSE_LOCATION (c), + "for pointer type length expression must be specified"); + return error_mark_node; + } + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && tree_int_cst_sgn (length) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative length in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + /* If there is a pointer type anywhere but in the very first + array-section-subscript, the array section could be non-contiguous. */ + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST) + { + /* If any prior dimension has a non-one length, then deem this + array section as non-contiguous. */ + for (tree d = TREE_CHAIN (t); TREE_CODE (d) == TREE_LIST; + d = TREE_CHAIN (d)) + { + tree d_length = TREE_VALUE (d); + if (d_length == NULL_TREE || !integer_onep (d_length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + } + } + else + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have pointer or array type", ret); + return error_mark_node; + } + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + types.safe_push (TREE_TYPE (ret)); + /* We will need to evaluate lb more than once. */ + tree lb = save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound); + return ret; +} + +/* Handle array sections for clause C. */ + +static bool +handle_omp_array_sections (tree c, enum c_omp_region_type ort) +{ + bool maybe_zero_len = false; + unsigned int first_non_one = 0; + auto_vec types; + tree *tp = &OMP_CLAUSE_DECL (c); + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) + && TREE_CODE (*tp) == TREE_LIST + && TREE_PURPOSE (*tp) + && TREE_CODE (TREE_PURPOSE (*tp)) == TREE_VEC) + tp = &TREE_VALUE (*tp); + tree first = handle_omp_array_sections_1 (c, *tp, types, + maybe_zero_len, first_non_one, + ort); + if (first == error_mark_node) + return true; + if (first == NULL_TREE) + return false; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) + { + tree t = *tp; + tree tem = NULL_TREE; + /* Need to evaluate side effects in the length expressions + if any. */ + while (TREE_CODE (t) == TREE_LIST) + { + if (TREE_VALUE (t) && TREE_SIDE_EFFECTS (TREE_VALUE (t))) + { + if (tem == NULL_TREE) + tem = TREE_VALUE (t); + else + tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), + TREE_VALUE (t), tem); + } + t = TREE_CHAIN (t); + } + if (tem) + first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); + first = c_fully_fold (first, false, NULL, true); + *tp = first; + } + else + { + unsigned int num = types.length (), i; + tree t, side_effects = NULL_TREE, size = NULL_TREE; + tree condition = NULL_TREE; + + if (int_size_in_bytes (TREE_TYPE (first)) <= 0) + maybe_zero_len = true; + + for (i = num, t = OMP_CLAUSE_DECL (c); i > 0; + t = TREE_CHAIN (t)) + { + tree low_bound = TREE_PURPOSE (t); + tree length = TREE_VALUE (t); + + i--; + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + if (!maybe_zero_len && i > first_non_one) + { + if (integer_nonzerop (low_bound)) + goto do_warn_noncontiguous; + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && TYPE_DOMAIN (types[i]) + && TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (types[i]))) + == INTEGER_CST) + { + tree size; + size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + if (!tree_int_cst_equal (length, size)) + { + do_warn_noncontiguous: + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs " + "clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return true; + } + } + if (length != NULL_TREE + && TREE_SIDE_EFFECTS (length)) + { + if (side_effects == NULL_TREE) + side_effects = length; + else + side_effects = build2 (COMPOUND_EXPR, + TREE_TYPE (side_effects), + length, side_effects); + } + } + else + { + tree l; + + if (i > first_non_one + && ((length && integer_nonzerop (length)) + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION)) + continue; + if (length) + l = fold_convert (sizetype, length); + else + { + l = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + l = size_binop (MINUS_EXPR, l, + fold_convert (sizetype, low_bound)); + } + if (i > first_non_one) + { + l = fold_build2 (NE_EXPR, boolean_type_node, l, + size_zero_node); + if (condition == NULL_TREE) + condition = l; + else + condition = fold_build2 (BIT_AND_EXPR, boolean_type_node, + l, condition); + } + else if (size == NULL_TREE) + { + size = size_in_bytes (TREE_TYPE (types[i])); + tree eltype = TREE_TYPE (types[num - 1]); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) + { + if (integer_zerop (size) + || integer_zerop (size_in_bytes (eltype))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + size = size_binop (EXACT_DIV_EXPR, size, + size_in_bytes (eltype)); + } + size = size_binop (MULT_EXPR, size, l); + if (condition) + size = fold_build3 (COND_EXPR, sizetype, condition, + size, size_zero_node); + } + else + size = size_binop (MULT_EXPR, size, l); + } + } + if (side_effects) + size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) + { + size = size_binop (MINUS_EXPR, size, size_one_node); + size = c_fully_fold (size, false, NULL); + size = save_expr (size); + tree index_type = build_index_type (size); + tree eltype = TREE_TYPE (first); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + tree type = build_array_type (eltype, index_type); + tree ptype = build_pointer_type (eltype); + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + tree t2 = build_fold_addr_expr (first); + t2 = fold_convert_loc (OMP_CLAUSE_LOCATION (c), + ptrdiff_type_node, t2); + t2 = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + ptrdiff_type_node, t2, + fold_convert_loc (OMP_CLAUSE_LOCATION (c), + ptrdiff_type_node, t)); + t2 = c_fully_fold (t2, false, NULL); + if (tree_fits_shwi_p (t2)) + t = build2 (MEM_REF, type, t, + build_int_cst (ptype, tree_to_shwi (t2))); + else + { + t2 = fold_convert_loc (OMP_CLAUSE_LOCATION (c), sizetype, t2); + t = build2_loc (OMP_CLAUSE_LOCATION (c), POINTER_PLUS_EXPR, + TREE_TYPE (t), t, t2); + t = build2 (MEM_REF, type, t, build_int_cst (ptype, 0)); + } + OMP_CLAUSE_DECL (c) = t; + return false; + } + first = c_fully_fold (first, false, NULL); + OMP_CLAUSE_DECL (c) = first; + if (size) + size = c_fully_fold (size, false, NULL); + OMP_CLAUSE_SIZE (c) = size; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP + || (TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)) + return false; + gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR); + switch (OMP_CLAUSE_MAP_KIND (c)) + { + case GOMP_MAP_ALLOC: + case GOMP_MAP_IF_PRESENT: + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + case GOMP_MAP_FORCE_TO: + case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_FORCE_TOFROM: + case GOMP_MAP_FORCE_PRESENT: + OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1; + break; + default: + break; + } + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + if (TREE_CODE (t) == COMPONENT_REF) + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH); + else + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER); + OMP_CLAUSE_MAP_IMPLICIT (c2) = OMP_CLAUSE_MAP_IMPLICIT (c); + if (OMP_CLAUSE_MAP_KIND (c2) != GOMP_MAP_FIRSTPRIVATE_POINTER + && !c_mark_addressable (t)) + return false; + OMP_CLAUSE_DECL (c2) = t; + t = build_fold_addr_expr (first); + t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), ptrdiff_type_node, t); + tree ptr = OMP_CLAUSE_DECL (c2); + if (!POINTER_TYPE_P (TREE_TYPE (ptr))) + ptr = build_fold_addr_expr (ptr); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + ptrdiff_type_node, t, + fold_convert_loc (OMP_CLAUSE_LOCATION (c), + ptrdiff_type_node, ptr)); + t = c_fully_fold (t, false, NULL); + OMP_CLAUSE_SIZE (c2) = t; + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = c2; + } + return false; +} + +/* Helper function of finish_omp_clauses. Clone STMT as if we were making + an inline call. But, remap + the OMP_DECL1 VAR_DECL (omp_out resp. omp_orig) to PLACEHOLDER + and OMP_DECL2 VAR_DECL (omp_in resp. omp_priv) to DECL. */ + +static tree +c_clone_omp_udr (tree stmt, tree omp_decl1, tree omp_decl2, + tree decl, tree placeholder) +{ + copy_body_data id; + hash_map decl_map; + + decl_map.put (omp_decl1, placeholder); + decl_map.put (omp_decl2, decl); + memset (&id, 0, sizeof (id)); + id.src_fn = DECL_CONTEXT (omp_decl1); + id.dst_fn = current_function_decl; + id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn); + id.decl_map = &decl_map; + + id.copy_decl = copy_decl_no_change; + id.transform_call_graph_edges = CB_CGE_DUPLICATE; + id.transform_new_cfg = true; + id.transform_return_to_modify = false; + id.eh_lp_nr = 0; + walk_tree (&stmt, copy_tree_body_r, &id, NULL); + return stmt; +} + +/* Helper function of c_finish_omp_clauses, called via walk_tree. + Find OMP_CLAUSE_PLACEHOLDER (passed in DATA) in *TP. */ + +static tree +c_find_omp_placeholder_r (tree *tp, int *, void *data) +{ + if (*tp == (tree) data) + return *tp; + return NULL_TREE; +} + +/* Similarly, but also walk aggregate fields. */ + +struct c_find_omp_var_s { tree var; hash_set *pset; }; + +static tree +c_find_omp_var_r (tree *tp, int *, void *data) +{ + if (*tp == ((struct c_find_omp_var_s *) data)->var) + return *tp; + if (RECORD_OR_UNION_TYPE_P (*tp)) + { + tree field; + hash_set *pset = ((struct c_find_omp_var_s *) data)->pset; + + for (field = TYPE_FIELDS (*tp); field; + field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL) + { + tree ret = walk_tree (&DECL_FIELD_OFFSET (field), + c_find_omp_var_r, data, pset); + if (ret) + return ret; + ret = walk_tree (&DECL_SIZE (field), c_find_omp_var_r, data, pset); + if (ret) + return ret; + ret = walk_tree (&DECL_SIZE_UNIT (field), c_find_omp_var_r, data, + pset); + if (ret) + return ret; + ret = walk_tree (&TREE_TYPE (field), c_find_omp_var_r, data, pset); + if (ret) + return ret; + } + } + else if (INTEGRAL_TYPE_P (*tp)) + return walk_tree (&TYPE_MAX_VALUE (*tp), c_find_omp_var_r, data, + ((struct c_find_omp_var_s *) data)->pset); + return NULL_TREE; +} + +/* Finish OpenMP iterators ITER. Return true if they are errorneous + and clauses containing them should be removed. */ + +static bool +c_omp_finish_iterators (tree iter) +{ + bool ret = false; + for (tree it = iter; it; it = TREE_CHAIN (it)) + { + tree var = TREE_VEC_ELT (it, 0); + tree begin = TREE_VEC_ELT (it, 1); + tree end = TREE_VEC_ELT (it, 2); + tree step = TREE_VEC_ELT (it, 3); + tree orig_step; + tree type = TREE_TYPE (var); + location_t loc = DECL_SOURCE_LOCATION (var); + if (type == error_mark_node) + { + ret = true; + continue; + } + if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) + { + error_at (loc, "iterator %qD has neither integral nor pointer type", + var); + ret = true; + continue; + } + else if (TYPE_ATOMIC (type)) + { + error_at (loc, "iterator %qD has %<_Atomic%> qualified type", var); + ret = true; + continue; + } + else if (TYPE_READONLY (type)) + { + error_at (loc, "iterator %qD has const qualified type", var); + ret = true; + continue; + } + else if (step == error_mark_node + || TREE_TYPE (step) == error_mark_node) + { + ret = true; + continue; + } + else if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) + { + error_at (EXPR_LOC_OR_LOC (step, loc), + "iterator step with non-integral type"); + ret = true; + continue; + } + begin = c_fully_fold (build_c_cast (loc, type, begin), false, NULL); + end = c_fully_fold (build_c_cast (loc, type, end), false, NULL); + orig_step = save_expr (c_fully_fold (step, false, NULL)); + tree stype = POINTER_TYPE_P (type) ? sizetype : type; + step = c_fully_fold (build_c_cast (loc, stype, orig_step), false, NULL); + if (POINTER_TYPE_P (type)) + { + begin = save_expr (begin); + step = pointer_int_sum (loc, PLUS_EXPR, begin, step); + step = fold_build2_loc (loc, MINUS_EXPR, sizetype, + fold_convert (sizetype, step), + fold_convert (sizetype, begin)); + step = fold_convert (ssizetype, step); + } + if (integer_zerop (step)) + { + error_at (loc, "iterator %qD has zero step", var); + ret = true; + continue; + } + + if (begin == error_mark_node + || end == error_mark_node + || step == error_mark_node + || orig_step == error_mark_node) + { + ret = true; + continue; + } + hash_set pset; + tree it2; + for (it2 = TREE_CHAIN (it); it2; it2 = TREE_CHAIN (it2)) + { + tree var2 = TREE_VEC_ELT (it2, 0); + tree begin2 = TREE_VEC_ELT (it2, 1); + tree end2 = TREE_VEC_ELT (it2, 2); + tree step2 = TREE_VEC_ELT (it2, 3); + tree type2 = TREE_TYPE (var2); + location_t loc2 = DECL_SOURCE_LOCATION (var2); + struct c_find_omp_var_s data = { var, &pset }; + if (walk_tree (&type2, c_find_omp_var_r, &data, &pset)) + { + error_at (loc2, + "type of iterator %qD refers to outer iterator %qD", + var2, var); + break; + } + else if (walk_tree (&begin2, c_find_omp_var_r, &data, &pset)) + { + error_at (EXPR_LOC_OR_LOC (begin2, loc2), + "begin expression refers to outer iterator %qD", var); + break; + } + else if (walk_tree (&end2, c_find_omp_var_r, &data, &pset)) + { + error_at (EXPR_LOC_OR_LOC (end2, loc2), + "end expression refers to outer iterator %qD", var); + break; + } + else if (walk_tree (&step2, c_find_omp_var_r, &data, &pset)) + { + error_at (EXPR_LOC_OR_LOC (step2, loc2), + "step expression refers to outer iterator %qD", var); + break; + } + } + if (it2) + { + ret = true; + continue; + } + TREE_VEC_ELT (it, 1) = begin; + TREE_VEC_ELT (it, 2) = end; + TREE_VEC_ELT (it, 3) = step; + TREE_VEC_ELT (it, 4) = orig_step; + } + return ret; +} + +/* Ensure that pointers are used in OpenACC attach and detach clauses. + Return true if an error has been detected. */ + +static bool +c_oacc_check_attachments (tree c) +{ + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + return false; + + /* OpenACC attach / detach clauses must be pointers. */ + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH) + { + tree t = OMP_CLAUSE_DECL (c); + + while (TREE_CODE (t) == TREE_LIST) + t = TREE_CHAIN (t); + + if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), "expected pointer in %qs clause", + c_omp_map_clause_name (c, true)); + return true; + } + } + + return false; +} + +/* For all elements of CLAUSES, validate them against their constraints. + Remove any elements from the list that are invalid. */ + +tree +c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) +{ + bitmap_head generic_head, firstprivate_head, lastprivate_head; + bitmap_head aligned_head, map_head, map_field_head, map_firstprivate_head; + bitmap_head oacc_reduction_head; + tree c, t, type, *pc; + tree simdlen = NULL_TREE, safelen = NULL_TREE; + bool branch_seen = false; + bool copyprivate_seen = false; + bool mergeable_seen = false; + tree *detach_seen = NULL; + bool linear_variable_step_check = false; + tree *nowait_clause = NULL; + tree ordered_clause = NULL_TREE; + tree schedule_clause = NULL_TREE; + bool oacc_async = false; + bool indir_component_ref_p = false; + tree last_iterators = NULL_TREE; + bool last_iterators_remove = false; + tree *nogroup_seen = NULL; + tree *order_clause = NULL; + /* 1 if normal/task reduction has been seen, -1 if inscan reduction + has been seen, -2 if mixed inscan/normal reduction diagnosed. */ + int reduction_seen = 0; + bool allocate_seen = false; + bool implicit_moved = false; + bool target_in_reduction_seen = false; + + bitmap_obstack_initialize (NULL); + bitmap_initialize (&generic_head, &bitmap_default_obstack); + bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); + bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); + bitmap_initialize (&aligned_head, &bitmap_default_obstack); + /* If ort == C_ORT_OMP_DECLARE_SIMD used as uniform_head instead. */ + bitmap_initialize (&map_head, &bitmap_default_obstack); + bitmap_initialize (&map_field_head, &bitmap_default_obstack); + bitmap_initialize (&map_firstprivate_head, &bitmap_default_obstack); + /* If ort == C_ORT_OMP used as nontemporal_head or use_device_xxx_head + instead and for ort == C_ORT_OMP_TARGET used as in_reduction_head. */ + bitmap_initialize (&oacc_reduction_head, &bitmap_default_obstack); + + if (ort & C_ORT_ACC) + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ASYNC) + { + oacc_async = true; + break; + } + + for (pc = &clauses, c = clauses; c ; c = *pc) + { + bool remove = false; + bool need_complete = false; + bool need_implicitly_determined = false; + + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_SHARED: + need_implicitly_determined = true; + goto check_dup_generic; + + case OMP_CLAUSE_PRIVATE: + need_complete = true; + need_implicitly_determined = true; + goto check_dup_generic; + + case OMP_CLAUSE_REDUCTION: + if (reduction_seen == 0) + reduction_seen = OMP_CLAUSE_REDUCTION_INSCAN (c) ? -1 : 1; + else if (reduction_seen != -2 + && reduction_seen != (OMP_CLAUSE_REDUCTION_INSCAN (c) + ? -1 : 1)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% and non-% % clauses " + "on the same construct"); + reduction_seen = -2; + } + /* FALLTHRU */ + case OMP_CLAUSE_IN_REDUCTION: + case OMP_CLAUSE_TASK_REDUCTION: + need_implicitly_determined = true; + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c, ort)) + { + remove = true; + break; + } + + t = OMP_CLAUSE_DECL (c); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && OMP_CLAUSE_REDUCTION_INSCAN (c)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% % clause with array " + "section"); + remove = true; + break; + } + } + t = require_complete_type (OMP_CLAUSE_LOCATION (c), t); + if (t == error_mark_node) + { + remove = true; + break; + } + if (oacc_async) + c_mark_addressable (t); + type = TREE_TYPE (t); + if (TREE_CODE (t) == MEM_REF) + type = TREE_TYPE (type); + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree oatype = type; + gcc_assert (TREE_CODE (t) != MEM_REF); + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + if (integer_zerop (TYPE_SIZE_UNIT (type))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD in % clause is a zero size array", + t); + remove = true; + break; + } + tree size = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (oatype), + TYPE_SIZE_UNIT (type)); + if (integer_zerop (size)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD in % clause is a zero size array", + t); + remove = true; + break; + } + size = size_binop (MINUS_EXPR, size, size_one_node); + size = save_expr (size); + tree index_type = build_index_type (size); + tree atype = build_array_type (TYPE_MAIN_VARIANT (type), + index_type); + atype = c_build_qualified_type (atype, TYPE_QUALS (type)); + tree ptype = build_pointer_type (type); + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, atype, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + } + if (TYPE_ATOMIC (type)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<_Atomic%> %qE in % clause", t); + remove = true; + break; + } + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_REDUCTION_TASK (c)) + { + /* Disallow zero sized or potentially zero sized task + reductions. */ + if (integer_zerop (TYPE_SIZE_UNIT (type))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero sized type %qT in %qs clause", type, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + break; + } + else if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "variable sized type %qT in %qs clause", type, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + break; + } + } + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE + && (FLOAT_TYPE_P (type) + || TREE_CODE (type) == COMPLEX_TYPE)) + { + enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c); + const char *r_name = NULL; + + switch (r_code) + { + case PLUS_EXPR: + case MULT_EXPR: + case MINUS_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + break; + case MIN_EXPR: + if (TREE_CODE (type) == COMPLEX_TYPE) + r_name = "min"; + break; + case MAX_EXPR: + if (TREE_CODE (type) == COMPLEX_TYPE) + r_name = "max"; + break; + case BIT_AND_EXPR: + r_name = "&"; + break; + case BIT_XOR_EXPR: + r_name = "^"; + break; + case BIT_IOR_EXPR: + r_name = "|"; + break; + default: + gcc_unreachable (); + } + if (r_name) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE has invalid type for %", + t, r_name); + remove = true; + break; + } + } + else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node) + { + error_at (OMP_CLAUSE_LOCATION (c), + "user defined reduction not found for %qE", t); + remove = true; + break; + } + else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + { + tree list = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); + type = TYPE_MAIN_VARIANT (type); + tree placeholder = build_decl (OMP_CLAUSE_LOCATION (c), + VAR_DECL, NULL_TREE, type); + tree decl_placeholder = NULL_TREE; + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder; + DECL_ARTIFICIAL (placeholder) = 1; + DECL_IGNORED_P (placeholder) = 1; + if (TREE_CODE (t) == MEM_REF) + { + decl_placeholder = build_decl (OMP_CLAUSE_LOCATION (c), + VAR_DECL, NULL_TREE, type); + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = decl_placeholder; + DECL_ARTIFICIAL (decl_placeholder) = 1; + DECL_IGNORED_P (decl_placeholder) = 1; + } + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 0))) + c_mark_addressable (placeholder); + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 1))) + c_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); + OMP_CLAUSE_REDUCTION_MERGE (c) + = c_clone_omp_udr (TREE_VEC_ELT (list, 2), + TREE_VEC_ELT (list, 0), + TREE_VEC_ELT (list, 1), + decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c), placeholder); + OMP_CLAUSE_REDUCTION_MERGE (c) + = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, + void_type_node, NULL_TREE, + OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE); + TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_MERGE (c)) = 1; + if (TREE_VEC_LENGTH (list) == 6) + { + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 3))) + c_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 4))) + c_mark_addressable (placeholder); + tree init = TREE_VEC_ELT (list, 5); + if (init == error_mark_node) + init = DECL_INITIAL (TREE_VEC_ELT (list, 3)); + OMP_CLAUSE_REDUCTION_INIT (c) + = c_clone_omp_udr (init, TREE_VEC_ELT (list, 4), + TREE_VEC_ELT (list, 3), + decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c), placeholder); + if (TREE_VEC_ELT (list, 5) == error_mark_node) + { + tree v = decl_placeholder ? decl_placeholder : t; + OMP_CLAUSE_REDUCTION_INIT (c) + = build2 (INIT_EXPR, TREE_TYPE (v), v, + OMP_CLAUSE_REDUCTION_INIT (c)); + } + if (walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c), + c_find_omp_placeholder_r, + placeholder, NULL)) + OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1; + } + else + { + tree init; + tree v = decl_placeholder ? decl_placeholder : t; + if (AGGREGATE_TYPE_P (TREE_TYPE (v))) + init = build_constructor (TREE_TYPE (v), NULL); + else + init = fold_convert (TREE_TYPE (v), integer_zero_node); + OMP_CLAUSE_REDUCTION_INIT (c) + = build2 (INIT_EXPR, TREE_TYPE (v), v, init); + } + OMP_CLAUSE_REDUCTION_INIT (c) + = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, + void_type_node, NULL_TREE, + OMP_CLAUSE_REDUCTION_INIT (c), NULL_TREE); + TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_INIT (c)) = 1; + } + if (TREE_CODE (t) == MEM_REF) + { + if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t))) == NULL_TREE + || TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t)))) + != INTEGER_CST) + { + sorry ("variable length element type in array " + "% clause"); + remove = true; + break; + } + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == ADDR_EXPR) + t = TREE_OPERAND (t, 0); + } + goto check_dup_generic_t; + + case OMP_CLAUSE_COPYPRIVATE: + copyprivate_seen = true; + if (nowait_clause) + { + error_at (OMP_CLAUSE_LOCATION (*nowait_clause), + "% clause must not be used together " + "with %"); + *nowait_clause = OMP_CLAUSE_CHAIN (*nowait_clause); + nowait_clause = NULL; + } + goto check_dup_generic; + + case OMP_CLAUSE_COPYIN: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t) || !DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE must be % for %", t); + remove = true; + break; + } + goto check_dup_generic; + + case OMP_CLAUSE_LINEAR: + if (ort != C_ORT_OMP_DECLARE_SIMD) + need_implicitly_determined = true; + t = OMP_CLAUSE_DECL (c); + if (ort != C_ORT_OMP_DECLARE_SIMD + && OMP_CLAUSE_LINEAR_KIND (c) != OMP_CLAUSE_LINEAR_DEFAULT) + { + error_at (OMP_CLAUSE_LOCATION (c), + "modifier should not be specified in % " + "clause on % or % constructs"); + OMP_CLAUSE_LINEAR_KIND (c) = OMP_CLAUSE_LINEAR_DEFAULT; + } + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "linear clause applied to non-integral non-pointer " + "variable with type %qT", TREE_TYPE (t)); + remove = true; + break; + } + if (TYPE_ATOMIC (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<_Atomic%> %qD in % clause", t); + remove = true; + break; + } + if (ort == C_ORT_OMP_DECLARE_SIMD) + { + tree s = OMP_CLAUSE_LINEAR_STEP (c); + if (TREE_CODE (s) == PARM_DECL) + { + OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c) = 1; + /* map_head bitmap is used as uniform_head if + declare_simd. */ + if (!bitmap_bit_p (&map_head, DECL_UID (s))) + linear_variable_step_check = true; + goto check_dup_generic; + } + if (TREE_CODE (s) != INTEGER_CST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause step %qE is neither constant " + "nor a parameter", s); + remove = true; + break; + } + } + if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE) + { + tree s = OMP_CLAUSE_LINEAR_STEP (c); + s = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, + OMP_CLAUSE_DECL (c), s); + s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + sizetype, fold_convert (sizetype, s), + fold_convert + (sizetype, OMP_CLAUSE_DECL (c))); + if (s == error_mark_node) + s = size_one_node; + OMP_CLAUSE_LINEAR_STEP (c) = s; + } + else + OMP_CLAUSE_LINEAR_STEP (c) + = fold_convert (TREE_TYPE (t), OMP_CLAUSE_LINEAR_STEP (c)); + goto check_dup_generic; + + check_dup_generic: + t = OMP_CLAUSE_DECL (c); + check_dup_generic_t: + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if ((ort == C_ORT_ACC + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + || (ort == C_ORT_OMP + && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR + || (OMP_CLAUSE_CODE (c) + == OMP_CLAUSE_USE_DEVICE_ADDR))) + || (ort == C_ORT_OMP_TARGET + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + && (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data-sharing " + "clauses", t); + remove = true; + break; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) + target_in_reduction_seen = true; + if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + ort == C_ORT_ACC + ? "%qD appears more than once in reduction clauses" + : "%qD appears more than once in data clauses", + t); + remove = true; + } + else + bitmap_set_bit (&oacc_reduction_head, DECL_UID (t)); + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) + || bitmap_bit_p (&lastprivate_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in data clauses", t); + remove = true; + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + && bitmap_bit_p (&map_head, DECL_UID (t))) + { + if (ort == C_ORT_ACC) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears both in data and map clauses", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_FIRSTPRIVATE: + if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) && !implicit_moved) + { + move_implicit: + implicit_moved = true; + /* Move firstprivate and map clauses with + OMP_CLAUSE_{FIRSTPRIVATE,MAP}_IMPLICIT set to the end of + clauses chain. */ + tree cl1 = NULL_TREE, cl2 = NULL_TREE; + tree *pc1 = pc, *pc2 = &cl1, *pc3 = &cl2; + while (*pc1) + if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (*pc1)) + { + *pc3 = *pc1; + pc3 = &OMP_CLAUSE_CHAIN (*pc3); + *pc1 = OMP_CLAUSE_CHAIN (*pc1); + } + else if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_IMPLICIT (*pc1)) + { + *pc2 = *pc1; + pc2 = &OMP_CLAUSE_CHAIN (*pc2); + *pc1 = OMP_CLAUSE_CHAIN (*pc1); + } + else + pc1 = &OMP_CLAUSE_CHAIN (*pc1); + *pc3 = NULL; + *pc2 = cl2; + *pc1 = cl1; + continue; + } + t = OMP_CLAUSE_DECL (c); + need_complete = true; + need_implicitly_determined = true; + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %", t); + remove = true; + } + else if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c) + && bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) + remove = true; + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in data clauses", t); + remove = true; + } + else if (bitmap_bit_p (&map_head, DECL_UID (t))) + { + if (ort == C_ORT_ACC) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); + else if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c)) + /* Silently drop the clause. */; + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears both in data and map clauses", t); + remove = true; + } + else + bitmap_set_bit (&firstprivate_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_LASTPRIVATE: + t = OMP_CLAUSE_DECL (c); + need_complete = true; + need_implicitly_determined = true; + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %", t); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&lastprivate_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in data clauses", t); + remove = true; + } + else + bitmap_set_bit (&lastprivate_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_ALIGNED: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in % clause", t); + remove = true; + } + else if (!POINTER_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE in % clause is neither a pointer nor " + "an array", t); + remove = true; + } + else if (TYPE_ATOMIC (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<_Atomic%> %qD in % clause", t); + remove = true; + break; + } + else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in % clauses", + t); + remove = true; + } + else + bitmap_set_bit (&aligned_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_NONTEMPORAL: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in % clause", t); + remove = true; + } + else if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in % " + "clauses", t); + remove = true; + } + else + bitmap_set_bit (&oacc_reduction_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_ALLOCATE: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in % clause", t); + remove = true; + } + else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "%qE appears more than once in % clauses", + t); + remove = true; + } + else + { + bitmap_set_bit (&aligned_head, DECL_UID (t)); + if (!OMP_CLAUSE_ALLOCATE_COMBINED (c)) + allocate_seen = true; + } + break; + + case OMP_CLAUSE_DEPEND: + t = OMP_CLAUSE_DECL (c); + if (t == NULL_TREE) + { + gcc_assert (OMP_CLAUSE_DEPEND_KIND (c) + == OMP_CLAUSE_DEPEND_SOURCE); + break; + } + if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + { + gcc_assert (TREE_CODE (t) == TREE_LIST); + for (; t; t = TREE_CHAIN (t)) + { + tree decl = TREE_VALUE (t); + if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) + { + tree offset = TREE_PURPOSE (t); + bool neg = wi::neg_p (wi::to_wide (offset)); + offset = fold_unary (ABS_EXPR, TREE_TYPE (offset), offset); + tree t2 = pointer_int_sum (OMP_CLAUSE_LOCATION (c), + neg ? MINUS_EXPR : PLUS_EXPR, + decl, offset); + t2 = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + sizetype, + fold_convert (sizetype, t2), + fold_convert (sizetype, decl)); + if (t2 == error_mark_node) + { + remove = true; + break; + } + TREE_PURPOSE (t) = t2; + } + } + break; + } + /* FALLTHRU */ + case OMP_CLAUSE_AFFINITY: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST + && TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + { + if (TREE_PURPOSE (t) != last_iterators) + last_iterators_remove + = c_omp_finish_iterators (TREE_PURPOSE (t)); + last_iterators = TREE_PURPOSE (t); + t = TREE_VALUE (t); + if (last_iterators_remove) + t = error_mark_node; + } + else + last_iterators = NULL_TREE; + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c, ort)) + remove = true; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause with % dependence " + "type on array section"); + remove = true; + } + break; + } + if (t == error_mark_node) + remove = true; + else if (!lvalue_p (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not lvalue expression nor array section in " + "%qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TREE_CODE (t) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (t, 1))) + { + gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY); + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) + { + if (!c_omp_depend_t_p (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have % type in " + "% clause with % dependence " + "type", t); + remove = true; + } + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && c_omp_depend_t_p (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE should not have % type in " + "% clause with dependence type other than " + "%", t); + remove = true; + } + if (!remove) + { + tree addr = build_unary_op (OMP_CLAUSE_LOCATION (c), ADDR_EXPR, + t, false); + if (addr == error_mark_node) + remove = true; + else + { + t = build_indirect_ref (OMP_CLAUSE_LOCATION (c), addr, + RO_UNARY_STAR); + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (OMP_CLAUSE_DECL (c)) == TREE_LIST + && TREE_PURPOSE (OMP_CLAUSE_DECL (c)) + && (TREE_CODE (TREE_PURPOSE (OMP_CLAUSE_DECL (c))) + == TREE_VEC)) + TREE_VALUE (OMP_CLAUSE_DECL (c)) = t; + else + OMP_CLAUSE_DECL (c) = t; + } + } + break; + + case OMP_CLAUSE_MAP: + if (OMP_CLAUSE_MAP_IMPLICIT (c) && !implicit_moved) + goto move_implicit; + /* FALLTHRU */ + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE__CACHE_: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c, ort)) + remove = true; + else + { + t = OMP_CLAUSE_DECL (c); + if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section does not have mappable type " + "in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TYPE_ATOMIC (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<_Atomic%> %qE in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + while (TREE_CODE (t) == ARRAY_REF) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + { + do + { + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == MEM_REF + || TREE_CODE (t) == INDIRECT_REF) + { + t = TREE_OPERAND (t, 0); + STRIP_NOPS (t); + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + t = TREE_OPERAND (t, 0); + } + } + while (TREE_CODE (t) == COMPONENT_REF + || TREE_CODE (t) == ARRAY_REF); + + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_IMPLICIT (c) + && (bitmap_bit_p (&map_head, DECL_UID (t)) + || bitmap_bit_p (&map_field_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, + DECL_UID (t)))) + { + remove = true; + break; + } + if (bitmap_bit_p (&map_field_head, DECL_UID (t))) + break; + if (bitmap_bit_p (&map_head, DECL_UID (t))) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in motion " + "clauses", t); + else if (ort == C_ORT_ACC) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data " + "clauses", t); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in map " + "clauses", t); + remove = true; + } + else + { + bitmap_set_bit (&map_head, DECL_UID (t)); + bitmap_set_bit (&map_field_head, DECL_UID (t)); + } + } + } + if (c_oacc_check_attachments (c)) + remove = true; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)) + /* In this case, we have a single array element which is a + pointer, and we already set OMP_CLAUSE_SIZE in + handle_omp_array_sections above. For attach/detach clauses, + reset the OMP_CLAUSE_SIZE (representing a bias) to zero + here. */ + OMP_CLAUSE_SIZE (c) = size_zero_node; + break; + } + if (t == error_mark_node) + { + remove = true; + break; + } + /* OpenACC attach / detach clauses must be pointers. */ + if (c_oacc_check_attachments (c)) + { + remove = true; + break; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)) + /* For attach/detach clauses, set OMP_CLAUSE_SIZE (representing a + bias) to zero here, so it is not set erroneously to the pointer + size later on in gimplify.c. */ + OMP_CLAUSE_SIZE (c) = size_zero_node; + while (TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ARRAY_REF) + { + t = TREE_OPERAND (t, 0); + STRIP_NOPS (t); + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + t = TREE_OPERAND (t, 0); + } + while (TREE_CODE (t) == COMPOUND_EXPR) + { + t = TREE_OPERAND (t, 1); + STRIP_NOPS (t); + } + indir_component_ref_p = false; + if (TREE_CODE (t) == COMPONENT_REF + && (TREE_CODE (TREE_OPERAND (t, 0)) == MEM_REF + || TREE_CODE (TREE_OPERAND (t, 0)) == INDIRECT_REF + || TREE_CODE (TREE_OPERAND (t, 0)) == ARRAY_REF)) + { + t = TREE_OPERAND (TREE_OPERAND (t, 0), 0); + indir_component_ref_p = true; + STRIP_NOPS (t); + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + t = TREE_OPERAND (t, 0); + } + + if (TREE_CODE (t) == COMPONENT_REF + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) + { + if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have a mappable type in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TYPE_ATOMIC (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<_Atomic%> %qE in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + while (TREE_CODE (t) == COMPONENT_REF) + { + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) + == UNION_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is a member of a union", t); + remove = true; + break; + } + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == MEM_REF) + { + if (maybe_ne (mem_ref_offset (t), 0)) + error_at (OMP_CLAUSE_LOCATION (c), + "cannot dereference %qE in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + t = TREE_OPERAND (t, 0); + } + while (TREE_CODE (t) == MEM_REF + || TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ARRAY_REF) + { + t = TREE_OPERAND (t, 0); + STRIP_NOPS (t); + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + t = TREE_OPERAND (t, 0); + } + } + if (remove) + break; + if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) + { + if (bitmap_bit_p (&map_field_head, DECL_UID (t)) + || (ort != C_ORT_ACC + && bitmap_bit_p (&map_head, DECL_UID (t)))) + break; + } + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (VAR_P (t) && DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP + || (OMP_CLAUSE_MAP_KIND (c) + != GOMP_MAP_FIRSTPRIVATE_POINTER)) + && !indir_component_ref_p + && !c_mark_addressable (t)) + remove = true; + else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER + || (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_POINTER) + || (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FORCE_DEVICEPTR))) + && t == OMP_CLAUSE_DECL (c) + && !lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TREE_TYPE (t) == error_mark_node) + remove = true; + else if (TYPE_ATOMIC (strip_array_types (TREE_TYPE (t)))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<_Atomic%> %qE in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_IMPLICIT (c) + && (bitmap_bit_p (&map_head, DECL_UID (t)) + || bitmap_bit_p (&map_field_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))) + remove = true; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + { + if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); + remove = true; + } + else if (bitmap_bit_p (&map_head, DECL_UID (t)) + && !bitmap_bit_p (&map_field_head, DECL_UID (t))) + { + if (ort == C_ORT_ACC) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears both in data and map clauses", t); + remove = true; + } + else + bitmap_set_bit (&map_firstprivate_head, DECL_UID (t)); + } + else if (bitmap_bit_p (&map_head, DECL_UID (t)) + && !bitmap_bit_p (&map_field_head, DECL_UID (t))) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in motion clauses", t); + else if (ort == C_ORT_ACC) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in map clauses", t); + remove = true; + } + else if (ort == C_ORT_ACC + && bitmap_bit_p (&generic_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); + remove = true; + } + else if (bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + { + if (ort == C_ORT_ACC) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears both in data and map clauses", t); + remove = true; + } + else + { + bitmap_set_bit (&map_head, DECL_UID (t)); + if (t != OMP_CLAUSE_DECL (c) + && TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPONENT_REF) + bitmap_set_bit (&map_field_head, DECL_UID (t)); + } + break; + + case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_LINK: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == FUNCTION_DECL + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) + ; + else if (!VAR_P (t)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is neither a variable nor a function name in " + "clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + if (remove) + break; + if (bitmap_bit_p (&generic_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once on the same " + "% directive", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_UNIFORM: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != PARM_DECL) + { + if (DECL_P (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not an argument in % clause", t); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not an argument in % clause", t); + remove = true; + break; + } + /* map_head bitmap is used as uniform_head if declare_simd. */ + bitmap_set_bit (&map_head, DECL_UID (t)); + goto check_dup_generic; + + case OMP_CLAUSE_IS_DEVICE_PTR: + case OMP_CLAUSE_USE_DEVICE_PTR: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR + && ort != C_ORT_ACC) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qs variable is not a pointer", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qs variable is neither a pointer nor an array", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } + goto check_dup_generic; + + case OMP_CLAUSE_USE_DEVICE_ADDR: + t = OMP_CLAUSE_DECL (c); + if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) + c_mark_addressable (t); + goto check_dup_generic; + + case OMP_CLAUSE_NOWAIT: + if (copyprivate_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause must not be used together " + "with %"); + remove = true; + break; + } + nowait_clause = pc; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_ORDER: + if (ordered_clause) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause must not be used together " + "with %"); + remove = true; + break; + } + else if (order_clause) + { + /* Silently remove duplicates. */ + remove = true; + break; + } + order_clause = pc; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_DETACH: + t = OMP_CLAUSE_DECL (c); + if (detach_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "too many %qs clauses on a task construct", + "detach"); + remove = true; + break; + } + detach_seen = pc; + pc = &OMP_CLAUSE_CHAIN (c); + c_mark_addressable (t); + continue; + + case OMP_CLAUSE_IF: + case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: + case OMP_CLAUSE_DEFAULT: + case OMP_CLAUSE_UNTIED: + case OMP_CLAUSE_COLLAPSE: + case OMP_CLAUSE_FINAL: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_DEVICE_TYPE: + case OMP_CLAUSE_PRIORITY: + case OMP_CLAUSE_GRAINSIZE: + case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: + case OMP_CLAUSE_DEFAULTMAP: + case OMP_CLAUSE_BIND: + case OMP_CLAUSE_NUM_GANGS: + case OMP_CLAUSE_NUM_WORKERS: + case OMP_CLAUSE_VECTOR_LENGTH: + case OMP_CLAUSE_ASYNC: + case OMP_CLAUSE_WAIT: + case OMP_CLAUSE_AUTO: + case OMP_CLAUSE_INDEPENDENT: + case OMP_CLAUSE_SEQ: + case OMP_CLAUSE_GANG: + case OMP_CLAUSE_WORKER: + case OMP_CLAUSE_VECTOR: + case OMP_CLAUSE_TILE: + case OMP_CLAUSE_IF_PRESENT: + case OMP_CLAUSE_FINALIZE: + case OMP_CLAUSE_NOHOST: + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_MERGEABLE: + mergeable_seen = true; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_NOGROUP: + nogroup_seen = pc; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_SCHEDULE: + schedule_clause = c; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_ORDERED: + ordered_clause = c; + if (order_clause) + { + error_at (OMP_CLAUSE_LOCATION (*order_clause), + "% clause must not be used together " + "with %"); + *order_clause = OMP_CLAUSE_CHAIN (*order_clause); + order_clause = NULL; + } + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_SAFELEN: + safelen = c; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + case OMP_CLAUSE_SIMDLEN: + simdlen = c; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + if (branch_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause is incompatible with " + "%"); + remove = true; + break; + } + branch_seen = true; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_INCLUSIVE: + case OMP_CLAUSE_EXCLUSIVE: + need_complete = true; + need_implicitly_determined = true; + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + break; + + default: + gcc_unreachable (); + } + + if (!remove) + { + t = OMP_CLAUSE_DECL (c); + + if (need_complete) + { + t = require_complete_type (OMP_CLAUSE_LOCATION (c), t); + if (t == error_mark_node) + remove = true; + } + + if (need_implicitly_determined) + { + const char *share_name = NULL; + + if (VAR_P (t) && DECL_THREAD_LOCAL_P (t)) + share_name = "threadprivate"; + else switch (c_omp_predetermined_sharing (t)) + { + case OMP_CLAUSE_DEFAULT_UNSPECIFIED: + break; + case OMP_CLAUSE_DEFAULT_SHARED: + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) + && c_omp_predefined_variable (t)) + /* The __func__ variable and similar function-local + predefined variables may be listed in a shared or + firstprivate clause. */ + break; + share_name = "shared"; + break; + case OMP_CLAUSE_DEFAULT_PRIVATE: + share_name = "private"; + break; + default: + gcc_unreachable (); + } + if (share_name) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is predetermined %qs for %qs", + t, share_name, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TREE_READONLY (t) + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SHARED + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FIRSTPRIVATE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% qualified %qE may appear only in " + "% or % clauses", t); + remove = true; + } + } + } + + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + + if (simdlen + && safelen + && tree_int_cst_lt (OMP_CLAUSE_SAFELEN_EXPR (safelen), + OMP_CLAUSE_SIMDLEN_EXPR (simdlen))) + { + error_at (OMP_CLAUSE_LOCATION (simdlen), + "% clause value is bigger than " + "% clause value"); + OMP_CLAUSE_SIMDLEN_EXPR (simdlen) + = OMP_CLAUSE_SAFELEN_EXPR (safelen); + } + + if (ordered_clause + && schedule_clause + && (OMP_CLAUSE_SCHEDULE_KIND (schedule_clause) + & OMP_CLAUSE_SCHEDULE_NONMONOTONIC)) + { + error_at (OMP_CLAUSE_LOCATION (schedule_clause), + "% schedule modifier specified together " + "with % clause"); + OMP_CLAUSE_SCHEDULE_KIND (schedule_clause) + = (enum omp_clause_schedule_kind) + (OMP_CLAUSE_SCHEDULE_KIND (schedule_clause) + & ~OMP_CLAUSE_SCHEDULE_NONMONOTONIC); + } + + if (reduction_seen < 0 && ordered_clause) + { + error_at (OMP_CLAUSE_LOCATION (ordered_clause), + "%qs clause specified together with % " + "% clause", "ordered"); + reduction_seen = -2; + } + + if (reduction_seen < 0 && schedule_clause) + { + error_at (OMP_CLAUSE_LOCATION (schedule_clause), + "%qs clause specified together with % " + "% clause", "schedule"); + reduction_seen = -2; + } + + if (linear_variable_step_check + || reduction_seen == -2 + || allocate_seen + || target_in_reduction_seen) + for (pc = &clauses, c = clauses; c ; c = *pc) + { + bool remove = false; + if (allocate_seen) + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_IN_REDUCTION: + case OMP_CLAUSE_TASK_REDUCTION: + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) + { + t = TREE_OPERAND (OMP_CLAUSE_DECL (c), 0); + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == ADDR_EXPR + || TREE_CODE (t) == INDIRECT_REF) + t = TREE_OPERAND (t, 0); + if (DECL_P (t)) + bitmap_clear_bit (&aligned_head, DECL_UID (t)); + break; + } + /* FALLTHRU */ + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LASTPRIVATE: + case OMP_CLAUSE_LINEAR: + if (DECL_P (OMP_CLAUSE_DECL (c))) + bitmap_clear_bit (&aligned_head, + DECL_UID (OMP_CLAUSE_DECL (c))); + break; + default: + break; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c) + && !bitmap_bit_p (&map_head, + DECL_UID (OMP_CLAUSE_LINEAR_STEP (c)))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause step is a parameter %qD not " + "specified in % clause", + OMP_CLAUSE_LINEAR_STEP (c)); + remove = true; + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && reduction_seen == -2) + OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; + if (target_in_reduction_seen + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) + { + tree t = OMP_CLAUSE_DECL (c); + while (handled_component_p (t) + || TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ADDR_EXPR + || TREE_CODE (t) == MEM_REF + || TREE_CODE (t) == NON_LVALUE_EXPR) + t = TREE_OPERAND (t, 0); + if (DECL_P (t) + && bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) + OMP_CLAUSE_MAP_IN_REDUCTION (c) = 1; + } + + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + + if (allocate_seen) + for (pc = &clauses, c = clauses; c ; c = *pc) + { + bool remove = false; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ALLOCATE + && !OMP_CLAUSE_ALLOCATE_COMBINED (c) + && bitmap_bit_p (&aligned_head, DECL_UID (OMP_CLAUSE_DECL (c)))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified in % clause but not in " + "an explicit privatization clause", OMP_CLAUSE_DECL (c)); + remove = true; + } + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + + if (nogroup_seen && reduction_seen) + { + error_at (OMP_CLAUSE_LOCATION (*nogroup_seen), + "% clause must not be used together with " + "% clause"); + *nogroup_seen = OMP_CLAUSE_CHAIN (*nogroup_seen); + } + + if (detach_seen) + { + if (mergeable_seen) + { + error_at (OMP_CLAUSE_LOCATION (*detach_seen), + "% clause must not be used together with " + "% clause"); + *detach_seen = OMP_CLAUSE_CHAIN (*detach_seen); + } + else + { + tree detach_decl = OMP_CLAUSE_DECL (*detach_seen); + + for (pc = &clauses, c = clauses; c ; c = *pc) + { + bool remove = false; + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + && OMP_CLAUSE_DECL (c) == detach_decl) + { + error_at (OMP_CLAUSE_LOCATION (c), + "the event handle of a % clause " + "should not be in a data-sharing clause"); + remove = true; + } + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + } + } + + bitmap_obstack_release (NULL); + return clauses; +} + +/* Return code to initialize DST with a copy constructor from SRC. + C doesn't have copy constructors nor assignment operators, only for + _Atomic vars we need to perform __atomic_load from src into a temporary + followed by __atomic_store of the temporary to dst. */ + +tree +c_omp_clause_copy_ctor (tree clause, tree dst, tree src) +{ + if (!really_atomic_lvalue (dst) && !really_atomic_lvalue (src)) + return build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src); + + location_t loc = OMP_CLAUSE_LOCATION (clause); + tree type = TREE_TYPE (dst); + tree nonatomic_type = build_qualified_type (type, TYPE_UNQUALIFIED); + tree tmp = create_tmp_var (nonatomic_type); + tree tmp_addr = build_fold_addr_expr (tmp); + TREE_ADDRESSABLE (tmp) = 1; + suppress_warning (tmp); + tree src_addr = build_fold_addr_expr (src); + tree dst_addr = build_fold_addr_expr (dst); + tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); + vec *params; + /* Expansion of a generic atomic load may require an addition + element, so allocate enough to prevent a resize. */ + vec_alloc (params, 4); + + /* Build __atomic_load (&src, &tmp, SEQ_CST); */ + tree fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD); + params->quick_push (src_addr); + params->quick_push (tmp_addr); + params->quick_push (seq_cst); + tree load = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); + + vec_alloc (params, 4); + + /* Build __atomic_store (&dst, &tmp, SEQ_CST); */ + fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_STORE); + params->quick_push (dst_addr); + params->quick_push (tmp_addr); + params->quick_push (seq_cst); + tree store = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); + return build2 (COMPOUND_EXPR, void_type_node, load, store); +} + +/* Create a transaction node. */ + +tree +c_finish_transaction (location_t loc, tree block, int flags) +{ + tree stmt = build_stmt (loc, TRANSACTION_EXPR, block); + if (flags & TM_STMT_ATTR_OUTER) + TRANSACTION_EXPR_OUTER (stmt) = 1; + if (flags & TM_STMT_ATTR_RELAXED) + TRANSACTION_EXPR_RELAXED (stmt) = 1; + return add_stmt (stmt); +} + +/* Make a variant type in the proper way for C/C++, propagating qualifiers + down to the element type of an array. If ORIG_QUAL_TYPE is not + NULL, then it should be used as the qualified type + ORIG_QUAL_INDIRECT levels down in array type derivation (to + preserve information about the typedef name from which an array + type was derived). */ + +tree +c_build_qualified_type (tree type, int type_quals, tree orig_qual_type, + size_t orig_qual_indirect) +{ + if (type == error_mark_node) + return type; + + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree t; + tree element_type = c_build_qualified_type (TREE_TYPE (type), + type_quals, orig_qual_type, + orig_qual_indirect - 1); + + /* See if we already have an identically qualified type. */ + if (orig_qual_type && orig_qual_indirect == 0) + t = orig_qual_type; + else + for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) + { + if (TYPE_QUALS (strip_array_types (t)) == type_quals + && TYPE_NAME (t) == TYPE_NAME (type) + && TYPE_CONTEXT (t) == TYPE_CONTEXT (type) + && attribute_list_equal (TYPE_ATTRIBUTES (t), + TYPE_ATTRIBUTES (type))) + break; + } + if (!t) + { + tree domain = TYPE_DOMAIN (type); + + t = build_variant_type_copy (type); + TREE_TYPE (t) = element_type; + + if (TYPE_STRUCTURAL_EQUALITY_P (element_type) + || (domain && TYPE_STRUCTURAL_EQUALITY_P (domain))) + SET_TYPE_STRUCTURAL_EQUALITY (t); + else if (TYPE_CANONICAL (element_type) != element_type + || (domain && TYPE_CANONICAL (domain) != domain)) + { + tree unqualified_canon + = build_array_type (TYPE_CANONICAL (element_type), + domain? TYPE_CANONICAL (domain) + : NULL_TREE); + if (TYPE_REVERSE_STORAGE_ORDER (type)) + { + unqualified_canon + = build_distinct_type_copy (unqualified_canon); + TYPE_REVERSE_STORAGE_ORDER (unqualified_canon) = 1; + } + TYPE_CANONICAL (t) + = c_build_qualified_type (unqualified_canon, type_quals); + } + else + TYPE_CANONICAL (t) = t; + } + return t; + } + + /* A restrict-qualified pointer type must be a pointer to object or + incomplete type. Note that the use of POINTER_TYPE_P also allows + REFERENCE_TYPEs, which is appropriate for C++. */ + if ((type_quals & TYPE_QUAL_RESTRICT) + && (!POINTER_TYPE_P (type) + || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))) + { + error ("invalid use of %"); + type_quals &= ~TYPE_QUAL_RESTRICT; + } + + tree var_type = (orig_qual_type && orig_qual_indirect == 0 + ? orig_qual_type + : build_qualified_type (type, type_quals)); + /* A variant type does not inherit the list of incomplete vars from the + type main variant. */ + if ((RECORD_OR_UNION_TYPE_P (var_type) + || TREE_CODE (var_type) == ENUMERAL_TYPE) + && TYPE_MAIN_VARIANT (var_type) != var_type) + C_TYPE_INCOMPLETE_VARS (var_type) = 0; + return var_type; +} + +/* Build a VA_ARG_EXPR for the C parser. */ + +tree +c_build_va_arg (location_t loc1, tree expr, location_t loc2, tree type) +{ + if (error_operand_p (type)) + return error_mark_node; + /* VA_ARG_EXPR cannot be used for a scalar va_list with reverse storage + order because it takes the address of the expression. */ + else if (handled_component_p (expr) + && reverse_storage_order_for_component_p (expr)) + { + error_at (loc1, "cannot use % with reverse storage order"); + return error_mark_node; + } + else if (!COMPLETE_TYPE_P (type)) + { + error_at (loc2, "second argument to % is of incomplete " + "type %qT", type); + return error_mark_node; + } + else if (warn_cxx_compat && TREE_CODE (type) == ENUMERAL_TYPE) + warning_at (loc2, OPT_Wc___compat, + "C++ requires promoted type, not enum type, in %"); + return build_va_arg (loc2, expr, type); +} + +/* Return truthvalue of whether T1 is the same tree structure as T2. + Return 1 if they are the same. Return false if they are different. */ + +bool +c_tree_equal (tree t1, tree t2) +{ + enum tree_code code1, code2; + + if (t1 == t2) + return true; + if (!t1 || !t2) + return false; + + for (code1 = TREE_CODE (t1); + CONVERT_EXPR_CODE_P (code1) + || code1 == NON_LVALUE_EXPR; + code1 = TREE_CODE (t1)) + t1 = TREE_OPERAND (t1, 0); + for (code2 = TREE_CODE (t2); + CONVERT_EXPR_CODE_P (code2) + || code2 == NON_LVALUE_EXPR; + code2 = TREE_CODE (t2)) + t2 = TREE_OPERAND (t2, 0); + + /* They might have become equal now. */ + if (t1 == t2) + return true; + + if (code1 != code2) + return false; + + switch (code1) + { + case INTEGER_CST: + return wi::to_wide (t1) == wi::to_wide (t2); + + case REAL_CST: + return real_equal (&TREE_REAL_CST (t1), &TREE_REAL_CST (t2)); + + case STRING_CST: + return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2) + && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2), + TREE_STRING_LENGTH (t1)); + + case FIXED_CST: + return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), + TREE_FIXED_CST (t2)); + + case COMPLEX_CST: + return c_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2)) + && c_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2)); + + case VECTOR_CST: + return operand_equal_p (t1, t2, OEP_ONLY_CONST); + + case CONSTRUCTOR: + /* We need to do this when determining whether or not two + non-type pointer to member function template arguments + are the same. */ + if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2)) + || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2)) + return false; + { + tree field, value; + unsigned int i; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value) + { + constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i); + if (!c_tree_equal (field, elt2->index) + || !c_tree_equal (value, elt2->value)) + return false; + } + } + return true; + + case TREE_LIST: + if (!c_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))) + return false; + if (!c_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2))) + return false; + return c_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2)); + + case SAVE_EXPR: + return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); + + case CALL_EXPR: + { + tree arg1, arg2; + call_expr_arg_iterator iter1, iter2; + if (!c_tree_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2))) + return false; + for (arg1 = first_call_expr_arg (t1, &iter1), + arg2 = first_call_expr_arg (t2, &iter2); + arg1 && arg2; + arg1 = next_call_expr_arg (&iter1), + arg2 = next_call_expr_arg (&iter2)) + if (!c_tree_equal (arg1, arg2)) + return false; + if (arg1 || arg2) + return false; + return true; + } + + case TARGET_EXPR: + { + tree o1 = TREE_OPERAND (t1, 0); + tree o2 = TREE_OPERAND (t2, 0); + + /* Special case: if either target is an unallocated VAR_DECL, + it means that it's going to be unified with whatever the + TARGET_EXPR is really supposed to initialize, so treat it + as being equivalent to anything. */ + if (VAR_P (o1) && DECL_NAME (o1) == NULL_TREE + && !DECL_RTL_SET_P (o1)) + /*Nop*/; + else if (VAR_P (o2) && DECL_NAME (o2) == NULL_TREE + && !DECL_RTL_SET_P (o2)) + /*Nop*/; + else if (!c_tree_equal (o1, o2)) + return false; + + return c_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)); + } + + case COMPONENT_REF: + if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1)) + return false; + return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); + + case PARM_DECL: + case VAR_DECL: + case CONST_DECL: + case FIELD_DECL: + case FUNCTION_DECL: + case IDENTIFIER_NODE: + case SSA_NAME: + return false; + + case TREE_VEC: + { + unsigned ix; + if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2)) + return false; + for (ix = TREE_VEC_LENGTH (t1); ix--;) + if (!c_tree_equal (TREE_VEC_ELT (t1, ix), + TREE_VEC_ELT (t2, ix))) + return false; + return true; + } + + default: + break; + } + + switch (TREE_CODE_CLASS (code1)) + { + case tcc_unary: + case tcc_binary: + case tcc_comparison: + case tcc_expression: + case tcc_vl_exp: + case tcc_reference: + case tcc_statement: + { + int i, n = TREE_OPERAND_LENGTH (t1); + + switch (code1) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + n = 1; + break; + case ARRAY_REF: + n = 2; + break; + default: + break; + } + + if (TREE_CODE_CLASS (code1) == tcc_vl_exp + && n != TREE_OPERAND_LENGTH (t2)) + return false; + + for (i = 0; i < n; ++i) + if (!c_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i))) + return false; + + return true; + } + + case tcc_type: + return comptypes (t1, t2); + default: + gcc_unreachable (); + } +} + +/* Returns true when the function declaration FNDECL is implicit, + introduced as a result of a call to an otherwise undeclared + function, and false otherwise. */ + +bool +c_decl_implicit (const_tree fndecl) +{ + return C_DECL_IMPLICIT (fndecl); +} diff --git a/gcc/c/gccspec.c b/gcc/c/gccspec.c deleted file mode 100644 index d1165dd..0000000 --- a/gcc/c/gccspec.c +++ /dev/null @@ -1,107 +0,0 @@ -/* Specific flags and argument handling of the C front-end. - Copyright (C) 1999-2022 Free Software Foundation, Inc. - -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 -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "opts.h" - -/* Filter command line before processing by the gcc driver proper. */ -void -lang_specific_driver (struct cl_decoded_option **in_decoded_options ATTRIBUTE_UNUSED, - unsigned int *in_decoded_options_count ATTRIBUTE_UNUSED, - int *in_added_libraries ATTRIBUTE_UNUSED) -{ - /* Systems which use the NeXT runtime by default should arrange - for the shared libgcc to be used when -fgnu-runtime is passed - through specs. */ -#if defined(ENABLE_SHARED_LIBGCC) && ! NEXT_OBJC_RUNTIME - unsigned int i; - - /* The new argument list will be contained in this. */ - struct cl_decoded_option *new_decoded_options; - - /* True if we should add -shared-libgcc to the command-line. */ - int shared_libgcc = 0; - - /* The total number of arguments with the new stuff. */ - unsigned int argc; - - /* The argument list. */ - struct cl_decoded_option *decoded_options; - - argc = *in_decoded_options_count; - decoded_options = *in_decoded_options; - - for (i = 1; i < argc; i++) - { - switch (decoded_options[i].opt_index) - { - case OPT_static_libgcc: - case OPT_static: - return; - - case OPT_SPECIAL_input_file: - { - const char *file = decoded_options[i].arg; - int len; - - /* If the filename ends in .m or .mi, we are compiling - ObjC and want to pass -shared-libgcc. */ - len = strlen (file); - if ((len > 2 && file[len - 2] == '.' && file[len - 1] == 'm') - || (len > 3 && file[len - 3] == '.' && file[len - 2] == 'm' - && file[len - 1] == 'i')) - shared_libgcc = 1; - } - break; - } - } - - if (shared_libgcc) - { - new_decoded_options = XNEWVEC (struct cl_decoded_option, argc + 1); - - i = 0; - do - { - new_decoded_options[i] = decoded_options[i]; - i++; - } - while (i < argc); - - generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER, - &new_decoded_options[i++]); - - *in_decoded_options_count = i; - *in_decoded_options = new_decoded_options; - } -#endif -} - -/* Called before linking. Returns 0 on success and -1 on failure. */ -int -lang_specific_pre_link (void) -{ - return 0; /* Not used for C. */ -} - -/* Number of extra output files that lang_specific_pre_link may generate. */ -int lang_specific_extra_outfiles = 0; /* Not used for C. */ diff --git a/gcc/c/gccspec.cc b/gcc/c/gccspec.cc new file mode 100644 index 0000000..d1165dd --- /dev/null +++ b/gcc/c/gccspec.cc @@ -0,0 +1,107 @@ +/* Specific flags and argument handling of the C front-end. + Copyright (C) 1999-2022 Free Software Foundation, Inc. + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "opts.h" + +/* Filter command line before processing by the gcc driver proper. */ +void +lang_specific_driver (struct cl_decoded_option **in_decoded_options ATTRIBUTE_UNUSED, + unsigned int *in_decoded_options_count ATTRIBUTE_UNUSED, + int *in_added_libraries ATTRIBUTE_UNUSED) +{ + /* Systems which use the NeXT runtime by default should arrange + for the shared libgcc to be used when -fgnu-runtime is passed + through specs. */ +#if defined(ENABLE_SHARED_LIBGCC) && ! NEXT_OBJC_RUNTIME + unsigned int i; + + /* The new argument list will be contained in this. */ + struct cl_decoded_option *new_decoded_options; + + /* True if we should add -shared-libgcc to the command-line. */ + int shared_libgcc = 0; + + /* The total number of arguments with the new stuff. */ + unsigned int argc; + + /* The argument list. */ + struct cl_decoded_option *decoded_options; + + argc = *in_decoded_options_count; + decoded_options = *in_decoded_options; + + for (i = 1; i < argc; i++) + { + switch (decoded_options[i].opt_index) + { + case OPT_static_libgcc: + case OPT_static: + return; + + case OPT_SPECIAL_input_file: + { + const char *file = decoded_options[i].arg; + int len; + + /* If the filename ends in .m or .mi, we are compiling + ObjC and want to pass -shared-libgcc. */ + len = strlen (file); + if ((len > 2 && file[len - 2] == '.' && file[len - 1] == 'm') + || (len > 3 && file[len - 3] == '.' && file[len - 2] == 'm' + && file[len - 1] == 'i')) + shared_libgcc = 1; + } + break; + } + } + + if (shared_libgcc) + { + new_decoded_options = XNEWVEC (struct cl_decoded_option, argc + 1); + + i = 0; + do + { + new_decoded_options[i] = decoded_options[i]; + i++; + } + while (i < argc); + + generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER, + &new_decoded_options[i++]); + + *in_decoded_options_count = i; + *in_decoded_options = new_decoded_options; + } +#endif +} + +/* Called before linking. Returns 0 on success and -1 on failure. */ +int +lang_specific_pre_link (void) +{ + return 0; /* Not used for C. */ +} + +/* Number of extra output files that lang_specific_pre_link may generate. */ +int lang_specific_extra_outfiles = 0; /* Not used for C. */ diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c deleted file mode 100644 index 51ddd86..0000000 --- a/gcc/c/gimple-parser.c +++ /dev/null @@ -1,2453 +0,0 @@ -/* Parser for GIMPLE. - Copyright (C) 2016-2022 Free Software Foundation, Inc. - -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 -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "target.h" -#include "function.h" -#include "c-tree.h" -#include "timevar.h" -#include "stringpool.h" -#include "cgraph.h" -#include "attribs.h" -#include "stor-layout.h" -#include "varasm.h" -#include "trans-mem.h" -#include "c-family/c-pragma.h" -#include "c-lang.h" -#include "c-family/c-objc.h" -#include "plugin.h" -#include "builtins.h" -#include "gomp-constants.h" -#include "c-family/c-indentation.h" -#include "gimple-expr.h" -#include "context.h" -#include "gcc-rich-location.h" -#include "c-parser.h" -#include "tree-vrp.h" -#include "tree-pass.h" -#include "tree-pretty-print.h" -#include "tree.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-pretty-print.h" -#include "tree-ssa.h" -#include "pass_manager.h" -#include "tree-ssanames.h" -#include "gimple-ssa.h" -#include "tree-dfa.h" -#include "internal-fn.h" -#include "cfg.h" -#include "cfghooks.h" -#include "bitmap.h" -#include "cfganal.h" -#include "tree-cfg.h" -#include "gimple-iterator.h" -#include "cfgloop.h" -#include "tree-phinodes.h" -#include "tree-into-ssa.h" - - -/* GIMPLE parser state. */ - -class gimple_parser -{ -public: - gimple_parser (c_parser *p) : parser (p), edges(), current_bb(NULL) {} - /* c_parser is not visible here, use composition and fake inheritance - via a conversion operator. */ - operator c_parser *() { return parser; } - c_parser *parser; - - /* CFG build state. */ - class gimple_parser_edge - { - public: - int src; - int dest; - int flags; - profile_probability probability; - }; - auto_vec edges; - basic_block current_bb; - - void push_edge (int, int, int, profile_probability); -}; - -void -gimple_parser::push_edge (int src, int dest, int flags, - profile_probability prob) -{ - gimple_parser_edge e; - e.src = src; - e.dest = dest; - e.flags = flags; - e.probability = prob; - edges.safe_push (e); -} - - -/* Gimple parsing functions. */ -static bool c_parser_gimple_compound_statement (gimple_parser &, gimple_seq *); -static void c_parser_gimple_label (gimple_parser &, gimple_seq *); -static void c_parser_gimple_statement (gimple_parser &, gimple_seq *); -static struct c_expr c_parser_gimple_binary_expression (gimple_parser &); -static struct c_expr c_parser_gimple_unary_expression (gimple_parser &); -static struct c_expr c_parser_gimple_postfix_expression (gimple_parser &); -static struct c_expr c_parser_gimple_postfix_expression_after_primary - (gimple_parser &, location_t, struct c_expr); -static void c_parser_gimple_declaration (gimple_parser &); -static void c_parser_gimple_goto_stmt (gimple_parser &, location_t, - tree, gimple_seq *); -static void c_parser_gimple_try_stmt (gimple_parser &, gimple_seq *); -static void c_parser_gimple_if_stmt (gimple_parser &, gimple_seq *); -static void c_parser_gimple_switch_stmt (gimple_parser &, gimple_seq *); -static void c_parser_gimple_return_stmt (gimple_parser &, gimple_seq *); -static void c_finish_gimple_return (location_t, tree); -static tree c_parser_gimple_paren_condition (gimple_parser &); -static void c_parser_gimple_expr_list (gimple_parser &, vec *); - - -/* See if VAL is an identifier matching __BB and return - in *INDEX. */ - -static bool -c_parser_gimple_parse_bb_spec (tree val, int *index) -{ - if (!startswith (IDENTIFIER_POINTER (val), "__BB")) - return false; - for (const char *p = IDENTIFIER_POINTER (val) + 4; *p; ++p) - if (!ISDIGIT (*p)) - return false; - *index = atoi (IDENTIFIER_POINTER (val) + 4); - return *index > 0; -} - -/* See if VAL is an identifier matching __BB and return - in *INDEX. Return true if so and parse also FREQUENCY of - the edge. */ - - -static bool -c_parser_gimple_parse_bb_spec_edge_probability (tree val, - gimple_parser &parser, - int *index, - profile_probability - *probability) -{ - bool return_p = c_parser_gimple_parse_bb_spec (val, index); - if (return_p) - { - *probability = profile_probability::uninitialized (); - /* Parse frequency if provided. */ - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - tree f; - c_parser_consume_token (parser); - if (!c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected frequency quality"); - return false; - } - - profile_quality quality; - const char *v - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (!parse_profile_quality (v, &quality)) - { - c_parser_error (parser, "unknown profile quality"); - return false; - } - - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return false; - - if (!c_parser_next_token_is (parser, CPP_NUMBER) - || (TREE_CODE (f = c_parser_peek_token (parser)->value) - != INTEGER_CST)) - { - c_parser_error (parser, "expected frequency value"); - return false; - } - - unsigned int value = TREE_INT_CST_LOW (f); - *probability = profile_probability (value, quality); - - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - return false; - - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - return false; - } - - return true; - } - - return false; - -} - -/* Parse the body of a function declaration marked with "__GIMPLE". */ - -void -c_parser_parse_gimple_body (c_parser *cparser, char *gimple_pass, - enum c_declspec_il cdil, - profile_count entry_bb_count) -{ - gimple_parser parser (cparser); - gimple_seq seq = NULL; - gimple_seq body = NULL; - tree stmt = push_stmt_list (); - push_scope (); - location_t loc1 = c_parser_peek_token (parser)->location; - - cfun->pass_startwith = gimple_pass; - init_tree_ssa (cfun); - - if (cdil == cdil_gimple) - /* While we have SSA names in the IL we do not have a CFG built yet - and PHIs are represented using a PHI internal function. We do - have lowered control flow and exception handling (well, we do not - have parser support for EH yet). But as we still have BINDs - we have to go through lowering again. */ - cfun->curr_properties = PROP_gimple_any; - else - { - /* We have at least cdil_gimple_cfg. */ - gimple_register_cfg_hooks (); - init_empty_tree_cfg (); - parser.current_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun); - /* Initialize the bare loop structure - we are going to only - mark headers and leave the rest to fixup. */ - set_loops_for_fn (cfun, ggc_cleared_alloc ()); - init_loops_structure (cfun, loops_for_fn (cfun), 1); - loops_state_set (cfun, LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES); - cfun->curr_properties - |= PROP_gimple_lcf | PROP_gimple_leh | PROP_cfg | PROP_loops; - if (cdil == cdil_gimple_ssa) - { - init_ssa_operands (cfun); - cfun->curr_properties |= PROP_ssa; - } - } - - if (! c_parser_gimple_compound_statement (parser, &seq) - && cdil == cdil_gimple) - { - gimple *ret = gimple_build_return (NULL); - gimple_seq_add_stmt_without_update (&seq, ret); - } - - tree block = pop_scope (); - stmt = pop_stmt_list (stmt); - stmt = c_build_bind_expr (loc1, block, stmt); - - block = DECL_INITIAL (current_function_decl); - BLOCK_SUBBLOCKS (block) = NULL_TREE; - BLOCK_CHAIN (block) = NULL_TREE; - TREE_ASM_WRITTEN (block) = 1; - - if (cdil == cdil_gimple) - { - gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL, - BIND_EXPR_BLOCK (stmt)); - gimple_bind_set_body (bind_stmt, seq); - gimple_seq_add_stmt_without_update (&body, bind_stmt); - gimple_set_body (current_function_decl, body); - } - else - { - /* Control-flow and binds are lowered, record local decls. */ - for (tree var = BIND_EXPR_VARS (stmt); var; var = DECL_CHAIN (var)) - if (VAR_P (var) - && !DECL_EXTERNAL (var)) - add_local_decl (cfun, var); - /* We have a CFG. Build the edges. */ - for (unsigned i = 0; i < parser.edges.length (); ++i) - { - edge e = make_edge (BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].src), - BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].dest), - parser.edges[i].flags); - e->probability = parser.edges[i].probability; - } - /* Add edges for case labels. */ - basic_block bb; - FOR_EACH_BB_FN (bb, cfun) - if (EDGE_COUNT (bb->succs) == 0) - { - gimple *last = last_stmt (bb); - if (gswitch *sw = safe_dyn_cast (last)) - for (unsigned i = 0; i < gimple_switch_num_labels (sw); ++i) - { - basic_block label_bb = gimple_switch_label_bb (cfun, sw, i); - make_edge (bb, label_bb, 0); - } - } - /* Need those for loop fixup. */ - calculate_dominance_info (CDI_DOMINATORS); - /* With SSA lower PHIs parsed as internal function calls and - update stmts. */ - if (cdil == cdil_gimple_ssa) - { - /* Create PHI nodes, they are parsed into __PHI internal calls. */ - FOR_EACH_BB_FN (bb, cfun) - for (gimple_stmt_iterator gsi = gsi_start_bb (bb); - !gsi_end_p (gsi);) - { - gimple *stmt = gsi_stmt (gsi); - if (!gimple_call_internal_p (stmt, IFN_PHI)) - break; - - gphi *phi = create_phi_node (gimple_call_lhs (stmt), bb); - for (unsigned i = 0; i < gimple_call_num_args (stmt); i += 2) - { - int srcidx = TREE_INT_CST_LOW (gimple_call_arg (stmt, i)); - edge e = find_edge (BASIC_BLOCK_FOR_FN (cfun, srcidx), bb); - if (!e) - c_parser_error (parser, "edge not found"); - else - add_phi_arg (phi, gimple_call_arg (stmt, i + 1), e, - UNKNOWN_LOCATION); - } - gsi_remove (&gsi, true); - } - /* Fill SSA name gaps, putting them on the freelist. */ - for (unsigned i = 1; i < num_ssa_names; ++i) - if (!ssa_name (i)) - { - tree name = make_ssa_name_fn (cfun, integer_type_node, NULL, i); - release_ssa_name_fn (cfun, name); - } - /* No explicit virtual operands (yet). */ - bitmap_obstack_initialize (NULL); - update_ssa (TODO_update_ssa_only_virtuals); - bitmap_obstack_release (NULL); - /* ??? By flushing the freelist after virtual operand SSA rewrite - we keep the gaps available for re-use like needed for the - PR89595 testcase but then usually virtual operands would have - taken most of them. The fix is obviously to make virtual - operands explicit in the SSA IL. */ - flush_ssaname_freelist (); - } - fix_loop_structure (NULL); - } - - if (cfun->curr_properties & PROP_cfg) - { - ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = entry_bb_count; - gcov_type t = param_gimple_fe_computed_hot_bb_threshold; - set_hot_bb_threshold (t); - update_max_bb_count (); - cgraph_node::get_create (cfun->decl); - cgraph_edge::rebuild_edges (); - } - dump_function (TDI_gimple, current_function_decl); -} - -/* Parse a compound statement in gimple function body. - - gimple-statement: - gimple-statement - gimple-declaration-statement - gimple-if-statement - gimple-switch-statement - gimple-labeled-statement - gimple-expression-statement - gimple-goto-statement - gimple-phi-statement - gimple-return-statement -*/ - -static bool -c_parser_gimple_compound_statement (gimple_parser &parser, gimple_seq *seq) -{ - bool return_p = false; - - if (! c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) - return false; - - /* A compund statement starts with optional declarations. */ - while (c_parser_next_tokens_start_declaration (parser)) - { - c_parser_gimple_declaration (parser); - if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) - return false; - } - - while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) - { - if (c_parser_error (parser)) - { - c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); - return return_p; - } - else if (c_parser_next_token_is (parser, CPP_EOF)) - { - c_parser_error (parser, "expected declaration or statement"); - return return_p; - } - - switch (c_parser_peek_token (parser)->type) - { - case CPP_KEYWORD: - switch (c_parser_peek_token (parser)->keyword) - { - case RID_AT_TRY: - c_parser_gimple_try_stmt (parser, seq); - break; - case RID_IF: - c_parser_gimple_if_stmt (parser, seq); - break; - case RID_SWITCH: - c_parser_gimple_switch_stmt (parser, seq); - break; - case RID_GOTO: - { - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - tree label = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - c_parser_gimple_goto_stmt (parser, loc, label, seq); - if (! c_parser_require (parser, CPP_SEMICOLON, - "expected %<;%>")) - return return_p; - } - } - break; - case RID_RETURN: - return_p = true; - c_parser_gimple_return_stmt (parser, seq); - if (! c_parser_require (parser, CPP_SEMICOLON, - "expected %<;%>")) - return return_p; - if (cfun->curr_properties & PROP_cfg) - parser.push_edge (parser.current_bb->index, EXIT_BLOCK, 0, - profile_probability::uninitialized ()); - break; - default: - goto expr_stmt; - } - break; - case CPP_NAME: - if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) - { - c_parser_gimple_label (parser, seq); - break; - } - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_ID - && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), - "try") == 0) - { - c_parser_gimple_try_stmt (parser, seq); - break; - } - /* Basic block specification. - __BB (index, ...) */ - if ((cfun->curr_properties & PROP_cfg) - && !strcmp (IDENTIFIER_POINTER - (c_parser_peek_token (parser)->value), "__BB")) - { - c_parser_consume_token (parser); - if (! c_parser_require (parser, CPP_OPEN_PAREN, - "expected %<(%>")) - return return_p; - if (c_parser_next_token_is_not (parser, CPP_NUMBER)) - { - c_parser_error (parser, "expected block index"); - return return_p; - } - tree tnum = c_parser_peek_token (parser)->value; - if (TREE_CODE (tnum) != INTEGER_CST) - { - c_parser_error (parser, "expected block index"); - return return_p; - } - int index = TREE_INT_CST_LOW (tnum); - if (index < NUM_FIXED_BLOCKS - || (index < last_basic_block_for_fn (cfun) - && BASIC_BLOCK_FOR_FN (cfun, index) != NULL)) - { - c_parser_error (parser, "invalid block index"); - return return_p; - } - int is_loop_header_of = -1; - profile_count bb_count = profile_count::uninitialized (); - c_parser_consume_token (parser); - while (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - if (! c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected block specifier"); - return return_p; - } - /* loop_header (NUM) */ - if (!strcmp (IDENTIFIER_POINTER - (c_parser_peek_token (parser)->value), - "loop_header")) - { - c_parser_consume_token (parser); - if (! c_parser_require (parser, CPP_OPEN_PAREN, - "expected %<(%>")) - return return_p; - tree loop_num; - if (! c_parser_next_token_is (parser, CPP_NUMBER) - || TREE_CODE (loop_num - = c_parser_peek_token (parser)->value) - != INTEGER_CST) - { - c_parser_error (parser, "expected loop number"); - return return_p; - } - c_parser_consume_token (parser); - is_loop_header_of = TREE_INT_CST_LOW (loop_num); - if (! c_parser_require (parser, CPP_CLOSE_PAREN, - "expected %<)%>")) - return return_p; - } - /* Parse profile: quality(value) */ - else - { - tree q; - profile_quality quality; - tree v = c_parser_peek_token (parser)->value; - if (!parse_profile_quality (IDENTIFIER_POINTER (v), - &quality)) - { - c_parser_error (parser, "unknown block specifier"); - return false; - } - - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, - "expected %<(%>")) - return false; - - if (!c_parser_next_token_is (parser, CPP_NUMBER) - || (TREE_CODE (q = c_parser_peek_token (parser)->value) - != INTEGER_CST)) - { - c_parser_error (parser, "expected count value"); - return false; - } - - bb_count - = profile_count::from_gcov_type (TREE_INT_CST_LOW (q), - quality); - c_parser_consume_token (parser); - if (! c_parser_require (parser, CPP_CLOSE_PAREN, - "expected %<)%>")) - return return_p; - } - } - if (! c_parser_require (parser, CPP_CLOSE_PAREN, - "expected %<)%>") - || ! c_parser_require (parser, CPP_COLON, - "expected %<:%>")) - return return_p; - - /* Put stmts parsed in the current block. */ - if (!gimple_seq_empty_p (*seq)) - { - if (!parser.current_bb) - c_parser_error (parser, "stmts without block"); - else - { - gimple_stmt_iterator gsi - = gsi_start_bb (parser.current_bb); - gsi_insert_seq_after (&gsi, *seq, GSI_CONTINUE_LINKING); - } - *seq = NULL; - } - - /* Build an empty block with specified index, linking them - in source order. */ - basic_block bb = alloc_block (); - bb->index = index; - link_block (bb, (parser.current_bb ? parser.current_bb - : ENTRY_BLOCK_PTR_FOR_FN (cfun))); - if (basic_block_info_for_fn (cfun)->length () <= (size_t)index) - vec_safe_grow_cleared (basic_block_info_for_fn (cfun), - index + 1, true); - SET_BASIC_BLOCK_FOR_FN (cfun, index, bb); - if (last_basic_block_for_fn (cfun) <= index) - last_basic_block_for_fn (cfun) = index + 1; - n_basic_blocks_for_fn (cfun)++; - if (parser.current_bb->index == ENTRY_BLOCK) - parser.push_edge (ENTRY_BLOCK, bb->index, EDGE_FALLTHRU, - profile_probability::always ()); - - /* We leave the proper setting to fixup. */ - class loop *loop_father = loops_for_fn (cfun)->tree_root; - /* If the new block is a loop header, allocate a loop - struct. Fixup will take care of proper placement within - the loop tree. */ - if (is_loop_header_of != -1) - { - if (number_of_loops (cfun) > (unsigned)is_loop_header_of - && get_loop (cfun, is_loop_header_of) != NULL) - { - c_parser_error (parser, "duplicate loop header"); - } - else - { - class loop *loop = alloc_loop (); - loop->num = is_loop_header_of; - loop->header = bb; - if (number_of_loops (cfun) <= (unsigned)is_loop_header_of) - vec_safe_grow_cleared (loops_for_fn (cfun)->larray, - is_loop_header_of + 1, true); - (*loops_for_fn (cfun)->larray)[is_loop_header_of] = loop; - flow_loop_tree_node_add (loops_for_fn (cfun)->tree_root, - loop); - } - loop_father = get_loop (cfun, is_loop_header_of); - } - bb->loop_father = loop_father; - bb->count = bb_count; - - /* Stmts now go to the new block. */ - parser.current_bb = bb; - break; - } - goto expr_stmt; - - case CPP_SEMICOLON: - { - /* Empty stmt. */ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - gimple *nop = gimple_build_nop (); - gimple_set_location (nop, loc); - gimple_seq_add_stmt_without_update (seq, nop); - break; - } - - default: -expr_stmt: - c_parser_gimple_statement (parser, seq); - if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - } - } - c_parser_consume_token (parser); - - /* Put stmts parsed in the current block. */ - if ((cfun->curr_properties & PROP_cfg) - && !gimple_seq_empty_p (*seq)) - { - if (!parser.current_bb) - c_parser_error (parser, "stmts without block"); - else - { - gimple_stmt_iterator gsi = gsi_start_bb (parser.current_bb); - gsi_insert_seq_after (&gsi, *seq, GSI_CONTINUE_LINKING); - } - *seq = NULL; - } - - return return_p; -} - -/* Parse a gimple statement. - - gimple-statement: - gimple-call-expression - gimple-assign-statement - gimple-phi-statement - - gimple-assign-statement: - gimple-unary-expression = gimple-assign-rhs - - gimple-assign-rhs: - gimple-cast-expression - gimple-unary-expression - gimple-binary-expression - gimple-call-expression - - gimple-phi-statement: - identifier = __PHI ( label : gimple_primary-expression, ... ) - - gimple-call-expr: - gimple-primary-expression ( argument-list ) - - gimple-cast-expression: - ( type-name ) gimple-primary-expression - -*/ - -static void -c_parser_gimple_statement (gimple_parser &parser, gimple_seq *seq) -{ - struct c_expr lhs, rhs; - gimple *assign = NULL; - location_t loc; - tree arg = NULL_TREE; - auto_vec vargs; - - lhs = c_parser_gimple_unary_expression (parser); - loc = EXPR_LOCATION (lhs.value); - rhs.set_error (); - - /* GIMPLE call statement without LHS. */ - if (c_parser_next_token_is (parser, CPP_SEMICOLON) - && TREE_CODE (lhs.value) == CALL_EXPR) - { - gimple *call; - call = gimple_build_call_from_tree (lhs.value, NULL); - gimple_seq_add_stmt_without_update (seq, call); - gimple_set_location (call, loc); - return; - } - - /* All following cases are statements with LHS. */ - if (! c_parser_require (parser, CPP_EQ, "expected %<=%>")) - return; - - /* Cast expression. */ - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) - && c_token_starts_typename (c_parser_peek_2nd_token (parser))) - { - c_parser_consume_token (parser); - struct c_type_name *type_name = c_parser_type_name (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - if (type_name == NULL) - return; - /* ??? The actual type used in the cast expression is ignored as - in GIMPLE it is encoded by the type of the LHS. */ - rhs = c_parser_gimple_postfix_expression (parser); - if (lhs.value != error_mark_node - && rhs.value != error_mark_node) - { - enum tree_code code = NOP_EXPR; - if (FLOAT_TYPE_P (TREE_TYPE (lhs.value)) - && ! FLOAT_TYPE_P (TREE_TYPE (rhs.value))) - code = FLOAT_EXPR; - else if (! FLOAT_TYPE_P (TREE_TYPE (lhs.value)) - && FLOAT_TYPE_P (TREE_TYPE (rhs.value))) - code = FIX_TRUNC_EXPR; - assign = gimple_build_assign (lhs.value, code, rhs.value); - gimple_seq_add_stmt_without_update (seq, assign); - gimple_set_location (assign, loc); - return; - } - } - - /* Unary expression. */ - switch (c_parser_peek_token (parser)->type) - { - case CPP_NAME: - { - tree id = c_parser_peek_token (parser)->value; - if (strcmp (IDENTIFIER_POINTER (id), "__ABS") == 0 - || strcmp (IDENTIFIER_POINTER (id), "__ABSU") == 0 - || strcmp (IDENTIFIER_POINTER (id), "__MIN") == 0 - || strcmp (IDENTIFIER_POINTER (id), "__MAX") == 0 - || strcmp (IDENTIFIER_POINTER (id), "__BIT_INSERT") == 0 - || strcmp (IDENTIFIER_POINTER (id), "__VEC_PERM") == 0) - goto build_unary_expr; - break; - } - case CPP_KEYWORD: - if (c_parser_peek_token (parser)->keyword != RID_REALPART - && c_parser_peek_token (parser)->keyword != RID_IMAGPART) - break; - /* Fallthru. */ - case CPP_AND: - case CPP_PLUS: - case CPP_MINUS: - case CPP_COMPL: - case CPP_NOT: - case CPP_MULT: /* pointer deref */ - build_unary_expr: - rhs = c_parser_gimple_unary_expression (parser); - if (rhs.value != error_mark_node) - { - assign = gimple_build_assign (lhs.value, rhs.value); - gimple_set_location (assign, loc); - gimple_seq_add_stmt_without_update (seq, assign); - } - return; - - default:; - } - - /* GIMPLE PHI statement. */ - if (c_parser_next_token_is_keyword (parser, RID_PHI)) - { - c_parser_consume_token (parser); - - if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return; - - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - c_parser_consume_token (parser); - - while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) - { - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) - { - arg = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COLON)) - c_parser_consume_token (parser); - int src_index = -1; - if (!c_parser_gimple_parse_bb_spec (arg, &src_index)) - c_parser_error (parser, "invalid source block specification"); - vargs.safe_push (size_int (src_index)); - } - else if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - { - arg = c_parser_gimple_unary_expression (parser).value; - vargs.safe_push (arg); - } - } - - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - - /* Build internal function for PHI. */ - gcall *call_stmt = gimple_build_call_internal_vec (IFN_PHI, vargs); - gimple_call_set_lhs (call_stmt, lhs.value); - gimple_set_location (call_stmt, UNKNOWN_LOCATION); - gimple_seq_add_stmt_without_update (seq, call_stmt); - return; - } - - /* GIMPLE call with lhs. */ - if (c_parser_next_token_is (parser, CPP_DOT) - || (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN - && lookup_name (c_parser_peek_token (parser)->value))) - { - rhs = c_parser_gimple_unary_expression (parser); - if (rhs.value != error_mark_node) - { - gimple *call = gimple_build_call_from_tree (rhs.value, NULL); - gimple_call_set_lhs (call, lhs.value); - gimple_seq_add_stmt_without_update (seq, call); - gimple_set_location (call, loc); - } - return; - } - - rhs = c_parser_gimple_binary_expression (parser); - if (lhs.value != error_mark_node - && rhs.value != error_mark_node) - { - /* If we parsed a comparison and the next token is a '?' then - parse a conditional expression. */ - if (COMPARISON_CLASS_P (rhs.value) - && c_parser_next_token_is (parser, CPP_QUERY)) - { - struct c_expr trueval, falseval; - c_parser_consume_token (parser); - trueval = c_parser_gimple_postfix_expression (parser); - falseval.set_error (); - if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) - falseval = c_parser_gimple_postfix_expression (parser); - if (trueval.value == error_mark_node - || falseval.value == error_mark_node) - return; - rhs.value = build3_loc (loc, COND_EXPR, TREE_TYPE (trueval.value), - rhs.value, trueval.value, falseval.value); - } - if (get_gimple_rhs_class (TREE_CODE (rhs.value)) == GIMPLE_INVALID_RHS) - { - c_parser_error (parser, "unexpected RHS for assignment"); - return; - } - assign = gimple_build_assign (lhs.value, rhs.value); - gimple_seq_add_stmt_without_update (seq, assign); - gimple_set_location (assign, loc); - } - return; -} - -/* Parse gimple binary expr. - - gimple-binary-expression: - gimple-unary-expression * gimple-unary-expression - gimple-unary-expression __MULT_HIGHPART gimple-unary-expression - gimple-unary-expression / gimple-unary-expression - gimple-unary-expression % gimple-unary-expression - gimple-unary-expression + gimple-unary-expression - gimple-unary-expression - gimple-unary-expression - gimple-unary-expression << gimple-unary-expression - gimple-unary-expression >> gimple-unary-expression - gimple-unary-expression < gimple-unary-expression - gimple-unary-expression > gimple-unary-expression - gimple-unary-expression <= gimple-unary-expression - gimple-unary-expression >= gimple-unary-expression - gimple-unary-expression == gimple-unary-expression - gimple-unary-expression != gimple-unary-expression - gimple-unary-expression & gimple-unary-expression - gimple-unary-expression ^ gimple-unary-expression - gimple-unary-expression | gimple-unary-expression - -*/ - -static c_expr -c_parser_gimple_binary_expression (gimple_parser &parser) -{ - /* Location of the binary operator. */ - struct c_expr ret, lhs, rhs; - enum tree_code code = ERROR_MARK; - ret.set_error (); - lhs = c_parser_gimple_postfix_expression (parser); - if (c_parser_error (parser)) - return ret; - tree ret_type = TREE_TYPE (lhs.value); - switch (c_parser_peek_token (parser)->type) - { - case CPP_MULT: - code = MULT_EXPR; - break; - case CPP_DIV: - code = TRUNC_DIV_EXPR; - break; - case CPP_MOD: - code = TRUNC_MOD_EXPR; - break; - case CPP_PLUS: - if (POINTER_TYPE_P (TREE_TYPE (lhs.value))) - code = POINTER_PLUS_EXPR; - else - code = PLUS_EXPR; - break; - case CPP_MINUS: - code = MINUS_EXPR; - break; - case CPP_LSHIFT: - code = LSHIFT_EXPR; - break; - case CPP_RSHIFT: - code = RSHIFT_EXPR; - break; - case CPP_LESS: - code = LT_EXPR; - ret_type = boolean_type_node; - break; - case CPP_GREATER: - code = GT_EXPR; - ret_type = boolean_type_node; - break; - case CPP_LESS_EQ: - code = LE_EXPR; - ret_type = boolean_type_node; - break; - case CPP_GREATER_EQ: - code = GE_EXPR; - ret_type = boolean_type_node; - break; - case CPP_EQ_EQ: - code = EQ_EXPR; - ret_type = boolean_type_node; - break; - case CPP_NOT_EQ: - code = NE_EXPR; - ret_type = boolean_type_node; - break; - case CPP_AND: - code = BIT_AND_EXPR; - break; - case CPP_XOR: - code = BIT_XOR_EXPR; - break; - case CPP_OR: - code = BIT_IOR_EXPR; - break; - case CPP_AND_AND: - c_parser_error (parser, "%<&&%> not valid in GIMPLE"); - return ret; - case CPP_OR_OR: - c_parser_error (parser, "%<||%> not valid in GIMPLE"); - return ret; - case CPP_NAME: - { - tree id = c_parser_peek_token (parser)->value; - if (strcmp (IDENTIFIER_POINTER (id), "__MULT_HIGHPART") == 0) - { - code = MULT_HIGHPART_EXPR; - break; - } - } - /* Fallthru. */ - default: - /* Not a binary expression. */ - return lhs; - } - location_t ret_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - rhs = c_parser_gimple_postfix_expression (parser); - if (lhs.value != error_mark_node && rhs.value != error_mark_node) - ret.value = build2_loc (ret_loc, code, ret_type, lhs.value, rhs.value); - return ret; -} - -/* Parse a gimple parentized binary expression. */ - -static c_expr -c_parser_gimple_parentized_binary_expression (gimple_parser &parser, - location_t op_loc, - tree_code code) -{ - struct c_expr ret; - ret.set_error (); - - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return ret; - c_expr op1 = c_parser_gimple_postfix_expression (parser); - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - return ret; - c_expr op2 = c_parser_gimple_postfix_expression (parser); - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - return ret; - - if (op1.value != error_mark_node && op2.value != error_mark_node) - ret.value = build2_loc (op_loc, - code, TREE_TYPE (op1.value), op1.value, op2.value); - return ret; -} - -/* Parse a gimple parentized binary expression. */ - -static c_expr -c_parser_gimple_parentized_ternary_expression (gimple_parser &parser, - location_t op_loc, - tree_code code) -{ - struct c_expr ret; - ret.set_error (); - - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return ret; - c_expr op1 = c_parser_gimple_postfix_expression (parser); - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - return ret; - c_expr op2 = c_parser_gimple_postfix_expression (parser); - if (!c_parser_require (parser, CPP_COMMA, "expected %<)%>")) - return ret; - c_expr op3 = c_parser_gimple_postfix_expression (parser); - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - return ret; - - if (op1.value != error_mark_node - && op2.value != error_mark_node - && op3.value != error_mark_node) - ret.value = build3_loc (op_loc, - code, TREE_TYPE (op1.value), - op1.value, op2.value, op3.value); - return ret; -} - -/* Parse gimple unary expression. - - gimple-unary-expression: - gimple-postfix-expression - unary-operator gimple-postfix-expression - - unary-operator: one of - & * + - ~ abs_expr -*/ - -static c_expr -c_parser_gimple_unary_expression (gimple_parser &parser) -{ - struct c_expr ret, op; - location_t op_loc = c_parser_peek_token (parser)->location; - location_t finish; - ret.set_error (); - switch (c_parser_peek_token (parser)->type) - { - case CPP_AND: - c_parser_consume_token (parser); - op = c_parser_gimple_postfix_expression (parser); - mark_exp_read (op.value); - return parser_build_unary_op (op_loc, ADDR_EXPR, op); - case CPP_MULT: - { - c_parser_consume_token (parser); - op = c_parser_gimple_postfix_expression (parser); - if (op.value == error_mark_node) - return ret; - if (! POINTER_TYPE_P (TREE_TYPE (op.value))) - { - error_at (op_loc, "expected pointer as argument of unary %<*%>"); - return ret; - } - finish = op.get_finish (); - location_t combined_loc = make_location (op_loc, op_loc, finish); - ret.value = build_simple_mem_ref_loc (combined_loc, op.value); - TREE_SIDE_EFFECTS (ret.value) - = TREE_THIS_VOLATILE (ret.value) - = TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op.value))); - ret.src_range.m_start = op_loc; - ret.src_range.m_finish = finish; - return ret; - } - case CPP_PLUS: - c_parser_consume_token (parser); - op = c_parser_gimple_postfix_expression (parser); - return parser_build_unary_op (op_loc, CONVERT_EXPR, op); - case CPP_MINUS: - c_parser_consume_token (parser); - op = c_parser_gimple_postfix_expression (parser); - return parser_build_unary_op (op_loc, NEGATE_EXPR, op); - case CPP_COMPL: - c_parser_consume_token (parser); - op = c_parser_gimple_postfix_expression (parser); - return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); - case CPP_NOT: - c_parser_error (parser, "% not valid in GIMPLE"); - return ret; - case CPP_KEYWORD: - switch (c_parser_peek_token (parser)->keyword) - { - case RID_REALPART: - c_parser_consume_token (parser); - op = c_parser_gimple_postfix_expression (parser); - return parser_build_unary_op (op_loc, REALPART_EXPR, op); - case RID_IMAGPART: - c_parser_consume_token (parser); - op = c_parser_gimple_postfix_expression (parser); - return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); - default: - return c_parser_gimple_postfix_expression (parser); - } - case CPP_NAME: - { - tree id = c_parser_peek_token (parser)->value; - if (strcmp (IDENTIFIER_POINTER (id), "__ABS") == 0) - { - c_parser_consume_token (parser); - op = c_parser_gimple_postfix_expression (parser); - return parser_build_unary_op (op_loc, ABS_EXPR, op); - } - else if (strcmp (IDENTIFIER_POINTER (id), "__ABSU") == 0) - { - c_parser_consume_token (parser); - op = c_parser_gimple_postfix_expression (parser); - return parser_build_unary_op (op_loc, ABSU_EXPR, op); - } - else if (strcmp (IDENTIFIER_POINTER (id), "__MIN") == 0) - return c_parser_gimple_parentized_binary_expression (parser, - op_loc, - MIN_EXPR); - else if (strcmp (IDENTIFIER_POINTER (id), "__MAX") == 0) - return c_parser_gimple_parentized_binary_expression (parser, - op_loc, - MAX_EXPR); - else if (strcmp (IDENTIFIER_POINTER (id), "__VEC_PERM") == 0) - return c_parser_gimple_parentized_ternary_expression - (parser, op_loc, VEC_PERM_EXPR); - else if (strcmp (IDENTIFIER_POINTER (id), "__BIT_INSERT") == 0) - { - /* __BIT_INSERT '(' postfix-expression, postfix-expression, - integer ')' */ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - c_expr op0 = c_parser_gimple_postfix_expression (parser); - c_parser_skip_until_found (parser, CPP_COMMA, - "expected %<,%>"); - c_expr op1 = c_parser_gimple_postfix_expression (parser); - c_parser_skip_until_found (parser, CPP_COMMA, - "expected %<,%>"); - c_expr op2 = c_parser_gimple_postfix_expression (parser); - if (TREE_CODE (op2.value) != INTEGER_CST - || !int_fits_type_p (op2.value, bitsizetype)) - c_parser_error (parser, "expected constant offset"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - if (op0.value != error_mark_node - && op1.value != error_mark_node - && TREE_CODE (op2.value) == INTEGER_CST) - ret.value = build3_loc (loc, BIT_INSERT_EXPR, - TREE_TYPE (op0.value), - op0.value, op1.value, - fold_convert (bitsizetype, - op2.value)); - } - return ret; - } - else - return c_parser_gimple_postfix_expression (parser); - } - default: - return c_parser_gimple_postfix_expression (parser); - } -} - -/* Decompose ID into base name (ID until ver_offset) and VERSION. Return - true if ID matches a SSA name. */ - -static bool -c_parser_parse_ssa_name_id (tree id, unsigned *version, unsigned *ver_offset) -{ - const char *token = IDENTIFIER_POINTER (id); - const char *var_version = strrchr (token, '_'); - if (! var_version) - return false; - - *ver_offset = var_version - token; - for (const char *p = var_version + 1; *p; ++p) - if (! ISDIGIT (*p)) - return false; - *version = atoi (var_version + 1); - return *version > 0; -} - -/* Get at the actual SSA name ID with VERSION starting at VER_OFFSET. - TYPE is the type if the SSA name is being declared. */ - -static tree -c_parser_parse_ssa_name (gimple_parser &parser, - tree id, tree type, unsigned version, - unsigned ver_offset) -{ - tree name = NULL_TREE; - const char *token = IDENTIFIER_POINTER (id); - - if (ver_offset == 0) - { - /* Anonymous unnamed SSA name. */ - if (version < num_ssa_names) - name = ssa_name (version); - if (! name) - { - if (! type) - { - c_parser_error (parser, "SSA name undeclared"); - return error_mark_node; - } - name = make_ssa_name_fn (cfun, type, NULL, version); - } - } - else - { - if (version < num_ssa_names) - name = ssa_name (version); - if (! name) - { - /* Separate var name from version. */ - char *var_name = XNEWVEC (char, ver_offset + 1); - memcpy (var_name, token, ver_offset); - var_name[ver_offset] = '\0'; - /* lookup for parent decl. */ - id = get_identifier (var_name); - tree parent = lookup_name (id); - XDELETEVEC (var_name); - if (! parent || parent == error_mark_node) - { - c_parser_error (parser, "base variable or SSA name undeclared"); - return error_mark_node; - } - if (!(VAR_P (parent) - || TREE_CODE (parent) == PARM_DECL - || TREE_CODE (parent) == RESULT_DECL)) - { - error ("invalid base %qE for SSA name", parent); - return error_mark_node; - } - name = make_ssa_name_fn (cfun, parent, - gimple_build_nop (), version); - } - } - - return name; -} - -/* Parse a gimple call to an internal function. - - gimple-call-internal: - . identifier ( gimple-argument-expression-list[opt] ) */ - -static struct c_expr -c_parser_gimple_call_internal (gimple_parser &parser) -{ - struct c_expr expr; - expr.set_error (); - - gcc_assert (c_parser_next_token_is (parser, CPP_DOT)); - c_parser_consume_token (parser); - location_t loc = c_parser_peek_token (parser)->location; - if (!c_parser_next_token_is (parser, CPP_NAME) - || c_parser_peek_token (parser)->id_kind != C_ID_ID) - { - c_parser_error (parser, "expecting internal function name"); - return expr; - } - tree id = c_parser_peek_token (parser)->value; - internal_fn ifn = lookup_internal_fn (IDENTIFIER_POINTER (id)); - c_parser_consume_token (parser); - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - auto_vec exprlist; - if (!c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - c_parser_gimple_expr_list (parser, &exprlist); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - if (ifn == IFN_LAST) - error_at (loc, "unknown internal function %qE", id); - else - { - expr.value = build_call_expr_internal_loc_array - (loc, ifn, void_type_node, exprlist.length (), - exprlist.address ()); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - } - } - return expr; -} - -/* Parse '<' type [',' alignment] '>' and return a type on success - and NULL_TREE on error. */ - -static tree -c_parser_gimple_typespec (gimple_parser &parser) -{ - struct c_type_name *type_name = NULL; - tree alignment = NULL_TREE; - if (c_parser_require (parser, CPP_LESS, "expected %<<%>")) - { - type_name = c_parser_type_name (parser); - /* Optional alignment. */ - if (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - alignment - = c_parser_gimple_postfix_expression (parser).value; - } - c_parser_skip_until_found (parser, - CPP_GREATER, "expected %<>%>"); - } - if (!type_name) - return NULL_TREE; - tree tem; - tree type = groktypename (type_name, &tem, NULL); - if (alignment) - type = build_aligned_type (type, tree_to_uhwi (alignment)); - return type; -} - -/* Parse gimple postfix expression. - - gimple-postfix-expression: - gimple-primary-expression - gimple-primary-expression [ gimple-primary-expression ] - gimple-primary-expression ( gimple-argument-expression-list[opt] ) - gimple-postfix-expression . identifier - gimple-postfix-expression -> identifier - - gimple-argument-expression-list: - gimple-unary-expression - gimple-argument-expression-list , gimple-unary-expression - - gimple-primary-expression: - identifier - constant - string-literal - constructor - gimple-call-internal - -*/ - -static struct c_expr -c_parser_gimple_postfix_expression (gimple_parser &parser) -{ - location_t loc = c_parser_peek_token (parser)->location; - source_range tok_range = c_parser_peek_token (parser)->get_range (); - struct c_expr expr; - expr.set_error (); - switch (c_parser_peek_token (parser)->type) - { - case CPP_NUMBER: - expr.value = c_parser_peek_token (parser)->value; - set_c_expr_source_range (&expr, tok_range); - loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - break; - case CPP_CHAR: - case CPP_CHAR16: - case CPP_CHAR32: - case CPP_UTF8CHAR: - case CPP_WCHAR: - expr.value = c_parser_peek_token (parser)->value; - set_c_expr_source_range (&expr, tok_range); - c_parser_consume_token (parser); - break; - case CPP_STRING: - case CPP_STRING16: - case CPP_STRING32: - case CPP_WSTRING: - case CPP_UTF8STRING: - expr = c_parser_string_literal (parser, false, true); - break; - case CPP_DOT: - expr = c_parser_gimple_call_internal (parser); - break; - case CPP_NAME: - if (c_parser_peek_token (parser)->id_kind == C_ID_ID) - { - tree id = c_parser_peek_token (parser)->value; - if (strcmp (IDENTIFIER_POINTER (id), "__MEM") == 0) - { - /* __MEM '<' type-name [ ',' number ] '>' - '(' [ '(' type-name ')' ] unary-expression - [ '+' number ] ')' */ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - tree type = c_parser_gimple_typespec (parser); - struct c_expr ptr; - ptr.value = error_mark_node; - tree alias_off = NULL_TREE; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - tree alias_type = NULL_TREE; - /* Optional alias-type cast. */ - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - { - c_parser_consume_token (parser); - struct c_type_name *alias_type_name - = c_parser_type_name (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - if (alias_type_name) - { - tree tem; - alias_type = groktypename (alias_type_name, - &tem, NULL); - } - } - ptr = c_parser_gimple_unary_expression (parser); - if (ptr.value == error_mark_node - || ! POINTER_TYPE_P (TREE_TYPE (ptr.value))) - { - if (ptr.value != error_mark_node) - error_at (ptr.get_start (), - "invalid type of %<__MEM%> operand"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - return expr; - } - if (! alias_type) - alias_type = TREE_TYPE (ptr.value); - /* Optional constant offset. */ - if (c_parser_next_token_is (parser, CPP_PLUS)) - { - c_parser_consume_token (parser); - alias_off - = c_parser_gimple_postfix_expression (parser).value; - alias_off = fold_convert (alias_type, alias_off); - } - if (! alias_off) - alias_off = build_int_cst (alias_type, 0); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - } - if (! type || c_parser_error (parser)) - { - c_parser_set_error (parser, false); - return expr; - } - expr.value = build2_loc (loc, MEM_REF, - type, ptr.value, alias_off); - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__VIEW_CONVERT") == 0) - { - /* __VIEW_CONVERT '<' type-name [ ',' number ] '>' - '(' postfix-expression ')' */ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - tree type = c_parser_gimple_typespec (parser); - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - c_expr op = c_parser_gimple_postfix_expression (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - if (type && op.value != error_mark_node) - expr.value = build1_loc (loc, VIEW_CONVERT_EXPR, - type, op.value); - } - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__BIT_FIELD_REF") == 0) - { - /* __BIT_FIELD_REF '<' type-name [ ',' number ] '>' - '(' postfix-expression, integer, integer ')' */ - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - tree type = c_parser_gimple_typespec (parser); - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - c_expr op0 = c_parser_gimple_postfix_expression (parser); - c_parser_skip_until_found (parser, CPP_COMMA, - "expected %<,%>"); - c_expr op1 = c_parser_gimple_postfix_expression (parser); - if (TREE_CODE (op1.value) != INTEGER_CST - || !int_fits_type_p (op1.value, bitsizetype)) - c_parser_error (parser, "expected constant size"); - c_parser_skip_until_found (parser, CPP_COMMA, - "expected %<,%>"); - c_expr op2 = c_parser_gimple_postfix_expression (parser); - if (TREE_CODE (op2.value) != INTEGER_CST - || !int_fits_type_p (op2.value, bitsizetype)) - c_parser_error (parser, "expected constant offset"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - if (type - && op0.value != error_mark_node - && TREE_CODE (op1.value) == INTEGER_CST - && TREE_CODE (op2.value) == INTEGER_CST) - expr.value = build3_loc (loc, BIT_FIELD_REF, type, - op0.value, - fold_convert (bitsizetype, - op1.value), - fold_convert (bitsizetype, - op2.value)); - } - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "_Literal") == 0) - { - /* _Literal '(' type-name ')' ( [ '-' ] constant | constructor ) */ - c_parser_consume_token (parser); - tree type = NULL_TREE; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - struct c_type_name *type_name = c_parser_type_name (parser); - tree tem; - if (type_name) - type = groktypename (type_name, &tem, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - } - if (! type) - { - c_parser_error (parser, "invalid _Literal"); - return expr; - } - if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - { - c_parser_consume_token (parser); - if (!AGGREGATE_TYPE_P (type) - && !VECTOR_TYPE_P (type)) - { - c_parser_error (parser, "invalid type for _Literal with " - "constructor"); - c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, - "expected %<}%>"); - return expr; - } - vec *v = NULL; - bool constant_p = true; - if (VECTOR_TYPE_P (type) - && !c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - vec_alloc (v, TYPE_VECTOR_SUBPARTS (type).to_constant ()); - do - { - tree val - = c_parser_gimple_postfix_expression (parser).value; - if (! val - || val == error_mark_node - || (! CONSTANT_CLASS_P (val) - && ! SSA_VAR_P (val))) - { - c_parser_error (parser, "invalid _Literal"); - return expr; - } - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, val); - if (! CONSTANT_CLASS_P (val)) - constant_p = false; - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else - break; - } - while (1); - } - if (c_parser_require (parser, CPP_CLOSE_BRACE, - "expected %<}%>")) - { - if (v && constant_p) - expr.value = build_vector_from_ctor (type, v); - else - expr.value = build_constructor (type, v); - } - else - { - c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, - "expected %<}%>"); - return expr; - } - } - else - { - bool neg_p, addr_p; - if ((neg_p = c_parser_next_token_is (parser, CPP_MINUS))) - c_parser_consume_token (parser); - if ((addr_p = c_parser_next_token_is (parser, CPP_AND))) - c_parser_consume_token (parser); - tree val = c_parser_gimple_postfix_expression (parser).value; - if (! val - || val == error_mark_node - || (!CONSTANT_CLASS_P (val) && !addr_p)) - { - c_parser_error (parser, "invalid _Literal"); - return expr; - } - if (addr_p) - { - val = build1 (ADDR_EXPR, type, val); - if (!is_gimple_invariant_address (val)) - { - c_parser_error (parser, "invalid _Literal"); - return expr; - } - } - if (neg_p) - { - val = const_unop (NEGATE_EXPR, TREE_TYPE (val), val); - if (! val) - { - c_parser_error (parser, "invalid _Literal"); - return expr; - } - } - expr.value = fold_convert (type, val); - } - return expr; - } - - /* SSA name. */ - unsigned version, ver_offset; - if (! lookup_name (id) - && c_parser_parse_ssa_name_id (id, &version, &ver_offset)) - { - c_parser_consume_token (parser); - expr.value = c_parser_parse_ssa_name (parser, id, NULL_TREE, - version, ver_offset); - if (expr.value == error_mark_node) - return expr; - set_c_expr_source_range (&expr, tok_range); - /* For default definition SSA names. */ - if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) - && c_parser_peek_2nd_token (parser)->type == CPP_NAME - && strcmp ("D", - IDENTIFIER_POINTER - (c_parser_peek_2nd_token (parser)->value)) == 0 - && c_parser_peek_nth_token (parser, 3)->type == CPP_CLOSE_PAREN) - { - c_parser_consume_token (parser); - c_parser_consume_token (parser); - c_parser_consume_token (parser); - if (! SSA_NAME_IS_DEFAULT_DEF (expr.value)) - { - if (!SSA_NAME_VAR (expr.value)) - { - error_at (loc, "anonymous SSA name cannot have" - " default definition"); - expr.value = error_mark_node; - return expr; - } - set_ssa_default_def (cfun, SSA_NAME_VAR (expr.value), - expr.value); - SSA_NAME_DEF_STMT (expr.value) = gimple_build_nop (); - } - } - } - else - { - c_parser_consume_token (parser); - expr.value - = build_external_ref (loc, id, - (c_parser_peek_token (parser)->type - == CPP_OPEN_PAREN), &expr.original_type); - set_c_expr_source_range (&expr, tok_range); - } - break; - } - /* Fallthru. */ - default: - c_parser_error (parser, "expected expression"); - expr.set_error (); - break; - } - if (expr.value == error_mark_node) - return expr; - return c_parser_gimple_postfix_expression_after_primary - (parser, EXPR_LOC_OR_LOC (expr.value, loc), expr); -} - -/* Parse a gimple postfix expression after the initial primary or compound - literal. */ - -static struct c_expr -c_parser_gimple_postfix_expression_after_primary (gimple_parser &parser, - location_t expr_loc, - struct c_expr expr) -{ - location_t start; - location_t finish; - tree ident; - location_t comp_loc; - - while (true) - { - location_t op_loc = c_parser_peek_token (parser)->location; - switch (c_parser_peek_token (parser)->type) - { - case CPP_OPEN_SQUARE: - { - c_parser_consume_token (parser); - tree idx = c_parser_gimple_unary_expression (parser).value; - - if (! c_parser_require (parser, CPP_CLOSE_SQUARE, "expected %<]%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL); - break; - } - - start = expr.get_start (); - finish = c_parser_tokens_buf (parser, 0)->location; - expr.value = build_array_ref (op_loc, expr.value, idx); - set_c_expr_source_range (&expr, start, finish); - - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - break; - } - case CPP_OPEN_PAREN: - { - /* Function call. */ - c_parser_consume_token (parser); - auto_vec exprlist; - if (! c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - c_parser_gimple_expr_list (parser, &exprlist); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - if (!FUNC_OR_METHOD_TYPE_P (TREE_TYPE (expr.value))) - { - c_parser_error (parser, "invalid call to non-function"); - expr.set_error (); - break; - } - expr.value = build_call_array_loc - (expr_loc, TREE_TYPE (TREE_TYPE (expr.value)), - expr.value, exprlist.length (), exprlist.address ()); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - break; - } - case CPP_DOT: - { - /* Structure element reference. */ - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - c_token *comp_tok = c_parser_peek_token (parser); - ident = comp_tok->value; - comp_loc = comp_tok->location; - } - else - { - c_parser_error (parser, "expected identifier"); - expr.set_error (); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - return expr; - } - start = expr.get_start (); - finish = c_parser_peek_token (parser)->get_finish (); - c_parser_consume_token (parser); - expr.value = build_component_ref (op_loc, expr.value, ident, - comp_loc); - set_c_expr_source_range (&expr, start, finish); - expr.original_code = ERROR_MARK; - if (TREE_CODE (expr.value) != COMPONENT_REF) - expr.original_type = NULL; - else - { - /* Remember the original type of a bitfield. */ - tree field = TREE_OPERAND (expr.value, 1); - if (TREE_CODE (field) != FIELD_DECL) - expr.original_type = NULL; - else - expr.original_type = DECL_BIT_FIELD_TYPE (field); - } - break; - } - case CPP_DEREF: - { - /* Structure element reference. */ - if (!POINTER_TYPE_P (TREE_TYPE (expr.value))) - { - c_parser_error (parser, "dereference of non-pointer"); - expr.set_error (); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - return expr; - } - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - c_token *comp_tok = c_parser_peek_token (parser); - ident = comp_tok->value; - comp_loc = comp_tok->location; - } - else - { - c_parser_error (parser, "expected identifier"); - expr.set_error (); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - return expr; - } - start = expr.get_start (); - finish = c_parser_peek_token (parser)->get_finish (); - c_parser_consume_token (parser); - expr.value = build_component_ref (op_loc, - build_simple_mem_ref_loc - (op_loc, expr.value), - ident, comp_loc); - set_c_expr_source_range (&expr, start, finish); - expr.original_code = ERROR_MARK; - if (TREE_CODE (expr.value) != COMPONENT_REF) - expr.original_type = NULL; - else - { - /* Remember the original type of a bitfield. */ - tree field = TREE_OPERAND (expr.value, 1); - if (TREE_CODE (field) != FIELD_DECL) - expr.original_type = NULL; - else - expr.original_type = DECL_BIT_FIELD_TYPE (field); - } - break; - } - default: - return expr; - } - } -} - -/* Parse expression list. - - gimple-expr-list: - gimple-unary-expression - gimple-expr-list , gimple-unary-expression - - */ - -static void -c_parser_gimple_expr_list (gimple_parser &parser, vec *ret) -{ - struct c_expr expr; - - expr = c_parser_gimple_unary_expression (parser); - ret->safe_push (expr.value); - while (c_parser_next_token_is (parser, CPP_COMMA)) - { - c_parser_consume_token (parser); - expr = c_parser_gimple_unary_expression (parser); - ret->safe_push (expr.value); - } -} - -/* Parse gimple label. - - gimple-label: - identifier : - case constant-expression : - default : - -*/ - -static void -c_parser_gimple_label (gimple_parser &parser, gimple_seq *seq) -{ - tree name = c_parser_peek_token (parser)->value; - location_t loc1 = c_parser_peek_token (parser)->location; - gcc_assert (c_parser_next_token_is (parser, CPP_NAME)); - c_parser_consume_token (parser); - gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); - c_parser_consume_token (parser); - tree label = define_label (loc1, name); - if (label) - gimple_seq_add_stmt_without_update (seq, gimple_build_label (label)); - return; -} - -/* Parse gimple/RTL pass list. - - gimple-or-rtl-pass-list: - startwith("pass-name")[,{cfg,ssa}] - */ - -void -c_parser_gimple_or_rtl_pass_list (c_parser *parser, c_declspecs *specs) -{ - char *pass = NULL; - - /* Accept __GIMPLE/__RTL. */ - if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) - return; - c_parser_consume_token (parser); - - specs->entry_bb_count = profile_count::uninitialized (); - while (c_parser_next_token_is (parser, CPP_NAME)) - { - profile_quality quality; - const char *op = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - c_parser_consume_token (parser); - if (! strcmp (op, "startwith")) - { - if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return; - if (c_parser_next_token_is_not (parser, CPP_STRING)) - { - error_at (c_parser_peek_token (parser)->location, - "expected pass name"); - return; - } - pass = xstrdup (TREE_STRING_POINTER - (c_parser_string_literal (parser, false, - false).value)); - if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<(%>")) - return; - } - else if (parse_profile_quality (op, &quality)) - { - tree q; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return; - - if (!c_parser_next_token_is (parser, CPP_NUMBER) - || (TREE_CODE (q = c_parser_peek_token (parser)->value) - != INTEGER_CST)) - { - c_parser_error (parser, "expected count value"); - return; - } - - specs->entry_bb_count - = profile_count::from_gcov_type (TREE_INT_CST_LOW (q), quality); - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - return; - } - else if (specs->declspec_il != cdil_gimple) - /* Allow only one IL specifier and none on RTL. */ - ; - else if (! strcmp (op, "cfg")) - specs->declspec_il = cdil_gimple_cfg; - else if (! strcmp (op, "ssa")) - specs->declspec_il = cdil_gimple_ssa; - else - { - error_at (c_parser_peek_token (parser)->location, - "invalid operation"); - return; - } - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - } - - if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - return; - - specs->gimple_or_rtl_pass = pass; -} - -/* Parse gimple local declaration. - - declaration-specifiers: - storage-class-specifier declaration-specifiers[opt] - type-specifier declaration-specifiers[opt] - type-qualifier declaration-specifiers[opt] - function-specifier declaration-specifiers[opt] - alignment-specifier declaration-specifiers[opt] - - storage-class-specifier: - typedef - extern - static - auto - register - - type-specifier: - void - char - short - int - long - float - double - signed - unsigned - _Bool - _Complex - - type-qualifier: - const - restrict - volatile - address-space-qualifier - _Atomic - - */ - -static void -c_parser_gimple_declaration (gimple_parser &parser) -{ - struct c_declarator *declarator; - struct c_declspecs *specs = build_null_declspecs (); - c_parser_declspecs (parser, specs, true, true, true, - true, true, true, true, cla_nonabstract_decl); - finish_declspecs (specs); - - /* Provide better error recovery. Note that a type name here is usually - better diagnosed as a redeclaration. */ - if (c_parser_next_token_starts_declspecs (parser) - && ! c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected %<;%>"); - c_parser_set_error (parser, false); - return; - } - - bool dummy = false; - declarator = c_parser_declarator (parser, - specs->typespec_kind != ctsk_none, - C_DTR_NORMAL, &dummy); - - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - /* Handle SSA name decls specially, they do not go into the identifier - table but we simply build the SSA name for later lookup. */ - unsigned version, ver_offset; - if (declarator->kind == cdk_id - && is_gimple_reg_type (specs->type) - && c_parser_parse_ssa_name_id (declarator->u.id.id, - &version, &ver_offset) - /* The following restricts it to unnamed anonymous SSA names - which fails parsing of named ones in dumps (we could - decide to not dump their name for -gimple). */ - && ver_offset == 0) - c_parser_parse_ssa_name (parser, declarator->u.id.id, specs->type, - version, ver_offset); - else - { - tree postfix_attrs = NULL_TREE; - tree all_prefix_attrs = specs->attrs; - specs->attrs = NULL; - tree decl = start_decl (declarator, specs, false, - chainon (postfix_attrs, all_prefix_attrs)); - if (decl) - finish_decl (decl, UNKNOWN_LOCATION, NULL_TREE, NULL_TREE, - NULL_TREE); - } - } - else - { - c_parser_error (parser, "expected %<;%>"); - return; - } -} - -/* Parse gimple goto statement. */ - -static void -c_parser_gimple_goto_stmt (gimple_parser &parser, - location_t loc, tree label, gimple_seq *seq) -{ - if (cfun->curr_properties & PROP_cfg) - { - int dest_index; - profile_probability prob; - if (c_parser_gimple_parse_bb_spec_edge_probability (label, parser, - &dest_index, &prob)) - { - parser.push_edge (parser.current_bb->index, dest_index, - EDGE_FALLTHRU, prob); - return; - } - } - tree decl = lookup_label_for_goto (loc, label); - gimple_seq_add_stmt_without_update (seq, gimple_build_goto (decl)); -} - -/* Parse a parenthesized condition. - gimple-condition: - ( gimple-binary-expression ) */ - -static tree -c_parser_gimple_paren_condition (gimple_parser &parser) -{ - if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return error_mark_node; - tree cond = c_parser_gimple_binary_expression (parser).value; - if (cond != error_mark_node - && ! COMPARISON_CLASS_P (cond) - && ! CONSTANT_CLASS_P (cond) - && ! SSA_VAR_P (cond)) - { - c_parser_error (parser, "comparison required"); - cond = error_mark_node; - } - if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - return error_mark_node; - return cond; -} - -/* Parse gimple try statement. - - try-statement: - try { ... } finally { ... } - try { ... } finally { ... } else { ... } - - This could support try/catch as well, but it's not implemented yet. - */ - -static void -c_parser_gimple_try_stmt (gimple_parser &parser, gimple_seq *seq) -{ - gimple_seq tryseq = NULL; - c_parser_consume_token (parser); - c_parser_gimple_compound_statement (parser, &tryseq); - - if ((c_parser_next_token_is (parser, CPP_KEYWORD) - && c_parser_peek_token (parser)->keyword == RID_AT_FINALLY) - || (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_ID - && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), - "finally") == 0)) - { - gimple_seq finseq = NULL; - c_parser_consume_token (parser); - c_parser_gimple_compound_statement (parser, &finseq); - - if (c_parser_next_token_is (parser, CPP_KEYWORD) - && c_parser_peek_token (parser)->keyword == RID_ELSE) - { - gimple_seq elsseq = NULL; - c_parser_consume_token (parser); - c_parser_gimple_compound_statement (parser, &elsseq); - - geh_else *stmt = gimple_build_eh_else (finseq, elsseq); - finseq = NULL; - gimple_seq_add_stmt_without_update (&finseq, stmt); - } - - gtry *stmt = gimple_build_try (tryseq, finseq, GIMPLE_TRY_FINALLY); - gimple_seq_add_stmt_without_update (seq, stmt); - } - else if (c_parser_next_token_is (parser, CPP_KEYWORD) - && c_parser_peek_token (parser)->keyword == RID_AT_CATCH) - c_parser_error (parser, "% is not supported"); - else - c_parser_error (parser, "expected % or %"); -} - -/* Parse gimple if-else statement. - - if-statement: - if ( gimple-binary-expression ) gimple-goto-statement - if ( gimple-binary-expression ) gimple-goto-statement \ - else gimple-goto-statement - */ - -static void -c_parser_gimple_if_stmt (gimple_parser &parser, gimple_seq *seq) -{ - tree t_label = NULL_TREE, f_label = NULL_TREE, label; - location_t loc; - c_parser_consume_token (parser); - tree cond = c_parser_gimple_paren_condition (parser); - - if (c_parser_next_token_is_keyword (parser, RID_GOTO)) - { - loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - if (! c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected label"); - return; - } - label = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - int dest_index; - profile_probability prob; - if ((cfun->curr_properties & PROP_cfg) - && c_parser_gimple_parse_bb_spec_edge_probability (label, parser, - &dest_index, &prob)) - parser.push_edge (parser.current_bb->index, dest_index, - EDGE_TRUE_VALUE, prob); - else - t_label = lookup_label_for_goto (loc, label); - if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) - return; - } - else - { - c_parser_error (parser, "expected goto expression"); - return; - } - - if (c_parser_next_token_is_keyword (parser, RID_ELSE)) - c_parser_consume_token (parser); - else - { - c_parser_error (parser, "expected else statement"); - return; - } - - if (c_parser_next_token_is_keyword (parser, RID_GOTO)) - { - loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - if (! c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected label"); - return; - } - label = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - int dest_index; - profile_probability prob; - if ((cfun->curr_properties & PROP_cfg) - && c_parser_gimple_parse_bb_spec_edge_probability (label, parser, - &dest_index, &prob)) - parser.push_edge (parser.current_bb->index, dest_index, - EDGE_FALSE_VALUE, prob); - else - f_label = lookup_label_for_goto (loc, label); - if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) - return; - } - else - { - c_parser_error (parser, "expected goto expression"); - return; - } - - if (cond != error_mark_node) - gimple_seq_add_stmt_without_update (seq, gimple_build_cond_from_tree (cond, t_label, - f_label)); -} - -/* Parse gimple switch-statement. - - gimple-switch-statement: - switch (gimple-postfix-expression) gimple-case-statement - - gimple-case-statement: - gimple-case-statement - gimple-label-statement : gimple-goto-statment -*/ - -static void -c_parser_gimple_switch_stmt (gimple_parser &parser, gimple_seq *seq) -{ - c_expr cond_expr; - tree case_label, label; - auto_vec labels; - tree default_label = NULL_TREE; - c_parser_consume_token (parser); - - if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return; - cond_expr = c_parser_gimple_postfix_expression (parser); - if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) - return; - - if (! c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) - return; - - while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) - { - if (c_parser_next_token_is (parser, CPP_EOF)) - { - c_parser_error (parser, "expected statement"); - return; - } - - switch (c_parser_peek_token (parser)->keyword) - { - case RID_CASE: - { - c_expr exp1; - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - - if (c_parser_next_token_is (parser, CPP_NAME) - || c_parser_peek_token (parser)->type == CPP_NUMBER) - exp1 = c_parser_gimple_postfix_expression (parser); - else - { - c_parser_error (parser, "expected expression"); - return; - } - - if (c_parser_next_token_is (parser, CPP_COLON)) - { - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - label = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - tree decl = lookup_label_for_goto (loc, label); - case_label = build_case_label (exp1.value, NULL_TREE, - decl); - labels.safe_push (case_label); - if (! c_parser_require (parser, CPP_SEMICOLON, - "expected %<;%>")) - return; - } - else if (! c_parser_require (parser, CPP_NAME, - "expected label")) - return; - } - else if (! c_parser_require (parser, CPP_SEMICOLON, - "expected %<:%>")) - return; - break; - } - case RID_DEFAULT: - { - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COLON)) - { - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - label = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - tree decl = lookup_label_for_goto (loc, label); - default_label = build_case_label (NULL_TREE, NULL_TREE, - decl); - if (! c_parser_require (parser, CPP_SEMICOLON, - "expected %<;%>")) - return; - } - else if (! c_parser_require (parser, CPP_NAME, - "expected label")) - return; - } - else if (! c_parser_require (parser, CPP_SEMICOLON, - "expected %<:%>")) - return; - break; - } - default: - c_parser_error (parser, "expected case label"); - return; - } - - } - if (! c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>")) - return; - - if (cond_expr.value != error_mark_node) - { - gswitch *s = gimple_build_switch (cond_expr.value, default_label, labels); - gimple_seq_add_stmt_without_update (seq, s); - } -} - -/* Parse gimple return statement. */ - -static void -c_parser_gimple_return_stmt (gimple_parser &parser, gimple_seq *seq) -{ - location_t loc = c_parser_peek_token (parser)->location; - gimple *ret = NULL; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - c_finish_gimple_return (loc, NULL_TREE); - ret = gimple_build_return (NULL); - gimple_seq_add_stmt_without_update (seq, ret); - } - else - { - location_t xloc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_gimple_unary_expression (parser); - if (expr.value != error_mark_node) - { - c_finish_gimple_return (xloc, expr.value); - ret = gimple_build_return (expr.value); - gimple_seq_add_stmt_without_update (seq, ret); - } - } -} - -/* Support function for c_parser_gimple_return_stmt. */ - -static void -c_finish_gimple_return (location_t loc, tree retval) -{ - tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)); - - /* Use the expansion point to handle cases such as returning NULL - in a function returning void. */ - location_t xloc = expansion_point_location_if_in_system_header (loc); - - if (TREE_THIS_VOLATILE (current_function_decl)) - warning_at (xloc, 0, - "function declared % has a % statement"); - - if (! retval) - current_function_returns_null = 1; - else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE) - { - current_function_returns_null = 1; - if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) - { - error_at - (xloc, "% with a value, in function returning void"); - inform (DECL_SOURCE_LOCATION (current_function_decl), - "declared here"); - } - } - else if (TREE_CODE (valtype) != TREE_CODE (TREE_TYPE (retval))) - { - error_at - (xloc, "invalid conversion in return statement"); - inform (DECL_SOURCE_LOCATION (current_function_decl), - "declared here"); - } - return; -} diff --git a/gcc/c/gimple-parser.cc b/gcc/c/gimple-parser.cc new file mode 100644 index 0000000..51ddd86 --- /dev/null +++ b/gcc/c/gimple-parser.cc @@ -0,0 +1,2453 @@ +/* Parser for GIMPLE. + Copyright (C) 2016-2022 Free Software Foundation, Inc. + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "function.h" +#include "c-tree.h" +#include "timevar.h" +#include "stringpool.h" +#include "cgraph.h" +#include "attribs.h" +#include "stor-layout.h" +#include "varasm.h" +#include "trans-mem.h" +#include "c-family/c-pragma.h" +#include "c-lang.h" +#include "c-family/c-objc.h" +#include "plugin.h" +#include "builtins.h" +#include "gomp-constants.h" +#include "c-family/c-indentation.h" +#include "gimple-expr.h" +#include "context.h" +#include "gcc-rich-location.h" +#include "c-parser.h" +#include "tree-vrp.h" +#include "tree-pass.h" +#include "tree-pretty-print.h" +#include "tree.h" +#include "basic-block.h" +#include "gimple.h" +#include "gimple-pretty-print.h" +#include "tree-ssa.h" +#include "pass_manager.h" +#include "tree-ssanames.h" +#include "gimple-ssa.h" +#include "tree-dfa.h" +#include "internal-fn.h" +#include "cfg.h" +#include "cfghooks.h" +#include "bitmap.h" +#include "cfganal.h" +#include "tree-cfg.h" +#include "gimple-iterator.h" +#include "cfgloop.h" +#include "tree-phinodes.h" +#include "tree-into-ssa.h" + + +/* GIMPLE parser state. */ + +class gimple_parser +{ +public: + gimple_parser (c_parser *p) : parser (p), edges(), current_bb(NULL) {} + /* c_parser is not visible here, use composition and fake inheritance + via a conversion operator. */ + operator c_parser *() { return parser; } + c_parser *parser; + + /* CFG build state. */ + class gimple_parser_edge + { + public: + int src; + int dest; + int flags; + profile_probability probability; + }; + auto_vec edges; + basic_block current_bb; + + void push_edge (int, int, int, profile_probability); +}; + +void +gimple_parser::push_edge (int src, int dest, int flags, + profile_probability prob) +{ + gimple_parser_edge e; + e.src = src; + e.dest = dest; + e.flags = flags; + e.probability = prob; + edges.safe_push (e); +} + + +/* Gimple parsing functions. */ +static bool c_parser_gimple_compound_statement (gimple_parser &, gimple_seq *); +static void c_parser_gimple_label (gimple_parser &, gimple_seq *); +static void c_parser_gimple_statement (gimple_parser &, gimple_seq *); +static struct c_expr c_parser_gimple_binary_expression (gimple_parser &); +static struct c_expr c_parser_gimple_unary_expression (gimple_parser &); +static struct c_expr c_parser_gimple_postfix_expression (gimple_parser &); +static struct c_expr c_parser_gimple_postfix_expression_after_primary + (gimple_parser &, location_t, struct c_expr); +static void c_parser_gimple_declaration (gimple_parser &); +static void c_parser_gimple_goto_stmt (gimple_parser &, location_t, + tree, gimple_seq *); +static void c_parser_gimple_try_stmt (gimple_parser &, gimple_seq *); +static void c_parser_gimple_if_stmt (gimple_parser &, gimple_seq *); +static void c_parser_gimple_switch_stmt (gimple_parser &, gimple_seq *); +static void c_parser_gimple_return_stmt (gimple_parser &, gimple_seq *); +static void c_finish_gimple_return (location_t, tree); +static tree c_parser_gimple_paren_condition (gimple_parser &); +static void c_parser_gimple_expr_list (gimple_parser &, vec *); + + +/* See if VAL is an identifier matching __BB and return + in *INDEX. */ + +static bool +c_parser_gimple_parse_bb_spec (tree val, int *index) +{ + if (!startswith (IDENTIFIER_POINTER (val), "__BB")) + return false; + for (const char *p = IDENTIFIER_POINTER (val) + 4; *p; ++p) + if (!ISDIGIT (*p)) + return false; + *index = atoi (IDENTIFIER_POINTER (val) + 4); + return *index > 0; +} + +/* See if VAL is an identifier matching __BB and return + in *INDEX. Return true if so and parse also FREQUENCY of + the edge. */ + + +static bool +c_parser_gimple_parse_bb_spec_edge_probability (tree val, + gimple_parser &parser, + int *index, + profile_probability + *probability) +{ + bool return_p = c_parser_gimple_parse_bb_spec (val, index); + if (return_p) + { + *probability = profile_probability::uninitialized (); + /* Parse frequency if provided. */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + tree f; + c_parser_consume_token (parser); + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected frequency quality"); + return false; + } + + profile_quality quality; + const char *v + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (!parse_profile_quality (v, &quality)) + { + c_parser_error (parser, "unknown profile quality"); + return false; + } + + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return false; + + if (!c_parser_next_token_is (parser, CPP_NUMBER) + || (TREE_CODE (f = c_parser_peek_token (parser)->value) + != INTEGER_CST)) + { + c_parser_error (parser, "expected frequency value"); + return false; + } + + unsigned int value = TREE_INT_CST_LOW (f); + *probability = profile_probability (value, quality); + + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return false; + + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return false; + } + + return true; + } + + return false; + +} + +/* Parse the body of a function declaration marked with "__GIMPLE". */ + +void +c_parser_parse_gimple_body (c_parser *cparser, char *gimple_pass, + enum c_declspec_il cdil, + profile_count entry_bb_count) +{ + gimple_parser parser (cparser); + gimple_seq seq = NULL; + gimple_seq body = NULL; + tree stmt = push_stmt_list (); + push_scope (); + location_t loc1 = c_parser_peek_token (parser)->location; + + cfun->pass_startwith = gimple_pass; + init_tree_ssa (cfun); + + if (cdil == cdil_gimple) + /* While we have SSA names in the IL we do not have a CFG built yet + and PHIs are represented using a PHI internal function. We do + have lowered control flow and exception handling (well, we do not + have parser support for EH yet). But as we still have BINDs + we have to go through lowering again. */ + cfun->curr_properties = PROP_gimple_any; + else + { + /* We have at least cdil_gimple_cfg. */ + gimple_register_cfg_hooks (); + init_empty_tree_cfg (); + parser.current_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun); + /* Initialize the bare loop structure - we are going to only + mark headers and leave the rest to fixup. */ + set_loops_for_fn (cfun, ggc_cleared_alloc ()); + init_loops_structure (cfun, loops_for_fn (cfun), 1); + loops_state_set (cfun, LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES); + cfun->curr_properties + |= PROP_gimple_lcf | PROP_gimple_leh | PROP_cfg | PROP_loops; + if (cdil == cdil_gimple_ssa) + { + init_ssa_operands (cfun); + cfun->curr_properties |= PROP_ssa; + } + } + + if (! c_parser_gimple_compound_statement (parser, &seq) + && cdil == cdil_gimple) + { + gimple *ret = gimple_build_return (NULL); + gimple_seq_add_stmt_without_update (&seq, ret); + } + + tree block = pop_scope (); + stmt = pop_stmt_list (stmt); + stmt = c_build_bind_expr (loc1, block, stmt); + + block = DECL_INITIAL (current_function_decl); + BLOCK_SUBBLOCKS (block) = NULL_TREE; + BLOCK_CHAIN (block) = NULL_TREE; + TREE_ASM_WRITTEN (block) = 1; + + if (cdil == cdil_gimple) + { + gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL, + BIND_EXPR_BLOCK (stmt)); + gimple_bind_set_body (bind_stmt, seq); + gimple_seq_add_stmt_without_update (&body, bind_stmt); + gimple_set_body (current_function_decl, body); + } + else + { + /* Control-flow and binds are lowered, record local decls. */ + for (tree var = BIND_EXPR_VARS (stmt); var; var = DECL_CHAIN (var)) + if (VAR_P (var) + && !DECL_EXTERNAL (var)) + add_local_decl (cfun, var); + /* We have a CFG. Build the edges. */ + for (unsigned i = 0; i < parser.edges.length (); ++i) + { + edge e = make_edge (BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].src), + BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].dest), + parser.edges[i].flags); + e->probability = parser.edges[i].probability; + } + /* Add edges for case labels. */ + basic_block bb; + FOR_EACH_BB_FN (bb, cfun) + if (EDGE_COUNT (bb->succs) == 0) + { + gimple *last = last_stmt (bb); + if (gswitch *sw = safe_dyn_cast (last)) + for (unsigned i = 0; i < gimple_switch_num_labels (sw); ++i) + { + basic_block label_bb = gimple_switch_label_bb (cfun, sw, i); + make_edge (bb, label_bb, 0); + } + } + /* Need those for loop fixup. */ + calculate_dominance_info (CDI_DOMINATORS); + /* With SSA lower PHIs parsed as internal function calls and + update stmts. */ + if (cdil == cdil_gimple_ssa) + { + /* Create PHI nodes, they are parsed into __PHI internal calls. */ + FOR_EACH_BB_FN (bb, cfun) + for (gimple_stmt_iterator gsi = gsi_start_bb (bb); + !gsi_end_p (gsi);) + { + gimple *stmt = gsi_stmt (gsi); + if (!gimple_call_internal_p (stmt, IFN_PHI)) + break; + + gphi *phi = create_phi_node (gimple_call_lhs (stmt), bb); + for (unsigned i = 0; i < gimple_call_num_args (stmt); i += 2) + { + int srcidx = TREE_INT_CST_LOW (gimple_call_arg (stmt, i)); + edge e = find_edge (BASIC_BLOCK_FOR_FN (cfun, srcidx), bb); + if (!e) + c_parser_error (parser, "edge not found"); + else + add_phi_arg (phi, gimple_call_arg (stmt, i + 1), e, + UNKNOWN_LOCATION); + } + gsi_remove (&gsi, true); + } + /* Fill SSA name gaps, putting them on the freelist. */ + for (unsigned i = 1; i < num_ssa_names; ++i) + if (!ssa_name (i)) + { + tree name = make_ssa_name_fn (cfun, integer_type_node, NULL, i); + release_ssa_name_fn (cfun, name); + } + /* No explicit virtual operands (yet). */ + bitmap_obstack_initialize (NULL); + update_ssa (TODO_update_ssa_only_virtuals); + bitmap_obstack_release (NULL); + /* ??? By flushing the freelist after virtual operand SSA rewrite + we keep the gaps available for re-use like needed for the + PR89595 testcase but then usually virtual operands would have + taken most of them. The fix is obviously to make virtual + operands explicit in the SSA IL. */ + flush_ssaname_freelist (); + } + fix_loop_structure (NULL); + } + + if (cfun->curr_properties & PROP_cfg) + { + ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = entry_bb_count; + gcov_type t = param_gimple_fe_computed_hot_bb_threshold; + set_hot_bb_threshold (t); + update_max_bb_count (); + cgraph_node::get_create (cfun->decl); + cgraph_edge::rebuild_edges (); + } + dump_function (TDI_gimple, current_function_decl); +} + +/* Parse a compound statement in gimple function body. + + gimple-statement: + gimple-statement + gimple-declaration-statement + gimple-if-statement + gimple-switch-statement + gimple-labeled-statement + gimple-expression-statement + gimple-goto-statement + gimple-phi-statement + gimple-return-statement +*/ + +static bool +c_parser_gimple_compound_statement (gimple_parser &parser, gimple_seq *seq) +{ + bool return_p = false; + + if (! c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + return false; + + /* A compund statement starts with optional declarations. */ + while (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_gimple_declaration (parser); + if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + return false; + } + + while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) + { + if (c_parser_error (parser)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); + return return_p; + } + else if (c_parser_next_token_is (parser, CPP_EOF)) + { + c_parser_error (parser, "expected declaration or statement"); + return return_p; + } + + switch (c_parser_peek_token (parser)->type) + { + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_AT_TRY: + c_parser_gimple_try_stmt (parser, seq); + break; + case RID_IF: + c_parser_gimple_if_stmt (parser, seq); + break; + case RID_SWITCH: + c_parser_gimple_switch_stmt (parser, seq); + break; + case RID_GOTO: + { + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree label = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + c_parser_gimple_goto_stmt (parser, loc, label, seq); + if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<;%>")) + return return_p; + } + } + break; + case RID_RETURN: + return_p = true; + c_parser_gimple_return_stmt (parser, seq); + if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<;%>")) + return return_p; + if (cfun->curr_properties & PROP_cfg) + parser.push_edge (parser.current_bb->index, EXIT_BLOCK, 0, + profile_probability::uninitialized ()); + break; + default: + goto expr_stmt; + } + break; + case CPP_NAME: + if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + c_parser_gimple_label (parser, seq); + break; + } + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "try") == 0) + { + c_parser_gimple_try_stmt (parser, seq); + break; + } + /* Basic block specification. + __BB (index, ...) */ + if ((cfun->curr_properties & PROP_cfg) + && !strcmp (IDENTIFIER_POINTER + (c_parser_peek_token (parser)->value), "__BB")) + { + c_parser_consume_token (parser); + if (! c_parser_require (parser, CPP_OPEN_PAREN, + "expected %<(%>")) + return return_p; + if (c_parser_next_token_is_not (parser, CPP_NUMBER)) + { + c_parser_error (parser, "expected block index"); + return return_p; + } + tree tnum = c_parser_peek_token (parser)->value; + if (TREE_CODE (tnum) != INTEGER_CST) + { + c_parser_error (parser, "expected block index"); + return return_p; + } + int index = TREE_INT_CST_LOW (tnum); + if (index < NUM_FIXED_BLOCKS + || (index < last_basic_block_for_fn (cfun) + && BASIC_BLOCK_FOR_FN (cfun, index) != NULL)) + { + c_parser_error (parser, "invalid block index"); + return return_p; + } + int is_loop_header_of = -1; + profile_count bb_count = profile_count::uninitialized (); + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + if (! c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected block specifier"); + return return_p; + } + /* loop_header (NUM) */ + if (!strcmp (IDENTIFIER_POINTER + (c_parser_peek_token (parser)->value), + "loop_header")) + { + c_parser_consume_token (parser); + if (! c_parser_require (parser, CPP_OPEN_PAREN, + "expected %<(%>")) + return return_p; + tree loop_num; + if (! c_parser_next_token_is (parser, CPP_NUMBER) + || TREE_CODE (loop_num + = c_parser_peek_token (parser)->value) + != INTEGER_CST) + { + c_parser_error (parser, "expected loop number"); + return return_p; + } + c_parser_consume_token (parser); + is_loop_header_of = TREE_INT_CST_LOW (loop_num); + if (! c_parser_require (parser, CPP_CLOSE_PAREN, + "expected %<)%>")) + return return_p; + } + /* Parse profile: quality(value) */ + else + { + tree q; + profile_quality quality; + tree v = c_parser_peek_token (parser)->value; + if (!parse_profile_quality (IDENTIFIER_POINTER (v), + &quality)) + { + c_parser_error (parser, "unknown block specifier"); + return false; + } + + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, + "expected %<(%>")) + return false; + + if (!c_parser_next_token_is (parser, CPP_NUMBER) + || (TREE_CODE (q = c_parser_peek_token (parser)->value) + != INTEGER_CST)) + { + c_parser_error (parser, "expected count value"); + return false; + } + + bb_count + = profile_count::from_gcov_type (TREE_INT_CST_LOW (q), + quality); + c_parser_consume_token (parser); + if (! c_parser_require (parser, CPP_CLOSE_PAREN, + "expected %<)%>")) + return return_p; + } + } + if (! c_parser_require (parser, CPP_CLOSE_PAREN, + "expected %<)%>") + || ! c_parser_require (parser, CPP_COLON, + "expected %<:%>")) + return return_p; + + /* Put stmts parsed in the current block. */ + if (!gimple_seq_empty_p (*seq)) + { + if (!parser.current_bb) + c_parser_error (parser, "stmts without block"); + else + { + gimple_stmt_iterator gsi + = gsi_start_bb (parser.current_bb); + gsi_insert_seq_after (&gsi, *seq, GSI_CONTINUE_LINKING); + } + *seq = NULL; + } + + /* Build an empty block with specified index, linking them + in source order. */ + basic_block bb = alloc_block (); + bb->index = index; + link_block (bb, (parser.current_bb ? parser.current_bb + : ENTRY_BLOCK_PTR_FOR_FN (cfun))); + if (basic_block_info_for_fn (cfun)->length () <= (size_t)index) + vec_safe_grow_cleared (basic_block_info_for_fn (cfun), + index + 1, true); + SET_BASIC_BLOCK_FOR_FN (cfun, index, bb); + if (last_basic_block_for_fn (cfun) <= index) + last_basic_block_for_fn (cfun) = index + 1; + n_basic_blocks_for_fn (cfun)++; + if (parser.current_bb->index == ENTRY_BLOCK) + parser.push_edge (ENTRY_BLOCK, bb->index, EDGE_FALLTHRU, + profile_probability::always ()); + + /* We leave the proper setting to fixup. */ + class loop *loop_father = loops_for_fn (cfun)->tree_root; + /* If the new block is a loop header, allocate a loop + struct. Fixup will take care of proper placement within + the loop tree. */ + if (is_loop_header_of != -1) + { + if (number_of_loops (cfun) > (unsigned)is_loop_header_of + && get_loop (cfun, is_loop_header_of) != NULL) + { + c_parser_error (parser, "duplicate loop header"); + } + else + { + class loop *loop = alloc_loop (); + loop->num = is_loop_header_of; + loop->header = bb; + if (number_of_loops (cfun) <= (unsigned)is_loop_header_of) + vec_safe_grow_cleared (loops_for_fn (cfun)->larray, + is_loop_header_of + 1, true); + (*loops_for_fn (cfun)->larray)[is_loop_header_of] = loop; + flow_loop_tree_node_add (loops_for_fn (cfun)->tree_root, + loop); + } + loop_father = get_loop (cfun, is_loop_header_of); + } + bb->loop_father = loop_father; + bb->count = bb_count; + + /* Stmts now go to the new block. */ + parser.current_bb = bb; + break; + } + goto expr_stmt; + + case CPP_SEMICOLON: + { + /* Empty stmt. */ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + gimple *nop = gimple_build_nop (); + gimple_set_location (nop, loc); + gimple_seq_add_stmt_without_update (seq, nop); + break; + } + + default: +expr_stmt: + c_parser_gimple_statement (parser, seq); + if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + } + } + c_parser_consume_token (parser); + + /* Put stmts parsed in the current block. */ + if ((cfun->curr_properties & PROP_cfg) + && !gimple_seq_empty_p (*seq)) + { + if (!parser.current_bb) + c_parser_error (parser, "stmts without block"); + else + { + gimple_stmt_iterator gsi = gsi_start_bb (parser.current_bb); + gsi_insert_seq_after (&gsi, *seq, GSI_CONTINUE_LINKING); + } + *seq = NULL; + } + + return return_p; +} + +/* Parse a gimple statement. + + gimple-statement: + gimple-call-expression + gimple-assign-statement + gimple-phi-statement + + gimple-assign-statement: + gimple-unary-expression = gimple-assign-rhs + + gimple-assign-rhs: + gimple-cast-expression + gimple-unary-expression + gimple-binary-expression + gimple-call-expression + + gimple-phi-statement: + identifier = __PHI ( label : gimple_primary-expression, ... ) + + gimple-call-expr: + gimple-primary-expression ( argument-list ) + + gimple-cast-expression: + ( type-name ) gimple-primary-expression + +*/ + +static void +c_parser_gimple_statement (gimple_parser &parser, gimple_seq *seq) +{ + struct c_expr lhs, rhs; + gimple *assign = NULL; + location_t loc; + tree arg = NULL_TREE; + auto_vec vargs; + + lhs = c_parser_gimple_unary_expression (parser); + loc = EXPR_LOCATION (lhs.value); + rhs.set_error (); + + /* GIMPLE call statement without LHS. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + && TREE_CODE (lhs.value) == CALL_EXPR) + { + gimple *call; + call = gimple_build_call_from_tree (lhs.value, NULL); + gimple_seq_add_stmt_without_update (seq, call); + gimple_set_location (call, loc); + return; + } + + /* All following cases are statements with LHS. */ + if (! c_parser_require (parser, CPP_EQ, "expected %<=%>")) + return; + + /* Cast expression. */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + c_parser_consume_token (parser); + struct c_type_name *type_name = c_parser_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (type_name == NULL) + return; + /* ??? The actual type used in the cast expression is ignored as + in GIMPLE it is encoded by the type of the LHS. */ + rhs = c_parser_gimple_postfix_expression (parser); + if (lhs.value != error_mark_node + && rhs.value != error_mark_node) + { + enum tree_code code = NOP_EXPR; + if (FLOAT_TYPE_P (TREE_TYPE (lhs.value)) + && ! FLOAT_TYPE_P (TREE_TYPE (rhs.value))) + code = FLOAT_EXPR; + else if (! FLOAT_TYPE_P (TREE_TYPE (lhs.value)) + && FLOAT_TYPE_P (TREE_TYPE (rhs.value))) + code = FIX_TRUNC_EXPR; + assign = gimple_build_assign (lhs.value, code, rhs.value); + gimple_seq_add_stmt_without_update (seq, assign); + gimple_set_location (assign, loc); + return; + } + } + + /* Unary expression. */ + switch (c_parser_peek_token (parser)->type) + { + case CPP_NAME: + { + tree id = c_parser_peek_token (parser)->value; + if (strcmp (IDENTIFIER_POINTER (id), "__ABS") == 0 + || strcmp (IDENTIFIER_POINTER (id), "__ABSU") == 0 + || strcmp (IDENTIFIER_POINTER (id), "__MIN") == 0 + || strcmp (IDENTIFIER_POINTER (id), "__MAX") == 0 + || strcmp (IDENTIFIER_POINTER (id), "__BIT_INSERT") == 0 + || strcmp (IDENTIFIER_POINTER (id), "__VEC_PERM") == 0) + goto build_unary_expr; + break; + } + case CPP_KEYWORD: + if (c_parser_peek_token (parser)->keyword != RID_REALPART + && c_parser_peek_token (parser)->keyword != RID_IMAGPART) + break; + /* Fallthru. */ + case CPP_AND: + case CPP_PLUS: + case CPP_MINUS: + case CPP_COMPL: + case CPP_NOT: + case CPP_MULT: /* pointer deref */ + build_unary_expr: + rhs = c_parser_gimple_unary_expression (parser); + if (rhs.value != error_mark_node) + { + assign = gimple_build_assign (lhs.value, rhs.value); + gimple_set_location (assign, loc); + gimple_seq_add_stmt_without_update (seq, assign); + } + return; + + default:; + } + + /* GIMPLE PHI statement. */ + if (c_parser_next_token_is_keyword (parser, RID_PHI)) + { + c_parser_consume_token (parser); + + if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return; + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + c_parser_consume_token (parser); + + while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + arg = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COLON)) + c_parser_consume_token (parser); + int src_index = -1; + if (!c_parser_gimple_parse_bb_spec (arg, &src_index)) + c_parser_error (parser, "invalid source block specification"); + vargs.safe_push (size_int (src_index)); + } + else if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + { + arg = c_parser_gimple_unary_expression (parser).value; + vargs.safe_push (arg); + } + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + + /* Build internal function for PHI. */ + gcall *call_stmt = gimple_build_call_internal_vec (IFN_PHI, vargs); + gimple_call_set_lhs (call_stmt, lhs.value); + gimple_set_location (call_stmt, UNKNOWN_LOCATION); + gimple_seq_add_stmt_without_update (seq, call_stmt); + return; + } + + /* GIMPLE call with lhs. */ + if (c_parser_next_token_is (parser, CPP_DOT) + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN + && lookup_name (c_parser_peek_token (parser)->value))) + { + rhs = c_parser_gimple_unary_expression (parser); + if (rhs.value != error_mark_node) + { + gimple *call = gimple_build_call_from_tree (rhs.value, NULL); + gimple_call_set_lhs (call, lhs.value); + gimple_seq_add_stmt_without_update (seq, call); + gimple_set_location (call, loc); + } + return; + } + + rhs = c_parser_gimple_binary_expression (parser); + if (lhs.value != error_mark_node + && rhs.value != error_mark_node) + { + /* If we parsed a comparison and the next token is a '?' then + parse a conditional expression. */ + if (COMPARISON_CLASS_P (rhs.value) + && c_parser_next_token_is (parser, CPP_QUERY)) + { + struct c_expr trueval, falseval; + c_parser_consume_token (parser); + trueval = c_parser_gimple_postfix_expression (parser); + falseval.set_error (); + if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) + falseval = c_parser_gimple_postfix_expression (parser); + if (trueval.value == error_mark_node + || falseval.value == error_mark_node) + return; + rhs.value = build3_loc (loc, COND_EXPR, TREE_TYPE (trueval.value), + rhs.value, trueval.value, falseval.value); + } + if (get_gimple_rhs_class (TREE_CODE (rhs.value)) == GIMPLE_INVALID_RHS) + { + c_parser_error (parser, "unexpected RHS for assignment"); + return; + } + assign = gimple_build_assign (lhs.value, rhs.value); + gimple_seq_add_stmt_without_update (seq, assign); + gimple_set_location (assign, loc); + } + return; +} + +/* Parse gimple binary expr. + + gimple-binary-expression: + gimple-unary-expression * gimple-unary-expression + gimple-unary-expression __MULT_HIGHPART gimple-unary-expression + gimple-unary-expression / gimple-unary-expression + gimple-unary-expression % gimple-unary-expression + gimple-unary-expression + gimple-unary-expression + gimple-unary-expression - gimple-unary-expression + gimple-unary-expression << gimple-unary-expression + gimple-unary-expression >> gimple-unary-expression + gimple-unary-expression < gimple-unary-expression + gimple-unary-expression > gimple-unary-expression + gimple-unary-expression <= gimple-unary-expression + gimple-unary-expression >= gimple-unary-expression + gimple-unary-expression == gimple-unary-expression + gimple-unary-expression != gimple-unary-expression + gimple-unary-expression & gimple-unary-expression + gimple-unary-expression ^ gimple-unary-expression + gimple-unary-expression | gimple-unary-expression + +*/ + +static c_expr +c_parser_gimple_binary_expression (gimple_parser &parser) +{ + /* Location of the binary operator. */ + struct c_expr ret, lhs, rhs; + enum tree_code code = ERROR_MARK; + ret.set_error (); + lhs = c_parser_gimple_postfix_expression (parser); + if (c_parser_error (parser)) + return ret; + tree ret_type = TREE_TYPE (lhs.value); + switch (c_parser_peek_token (parser)->type) + { + case CPP_MULT: + code = MULT_EXPR; + break; + case CPP_DIV: + code = TRUNC_DIV_EXPR; + break; + case CPP_MOD: + code = TRUNC_MOD_EXPR; + break; + case CPP_PLUS: + if (POINTER_TYPE_P (TREE_TYPE (lhs.value))) + code = POINTER_PLUS_EXPR; + else + code = PLUS_EXPR; + break; + case CPP_MINUS: + code = MINUS_EXPR; + break; + case CPP_LSHIFT: + code = LSHIFT_EXPR; + break; + case CPP_RSHIFT: + code = RSHIFT_EXPR; + break; + case CPP_LESS: + code = LT_EXPR; + ret_type = boolean_type_node; + break; + case CPP_GREATER: + code = GT_EXPR; + ret_type = boolean_type_node; + break; + case CPP_LESS_EQ: + code = LE_EXPR; + ret_type = boolean_type_node; + break; + case CPP_GREATER_EQ: + code = GE_EXPR; + ret_type = boolean_type_node; + break; + case CPP_EQ_EQ: + code = EQ_EXPR; + ret_type = boolean_type_node; + break; + case CPP_NOT_EQ: + code = NE_EXPR; + ret_type = boolean_type_node; + break; + case CPP_AND: + code = BIT_AND_EXPR; + break; + case CPP_XOR: + code = BIT_XOR_EXPR; + break; + case CPP_OR: + code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + c_parser_error (parser, "%<&&%> not valid in GIMPLE"); + return ret; + case CPP_OR_OR: + c_parser_error (parser, "%<||%> not valid in GIMPLE"); + return ret; + case CPP_NAME: + { + tree id = c_parser_peek_token (parser)->value; + if (strcmp (IDENTIFIER_POINTER (id), "__MULT_HIGHPART") == 0) + { + code = MULT_HIGHPART_EXPR; + break; + } + } + /* Fallthru. */ + default: + /* Not a binary expression. */ + return lhs; + } + location_t ret_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + rhs = c_parser_gimple_postfix_expression (parser); + if (lhs.value != error_mark_node && rhs.value != error_mark_node) + ret.value = build2_loc (ret_loc, code, ret_type, lhs.value, rhs.value); + return ret; +} + +/* Parse a gimple parentized binary expression. */ + +static c_expr +c_parser_gimple_parentized_binary_expression (gimple_parser &parser, + location_t op_loc, + tree_code code) +{ + struct c_expr ret; + ret.set_error (); + + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return ret; + c_expr op1 = c_parser_gimple_postfix_expression (parser); + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + return ret; + c_expr op2 = c_parser_gimple_postfix_expression (parser); + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return ret; + + if (op1.value != error_mark_node && op2.value != error_mark_node) + ret.value = build2_loc (op_loc, + code, TREE_TYPE (op1.value), op1.value, op2.value); + return ret; +} + +/* Parse a gimple parentized binary expression. */ + +static c_expr +c_parser_gimple_parentized_ternary_expression (gimple_parser &parser, + location_t op_loc, + tree_code code) +{ + struct c_expr ret; + ret.set_error (); + + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return ret; + c_expr op1 = c_parser_gimple_postfix_expression (parser); + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + return ret; + c_expr op2 = c_parser_gimple_postfix_expression (parser); + if (!c_parser_require (parser, CPP_COMMA, "expected %<)%>")) + return ret; + c_expr op3 = c_parser_gimple_postfix_expression (parser); + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return ret; + + if (op1.value != error_mark_node + && op2.value != error_mark_node + && op3.value != error_mark_node) + ret.value = build3_loc (op_loc, + code, TREE_TYPE (op1.value), + op1.value, op2.value, op3.value); + return ret; +} + +/* Parse gimple unary expression. + + gimple-unary-expression: + gimple-postfix-expression + unary-operator gimple-postfix-expression + + unary-operator: one of + & * + - ~ abs_expr +*/ + +static c_expr +c_parser_gimple_unary_expression (gimple_parser &parser) +{ + struct c_expr ret, op; + location_t op_loc = c_parser_peek_token (parser)->location; + location_t finish; + ret.set_error (); + switch (c_parser_peek_token (parser)->type) + { + case CPP_AND: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + mark_exp_read (op.value); + return parser_build_unary_op (op_loc, ADDR_EXPR, op); + case CPP_MULT: + { + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + if (op.value == error_mark_node) + return ret; + if (! POINTER_TYPE_P (TREE_TYPE (op.value))) + { + error_at (op_loc, "expected pointer as argument of unary %<*%>"); + return ret; + } + finish = op.get_finish (); + location_t combined_loc = make_location (op_loc, op_loc, finish); + ret.value = build_simple_mem_ref_loc (combined_loc, op.value); + TREE_SIDE_EFFECTS (ret.value) + = TREE_THIS_VOLATILE (ret.value) + = TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op.value))); + ret.src_range.m_start = op_loc; + ret.src_range.m_finish = finish; + return ret; + } + case CPP_PLUS: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, CONVERT_EXPR, op); + case CPP_MINUS: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, NEGATE_EXPR, op); + case CPP_COMPL: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); + case CPP_NOT: + c_parser_error (parser, "% not valid in GIMPLE"); + return ret; + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_REALPART: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, REALPART_EXPR, op); + case RID_IMAGPART: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); + default: + return c_parser_gimple_postfix_expression (parser); + } + case CPP_NAME: + { + tree id = c_parser_peek_token (parser)->value; + if (strcmp (IDENTIFIER_POINTER (id), "__ABS") == 0) + { + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, ABS_EXPR, op); + } + else if (strcmp (IDENTIFIER_POINTER (id), "__ABSU") == 0) + { + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, ABSU_EXPR, op); + } + else if (strcmp (IDENTIFIER_POINTER (id), "__MIN") == 0) + return c_parser_gimple_parentized_binary_expression (parser, + op_loc, + MIN_EXPR); + else if (strcmp (IDENTIFIER_POINTER (id), "__MAX") == 0) + return c_parser_gimple_parentized_binary_expression (parser, + op_loc, + MAX_EXPR); + else if (strcmp (IDENTIFIER_POINTER (id), "__VEC_PERM") == 0) + return c_parser_gimple_parentized_ternary_expression + (parser, op_loc, VEC_PERM_EXPR); + else if (strcmp (IDENTIFIER_POINTER (id), "__BIT_INSERT") == 0) + { + /* __BIT_INSERT '(' postfix-expression, postfix-expression, + integer ')' */ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + c_expr op0 = c_parser_gimple_postfix_expression (parser); + c_parser_skip_until_found (parser, CPP_COMMA, + "expected %<,%>"); + c_expr op1 = c_parser_gimple_postfix_expression (parser); + c_parser_skip_until_found (parser, CPP_COMMA, + "expected %<,%>"); + c_expr op2 = c_parser_gimple_postfix_expression (parser); + if (TREE_CODE (op2.value) != INTEGER_CST + || !int_fits_type_p (op2.value, bitsizetype)) + c_parser_error (parser, "expected constant offset"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + if (op0.value != error_mark_node + && op1.value != error_mark_node + && TREE_CODE (op2.value) == INTEGER_CST) + ret.value = build3_loc (loc, BIT_INSERT_EXPR, + TREE_TYPE (op0.value), + op0.value, op1.value, + fold_convert (bitsizetype, + op2.value)); + } + return ret; + } + else + return c_parser_gimple_postfix_expression (parser); + } + default: + return c_parser_gimple_postfix_expression (parser); + } +} + +/* Decompose ID into base name (ID until ver_offset) and VERSION. Return + true if ID matches a SSA name. */ + +static bool +c_parser_parse_ssa_name_id (tree id, unsigned *version, unsigned *ver_offset) +{ + const char *token = IDENTIFIER_POINTER (id); + const char *var_version = strrchr (token, '_'); + if (! var_version) + return false; + + *ver_offset = var_version - token; + for (const char *p = var_version + 1; *p; ++p) + if (! ISDIGIT (*p)) + return false; + *version = atoi (var_version + 1); + return *version > 0; +} + +/* Get at the actual SSA name ID with VERSION starting at VER_OFFSET. + TYPE is the type if the SSA name is being declared. */ + +static tree +c_parser_parse_ssa_name (gimple_parser &parser, + tree id, tree type, unsigned version, + unsigned ver_offset) +{ + tree name = NULL_TREE; + const char *token = IDENTIFIER_POINTER (id); + + if (ver_offset == 0) + { + /* Anonymous unnamed SSA name. */ + if (version < num_ssa_names) + name = ssa_name (version); + if (! name) + { + if (! type) + { + c_parser_error (parser, "SSA name undeclared"); + return error_mark_node; + } + name = make_ssa_name_fn (cfun, type, NULL, version); + } + } + else + { + if (version < num_ssa_names) + name = ssa_name (version); + if (! name) + { + /* Separate var name from version. */ + char *var_name = XNEWVEC (char, ver_offset + 1); + memcpy (var_name, token, ver_offset); + var_name[ver_offset] = '\0'; + /* lookup for parent decl. */ + id = get_identifier (var_name); + tree parent = lookup_name (id); + XDELETEVEC (var_name); + if (! parent || parent == error_mark_node) + { + c_parser_error (parser, "base variable or SSA name undeclared"); + return error_mark_node; + } + if (!(VAR_P (parent) + || TREE_CODE (parent) == PARM_DECL + || TREE_CODE (parent) == RESULT_DECL)) + { + error ("invalid base %qE for SSA name", parent); + return error_mark_node; + } + name = make_ssa_name_fn (cfun, parent, + gimple_build_nop (), version); + } + } + + return name; +} + +/* Parse a gimple call to an internal function. + + gimple-call-internal: + . identifier ( gimple-argument-expression-list[opt] ) */ + +static struct c_expr +c_parser_gimple_call_internal (gimple_parser &parser) +{ + struct c_expr expr; + expr.set_error (); + + gcc_assert (c_parser_next_token_is (parser, CPP_DOT)); + c_parser_consume_token (parser); + location_t loc = c_parser_peek_token (parser)->location; + if (!c_parser_next_token_is (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + c_parser_error (parser, "expecting internal function name"); + return expr; + } + tree id = c_parser_peek_token (parser)->value; + internal_fn ifn = lookup_internal_fn (IDENTIFIER_POINTER (id)); + c_parser_consume_token (parser); + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + auto_vec exprlist; + if (!c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_gimple_expr_list (parser, &exprlist); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (ifn == IFN_LAST) + error_at (loc, "unknown internal function %qE", id); + else + { + expr.value = build_call_expr_internal_loc_array + (loc, ifn, void_type_node, exprlist.length (), + exprlist.address ()); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + } + } + return expr; +} + +/* Parse '<' type [',' alignment] '>' and return a type on success + and NULL_TREE on error. */ + +static tree +c_parser_gimple_typespec (gimple_parser &parser) +{ + struct c_type_name *type_name = NULL; + tree alignment = NULL_TREE; + if (c_parser_require (parser, CPP_LESS, "expected %<<%>")) + { + type_name = c_parser_type_name (parser); + /* Optional alignment. */ + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + alignment + = c_parser_gimple_postfix_expression (parser).value; + } + c_parser_skip_until_found (parser, + CPP_GREATER, "expected %<>%>"); + } + if (!type_name) + return NULL_TREE; + tree tem; + tree type = groktypename (type_name, &tem, NULL); + if (alignment) + type = build_aligned_type (type, tree_to_uhwi (alignment)); + return type; +} + +/* Parse gimple postfix expression. + + gimple-postfix-expression: + gimple-primary-expression + gimple-primary-expression [ gimple-primary-expression ] + gimple-primary-expression ( gimple-argument-expression-list[opt] ) + gimple-postfix-expression . identifier + gimple-postfix-expression -> identifier + + gimple-argument-expression-list: + gimple-unary-expression + gimple-argument-expression-list , gimple-unary-expression + + gimple-primary-expression: + identifier + constant + string-literal + constructor + gimple-call-internal + +*/ + +static struct c_expr +c_parser_gimple_postfix_expression (gimple_parser &parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + source_range tok_range = c_parser_peek_token (parser)->get_range (); + struct c_expr expr; + expr.set_error (); + switch (c_parser_peek_token (parser)->type) + { + case CPP_NUMBER: + expr.value = c_parser_peek_token (parser)->value; + set_c_expr_source_range (&expr, tok_range); + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + break; + case CPP_CHAR: + case CPP_CHAR16: + case CPP_CHAR32: + case CPP_UTF8CHAR: + case CPP_WCHAR: + expr.value = c_parser_peek_token (parser)->value; + set_c_expr_source_range (&expr, tok_range); + c_parser_consume_token (parser); + break; + case CPP_STRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_WSTRING: + case CPP_UTF8STRING: + expr = c_parser_string_literal (parser, false, true); + break; + case CPP_DOT: + expr = c_parser_gimple_call_internal (parser); + break; + case CPP_NAME: + if (c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + tree id = c_parser_peek_token (parser)->value; + if (strcmp (IDENTIFIER_POINTER (id), "__MEM") == 0) + { + /* __MEM '<' type-name [ ',' number ] '>' + '(' [ '(' type-name ')' ] unary-expression + [ '+' number ] ')' */ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + tree type = c_parser_gimple_typespec (parser); + struct c_expr ptr; + ptr.value = error_mark_node; + tree alias_off = NULL_TREE; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + tree alias_type = NULL_TREE; + /* Optional alias-type cast. */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + struct c_type_name *alias_type_name + = c_parser_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + if (alias_type_name) + { + tree tem; + alias_type = groktypename (alias_type_name, + &tem, NULL); + } + } + ptr = c_parser_gimple_unary_expression (parser); + if (ptr.value == error_mark_node + || ! POINTER_TYPE_P (TREE_TYPE (ptr.value))) + { + if (ptr.value != error_mark_node) + error_at (ptr.get_start (), + "invalid type of %<__MEM%> operand"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return expr; + } + if (! alias_type) + alias_type = TREE_TYPE (ptr.value); + /* Optional constant offset. */ + if (c_parser_next_token_is (parser, CPP_PLUS)) + { + c_parser_consume_token (parser); + alias_off + = c_parser_gimple_postfix_expression (parser).value; + alias_off = fold_convert (alias_type, alias_off); + } + if (! alias_off) + alias_off = build_int_cst (alias_type, 0); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + } + if (! type || c_parser_error (parser)) + { + c_parser_set_error (parser, false); + return expr; + } + expr.value = build2_loc (loc, MEM_REF, + type, ptr.value, alias_off); + break; + } + else if (strcmp (IDENTIFIER_POINTER (id), "__VIEW_CONVERT") == 0) + { + /* __VIEW_CONVERT '<' type-name [ ',' number ] '>' + '(' postfix-expression ')' */ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + tree type = c_parser_gimple_typespec (parser); + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + c_expr op = c_parser_gimple_postfix_expression (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + if (type && op.value != error_mark_node) + expr.value = build1_loc (loc, VIEW_CONVERT_EXPR, + type, op.value); + } + break; + } + else if (strcmp (IDENTIFIER_POINTER (id), "__BIT_FIELD_REF") == 0) + { + /* __BIT_FIELD_REF '<' type-name [ ',' number ] '>' + '(' postfix-expression, integer, integer ')' */ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + tree type = c_parser_gimple_typespec (parser); + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + c_expr op0 = c_parser_gimple_postfix_expression (parser); + c_parser_skip_until_found (parser, CPP_COMMA, + "expected %<,%>"); + c_expr op1 = c_parser_gimple_postfix_expression (parser); + if (TREE_CODE (op1.value) != INTEGER_CST + || !int_fits_type_p (op1.value, bitsizetype)) + c_parser_error (parser, "expected constant size"); + c_parser_skip_until_found (parser, CPP_COMMA, + "expected %<,%>"); + c_expr op2 = c_parser_gimple_postfix_expression (parser); + if (TREE_CODE (op2.value) != INTEGER_CST + || !int_fits_type_p (op2.value, bitsizetype)) + c_parser_error (parser, "expected constant offset"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + if (type + && op0.value != error_mark_node + && TREE_CODE (op1.value) == INTEGER_CST + && TREE_CODE (op2.value) == INTEGER_CST) + expr.value = build3_loc (loc, BIT_FIELD_REF, type, + op0.value, + fold_convert (bitsizetype, + op1.value), + fold_convert (bitsizetype, + op2.value)); + } + break; + } + else if (strcmp (IDENTIFIER_POINTER (id), "_Literal") == 0) + { + /* _Literal '(' type-name ')' ( [ '-' ] constant | constructor ) */ + c_parser_consume_token (parser); + tree type = NULL_TREE; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + struct c_type_name *type_name = c_parser_type_name (parser); + tree tem; + if (type_name) + type = groktypename (type_name, &tem, NULL); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + } + if (! type) + { + c_parser_error (parser, "invalid _Literal"); + return expr; + } + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + c_parser_consume_token (parser); + if (!AGGREGATE_TYPE_P (type) + && !VECTOR_TYPE_P (type)) + { + c_parser_error (parser, "invalid type for _Literal with " + "constructor"); + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, + "expected %<}%>"); + return expr; + } + vec *v = NULL; + bool constant_p = true; + if (VECTOR_TYPE_P (type) + && !c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + vec_alloc (v, TYPE_VECTOR_SUBPARTS (type).to_constant ()); + do + { + tree val + = c_parser_gimple_postfix_expression (parser).value; + if (! val + || val == error_mark_node + || (! CONSTANT_CLASS_P (val) + && ! SSA_VAR_P (val))) + { + c_parser_error (parser, "invalid _Literal"); + return expr; + } + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, val); + if (! CONSTANT_CLASS_P (val)) + constant_p = false; + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + while (1); + } + if (c_parser_require (parser, CPP_CLOSE_BRACE, + "expected %<}%>")) + { + if (v && constant_p) + expr.value = build_vector_from_ctor (type, v); + else + expr.value = build_constructor (type, v); + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, + "expected %<}%>"); + return expr; + } + } + else + { + bool neg_p, addr_p; + if ((neg_p = c_parser_next_token_is (parser, CPP_MINUS))) + c_parser_consume_token (parser); + if ((addr_p = c_parser_next_token_is (parser, CPP_AND))) + c_parser_consume_token (parser); + tree val = c_parser_gimple_postfix_expression (parser).value; + if (! val + || val == error_mark_node + || (!CONSTANT_CLASS_P (val) && !addr_p)) + { + c_parser_error (parser, "invalid _Literal"); + return expr; + } + if (addr_p) + { + val = build1 (ADDR_EXPR, type, val); + if (!is_gimple_invariant_address (val)) + { + c_parser_error (parser, "invalid _Literal"); + return expr; + } + } + if (neg_p) + { + val = const_unop (NEGATE_EXPR, TREE_TYPE (val), val); + if (! val) + { + c_parser_error (parser, "invalid _Literal"); + return expr; + } + } + expr.value = fold_convert (type, val); + } + return expr; + } + + /* SSA name. */ + unsigned version, ver_offset; + if (! lookup_name (id) + && c_parser_parse_ssa_name_id (id, &version, &ver_offset)) + { + c_parser_consume_token (parser); + expr.value = c_parser_parse_ssa_name (parser, id, NULL_TREE, + version, ver_offset); + if (expr.value == error_mark_node) + return expr; + set_c_expr_source_range (&expr, tok_range); + /* For default definition SSA names. */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME + && strcmp ("D", + IDENTIFIER_POINTER + (c_parser_peek_2nd_token (parser)->value)) == 0 + && c_parser_peek_nth_token (parser, 3)->type == CPP_CLOSE_PAREN) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + c_parser_consume_token (parser); + if (! SSA_NAME_IS_DEFAULT_DEF (expr.value)) + { + if (!SSA_NAME_VAR (expr.value)) + { + error_at (loc, "anonymous SSA name cannot have" + " default definition"); + expr.value = error_mark_node; + return expr; + } + set_ssa_default_def (cfun, SSA_NAME_VAR (expr.value), + expr.value); + SSA_NAME_DEF_STMT (expr.value) = gimple_build_nop (); + } + } + } + else + { + c_parser_consume_token (parser); + expr.value + = build_external_ref (loc, id, + (c_parser_peek_token (parser)->type + == CPP_OPEN_PAREN), &expr.original_type); + set_c_expr_source_range (&expr, tok_range); + } + break; + } + /* Fallthru. */ + default: + c_parser_error (parser, "expected expression"); + expr.set_error (); + break; + } + if (expr.value == error_mark_node) + return expr; + return c_parser_gimple_postfix_expression_after_primary + (parser, EXPR_LOC_OR_LOC (expr.value, loc), expr); +} + +/* Parse a gimple postfix expression after the initial primary or compound + literal. */ + +static struct c_expr +c_parser_gimple_postfix_expression_after_primary (gimple_parser &parser, + location_t expr_loc, + struct c_expr expr) +{ + location_t start; + location_t finish; + tree ident; + location_t comp_loc; + + while (true) + { + location_t op_loc = c_parser_peek_token (parser)->location; + switch (c_parser_peek_token (parser)->type) + { + case CPP_OPEN_SQUARE: + { + c_parser_consume_token (parser); + tree idx = c_parser_gimple_unary_expression (parser).value; + + if (! c_parser_require (parser, CPP_CLOSE_SQUARE, "expected %<]%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL); + break; + } + + start = expr.get_start (); + finish = c_parser_tokens_buf (parser, 0)->location; + expr.value = build_array_ref (op_loc, expr.value, idx); + set_c_expr_source_range (&expr, start, finish); + + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + break; + } + case CPP_OPEN_PAREN: + { + /* Function call. */ + c_parser_consume_token (parser); + auto_vec exprlist; + if (! c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_gimple_expr_list (parser, &exprlist); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + if (!FUNC_OR_METHOD_TYPE_P (TREE_TYPE (expr.value))) + { + c_parser_error (parser, "invalid call to non-function"); + expr.set_error (); + break; + } + expr.value = build_call_array_loc + (expr_loc, TREE_TYPE (TREE_TYPE (expr.value)), + expr.value, exprlist.length (), exprlist.address ()); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + break; + } + case CPP_DOT: + { + /* Structure element reference. */ + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *comp_tok = c_parser_peek_token (parser); + ident = comp_tok->value; + comp_loc = comp_tok->location; + } + else + { + c_parser_error (parser, "expected identifier"); + expr.set_error (); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + return expr; + } + start = expr.get_start (); + finish = c_parser_peek_token (parser)->get_finish (); + c_parser_consume_token (parser); + expr.value = build_component_ref (op_loc, expr.value, ident, + comp_loc); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } + break; + } + case CPP_DEREF: + { + /* Structure element reference. */ + if (!POINTER_TYPE_P (TREE_TYPE (expr.value))) + { + c_parser_error (parser, "dereference of non-pointer"); + expr.set_error (); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + return expr; + } + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *comp_tok = c_parser_peek_token (parser); + ident = comp_tok->value; + comp_loc = comp_tok->location; + } + else + { + c_parser_error (parser, "expected identifier"); + expr.set_error (); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + return expr; + } + start = expr.get_start (); + finish = c_parser_peek_token (parser)->get_finish (); + c_parser_consume_token (parser); + expr.value = build_component_ref (op_loc, + build_simple_mem_ref_loc + (op_loc, expr.value), + ident, comp_loc); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } + break; + } + default: + return expr; + } + } +} + +/* Parse expression list. + + gimple-expr-list: + gimple-unary-expression + gimple-expr-list , gimple-unary-expression + + */ + +static void +c_parser_gimple_expr_list (gimple_parser &parser, vec *ret) +{ + struct c_expr expr; + + expr = c_parser_gimple_unary_expression (parser); + ret->safe_push (expr.value); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + expr = c_parser_gimple_unary_expression (parser); + ret->safe_push (expr.value); + } +} + +/* Parse gimple label. + + gimple-label: + identifier : + case constant-expression : + default : + +*/ + +static void +c_parser_gimple_label (gimple_parser &parser, gimple_seq *seq) +{ + tree name = c_parser_peek_token (parser)->value; + location_t loc1 = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is (parser, CPP_NAME)); + c_parser_consume_token (parser); + gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); + c_parser_consume_token (parser); + tree label = define_label (loc1, name); + if (label) + gimple_seq_add_stmt_without_update (seq, gimple_build_label (label)); + return; +} + +/* Parse gimple/RTL pass list. + + gimple-or-rtl-pass-list: + startwith("pass-name")[,{cfg,ssa}] + */ + +void +c_parser_gimple_or_rtl_pass_list (c_parser *parser, c_declspecs *specs) +{ + char *pass = NULL; + + /* Accept __GIMPLE/__RTL. */ + if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) + return; + c_parser_consume_token (parser); + + specs->entry_bb_count = profile_count::uninitialized (); + while (c_parser_next_token_is (parser, CPP_NAME)) + { + profile_quality quality; + const char *op = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + if (! strcmp (op, "startwith")) + { + if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return; + if (c_parser_next_token_is_not (parser, CPP_STRING)) + { + error_at (c_parser_peek_token (parser)->location, + "expected pass name"); + return; + } + pass = xstrdup (TREE_STRING_POINTER + (c_parser_string_literal (parser, false, + false).value)); + if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<(%>")) + return; + } + else if (parse_profile_quality (op, &quality)) + { + tree q; + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return; + + if (!c_parser_next_token_is (parser, CPP_NUMBER) + || (TREE_CODE (q = c_parser_peek_token (parser)->value) + != INTEGER_CST)) + { + c_parser_error (parser, "expected count value"); + return; + } + + specs->entry_bb_count + = profile_count::from_gcov_type (TREE_INT_CST_LOW (q), quality); + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return; + } + else if (specs->declspec_il != cdil_gimple) + /* Allow only one IL specifier and none on RTL. */ + ; + else if (! strcmp (op, "cfg")) + specs->declspec_il = cdil_gimple_cfg; + else if (! strcmp (op, "ssa")) + specs->declspec_il = cdil_gimple_ssa; + else + { + error_at (c_parser_peek_token (parser)->location, + "invalid operation"); + return; + } + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + } + + if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return; + + specs->gimple_or_rtl_pass = pass; +} + +/* Parse gimple local declaration. + + declaration-specifiers: + storage-class-specifier declaration-specifiers[opt] + type-specifier declaration-specifiers[opt] + type-qualifier declaration-specifiers[opt] + function-specifier declaration-specifiers[opt] + alignment-specifier declaration-specifiers[opt] + + storage-class-specifier: + typedef + extern + static + auto + register + + type-specifier: + void + char + short + int + long + float + double + signed + unsigned + _Bool + _Complex + + type-qualifier: + const + restrict + volatile + address-space-qualifier + _Atomic + + */ + +static void +c_parser_gimple_declaration (gimple_parser &parser) +{ + struct c_declarator *declarator; + struct c_declspecs *specs = build_null_declspecs (); + c_parser_declspecs (parser, specs, true, true, true, + true, true, true, true, cla_nonabstract_decl); + finish_declspecs (specs); + + /* Provide better error recovery. Note that a type name here is usually + better diagnosed as a redeclaration. */ + if (c_parser_next_token_starts_declspecs (parser) + && ! c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %<;%>"); + c_parser_set_error (parser, false); + return; + } + + bool dummy = false; + declarator = c_parser_declarator (parser, + specs->typespec_kind != ctsk_none, + C_DTR_NORMAL, &dummy); + + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + /* Handle SSA name decls specially, they do not go into the identifier + table but we simply build the SSA name for later lookup. */ + unsigned version, ver_offset; + if (declarator->kind == cdk_id + && is_gimple_reg_type (specs->type) + && c_parser_parse_ssa_name_id (declarator->u.id.id, + &version, &ver_offset) + /* The following restricts it to unnamed anonymous SSA names + which fails parsing of named ones in dumps (we could + decide to not dump their name for -gimple). */ + && ver_offset == 0) + c_parser_parse_ssa_name (parser, declarator->u.id.id, specs->type, + version, ver_offset); + else + { + tree postfix_attrs = NULL_TREE; + tree all_prefix_attrs = specs->attrs; + specs->attrs = NULL; + tree decl = start_decl (declarator, specs, false, + chainon (postfix_attrs, all_prefix_attrs)); + if (decl) + finish_decl (decl, UNKNOWN_LOCATION, NULL_TREE, NULL_TREE, + NULL_TREE); + } + } + else + { + c_parser_error (parser, "expected %<;%>"); + return; + } +} + +/* Parse gimple goto statement. */ + +static void +c_parser_gimple_goto_stmt (gimple_parser &parser, + location_t loc, tree label, gimple_seq *seq) +{ + if (cfun->curr_properties & PROP_cfg) + { + int dest_index; + profile_probability prob; + if (c_parser_gimple_parse_bb_spec_edge_probability (label, parser, + &dest_index, &prob)) + { + parser.push_edge (parser.current_bb->index, dest_index, + EDGE_FALLTHRU, prob); + return; + } + } + tree decl = lookup_label_for_goto (loc, label); + gimple_seq_add_stmt_without_update (seq, gimple_build_goto (decl)); +} + +/* Parse a parenthesized condition. + gimple-condition: + ( gimple-binary-expression ) */ + +static tree +c_parser_gimple_paren_condition (gimple_parser &parser) +{ + if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return error_mark_node; + tree cond = c_parser_gimple_binary_expression (parser).value; + if (cond != error_mark_node + && ! COMPARISON_CLASS_P (cond) + && ! CONSTANT_CLASS_P (cond) + && ! SSA_VAR_P (cond)) + { + c_parser_error (parser, "comparison required"); + cond = error_mark_node; + } + if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return error_mark_node; + return cond; +} + +/* Parse gimple try statement. + + try-statement: + try { ... } finally { ... } + try { ... } finally { ... } else { ... } + + This could support try/catch as well, but it's not implemented yet. + */ + +static void +c_parser_gimple_try_stmt (gimple_parser &parser, gimple_seq *seq) +{ + gimple_seq tryseq = NULL; + c_parser_consume_token (parser); + c_parser_gimple_compound_statement (parser, &tryseq); + + if ((c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_AT_FINALLY) + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "finally") == 0)) + { + gimple_seq finseq = NULL; + c_parser_consume_token (parser); + c_parser_gimple_compound_statement (parser, &finseq); + + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_ELSE) + { + gimple_seq elsseq = NULL; + c_parser_consume_token (parser); + c_parser_gimple_compound_statement (parser, &elsseq); + + geh_else *stmt = gimple_build_eh_else (finseq, elsseq); + finseq = NULL; + gimple_seq_add_stmt_without_update (&finseq, stmt); + } + + gtry *stmt = gimple_build_try (tryseq, finseq, GIMPLE_TRY_FINALLY); + gimple_seq_add_stmt_without_update (seq, stmt); + } + else if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_AT_CATCH) + c_parser_error (parser, "% is not supported"); + else + c_parser_error (parser, "expected % or %"); +} + +/* Parse gimple if-else statement. + + if-statement: + if ( gimple-binary-expression ) gimple-goto-statement + if ( gimple-binary-expression ) gimple-goto-statement \ + else gimple-goto-statement + */ + +static void +c_parser_gimple_if_stmt (gimple_parser &parser, gimple_seq *seq) +{ + tree t_label = NULL_TREE, f_label = NULL_TREE, label; + location_t loc; + c_parser_consume_token (parser); + tree cond = c_parser_gimple_paren_condition (parser); + + if (c_parser_next_token_is_keyword (parser, RID_GOTO)) + { + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (! c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected label"); + return; + } + label = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + int dest_index; + profile_probability prob; + if ((cfun->curr_properties & PROP_cfg) + && c_parser_gimple_parse_bb_spec_edge_probability (label, parser, + &dest_index, &prob)) + parser.push_edge (parser.current_bb->index, dest_index, + EDGE_TRUE_VALUE, prob); + else + t_label = lookup_label_for_goto (loc, label); + if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + return; + } + else + { + c_parser_error (parser, "expected goto expression"); + return; + } + + if (c_parser_next_token_is_keyword (parser, RID_ELSE)) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "expected else statement"); + return; + } + + if (c_parser_next_token_is_keyword (parser, RID_GOTO)) + { + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (! c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected label"); + return; + } + label = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + int dest_index; + profile_probability prob; + if ((cfun->curr_properties & PROP_cfg) + && c_parser_gimple_parse_bb_spec_edge_probability (label, parser, + &dest_index, &prob)) + parser.push_edge (parser.current_bb->index, dest_index, + EDGE_FALSE_VALUE, prob); + else + f_label = lookup_label_for_goto (loc, label); + if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + return; + } + else + { + c_parser_error (parser, "expected goto expression"); + return; + } + + if (cond != error_mark_node) + gimple_seq_add_stmt_without_update (seq, gimple_build_cond_from_tree (cond, t_label, + f_label)); +} + +/* Parse gimple switch-statement. + + gimple-switch-statement: + switch (gimple-postfix-expression) gimple-case-statement + + gimple-case-statement: + gimple-case-statement + gimple-label-statement : gimple-goto-statment +*/ + +static void +c_parser_gimple_switch_stmt (gimple_parser &parser, gimple_seq *seq) +{ + c_expr cond_expr; + tree case_label, label; + auto_vec labels; + tree default_label = NULL_TREE; + c_parser_consume_token (parser); + + if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return; + cond_expr = c_parser_gimple_postfix_expression (parser); + if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return; + + if (! c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + return; + + while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) + { + if (c_parser_next_token_is (parser, CPP_EOF)) + { + c_parser_error (parser, "expected statement"); + return; + } + + switch (c_parser_peek_token (parser)->keyword) + { + case RID_CASE: + { + c_expr exp1; + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_NAME) + || c_parser_peek_token (parser)->type == CPP_NUMBER) + exp1 = c_parser_gimple_postfix_expression (parser); + else + { + c_parser_error (parser, "expected expression"); + return; + } + + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + label = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + tree decl = lookup_label_for_goto (loc, label); + case_label = build_case_label (exp1.value, NULL_TREE, + decl); + labels.safe_push (case_label); + if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<;%>")) + return; + } + else if (! c_parser_require (parser, CPP_NAME, + "expected label")) + return; + } + else if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<:%>")) + return; + break; + } + case RID_DEFAULT: + { + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + label = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + tree decl = lookup_label_for_goto (loc, label); + default_label = build_case_label (NULL_TREE, NULL_TREE, + decl); + if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<;%>")) + return; + } + else if (! c_parser_require (parser, CPP_NAME, + "expected label")) + return; + } + else if (! c_parser_require (parser, CPP_SEMICOLON, + "expected %<:%>")) + return; + break; + } + default: + c_parser_error (parser, "expected case label"); + return; + } + + } + if (! c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>")) + return; + + if (cond_expr.value != error_mark_node) + { + gswitch *s = gimple_build_switch (cond_expr.value, default_label, labels); + gimple_seq_add_stmt_without_update (seq, s); + } +} + +/* Parse gimple return statement. */ + +static void +c_parser_gimple_return_stmt (gimple_parser &parser, gimple_seq *seq) +{ + location_t loc = c_parser_peek_token (parser)->location; + gimple *ret = NULL; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_finish_gimple_return (loc, NULL_TREE); + ret = gimple_build_return (NULL); + gimple_seq_add_stmt_without_update (seq, ret); + } + else + { + location_t xloc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_gimple_unary_expression (parser); + if (expr.value != error_mark_node) + { + c_finish_gimple_return (xloc, expr.value); + ret = gimple_build_return (expr.value); + gimple_seq_add_stmt_without_update (seq, ret); + } + } +} + +/* Support function for c_parser_gimple_return_stmt. */ + +static void +c_finish_gimple_return (location_t loc, tree retval) +{ + tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)); + + /* Use the expansion point to handle cases such as returning NULL + in a function returning void. */ + location_t xloc = expansion_point_location_if_in_system_header (loc); + + if (TREE_THIS_VOLATILE (current_function_decl)) + warning_at (xloc, 0, + "function declared % has a % statement"); + + if (! retval) + current_function_returns_null = 1; + else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE) + { + current_function_returns_null = 1; + if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) + { + error_at + (xloc, "% with a value, in function returning void"); + inform (DECL_SOURCE_LOCATION (current_function_decl), + "declared here"); + } + } + else if (TREE_CODE (valtype) != TREE_CODE (TREE_TYPE (retval))) + { + error_at + (xloc, "invalid conversion in return statement"); + inform (DECL_SOURCE_LOCATION (current_function_decl), + "declared here"); + } + return; +} -- cgit v1.1 From e53b6e564aab615703ff2f9e8406a3953f0a3785 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 14 Jan 2022 16:57:02 +0100 Subject: Change references of .c files to .cc files ChangeLog: * MAINTAINERS: Rename .c names to .cc. contrib/ChangeLog: * filter-clang-warnings.py: Rename .c names to .cc. * gcc_update: Likewise. * paranoia.cc: Likewise. contrib/header-tools/ChangeLog: * README: Rename .c names to .cc. gcc/ChangeLog: * Makefile.in: Rename .c names to .cc. * alias.h: Likewise. * asan.cc: Likewise. * auto-profile.h: Likewise. * basic-block.h (struct basic_block_d): Likewise. * btfout.cc: Likewise. * builtins.cc (expand_builtin_longjmp): Likewise. (validate_arg): Likewise. (access_ref::offset_bounded): Likewise. * caller-save.cc (reg_restore_code): Likewise. (setup_save_areas): Likewise. * calls.cc (initialize_argument_information): Likewise. (expand_call): Likewise. (emit_library_call_value_1): Likewise. * cfg-flags.def (RTL): Likewise. (SIBCALL): Likewise. (CAN_FALLTHRU): Likewise. * cfganal.cc (post_order_compute): Likewise. * cfgcleanup.cc (try_simplify_condjump): Likewise. (merge_blocks_move_predecessor_nojumps): Likewise. (merge_blocks_move_successor_nojumps): Likewise. (merge_blocks_move): Likewise. (old_insns_match_p): Likewise. (try_crossjump_bb): Likewise. * cfgexpand.cc (expand_gimple_stmt): Likewise. * cfghooks.cc (split_block_before_cond_jump): Likewise. (profile_record_check_consistency): Likewise. * cfghooks.h: Likewise. * cfgrtl.cc (pass_free_cfg::execute): Likewise. (rtl_can_merge_blocks): Likewise. (try_redirect_by_replacing_jump): Likewise. (make_pass_outof_cfg_layout_mode): Likewise. (cfg_layout_can_merge_blocks_p): Likewise. * cgraph.cc (release_function_body): Likewise. (cgraph_node::get_fun): Likewise. * cgraph.h (struct cgraph_node): Likewise. (asmname_hasher::equal): Likewise. (cgraph_inline_failed_type): Likewise. (thunk_adjust): Likewise. (dump_callgraph_transformation): Likewise. (record_references_in_initializer): Likewise. (ipa_discover_variable_flags): Likewise. * cgraphclones.cc (GTY): Likewise. * cgraphunit.cc (symbol_table::finalize_compilation_unit): Likewise. * collect-utils.h (GCC_COLLECT_UTILS_H): Likewise. * collect2-aix.h (GCC_COLLECT2_AIX_H): Likewise. * collect2.cc (maybe_run_lto_and_relink): Likewise. * combine-stack-adj.cc: Likewise. * combine.cc (setup_incoming_promotions): Likewise. (combine_simplify_rtx): Likewise. (count_rtxs): Likewise. * common.opt: Likewise. * common/config/aarch64/aarch64-common.cc: Likewise. * common/config/arm/arm-common.cc (arm_asm_auto_mfpu): Likewise. * common/config/avr/avr-common.cc: Likewise. * common/config/i386/i386-isas.h (struct _isa_names_table): Likewise. * conditions.h: Likewise. * config.gcc: Likewise. * config/aarch64/aarch64-builtins.cc (aarch64_resolve_overloaded_memtag): Likewise. * config/aarch64/aarch64-protos.h (aarch64_classify_address): Likewise. (aarch64_get_extension_string_for_isa_flags): Likewise. * config/aarch64/aarch64-sve-builtins.cc (function_builder::add_function): Likewise. * config/aarch64/aarch64.cc (aarch64_regmode_natural_size): Likewise. (aarch64_sched_first_cycle_multipass_dfa_lookahead): Likewise. (aarch64_option_valid_attribute_p): Likewise. (aarch64_short_vector_p): Likewise. (aarch64_float_const_representable_p): Likewise. * config/aarch64/aarch64.h (DBX_REGISTER_NUMBER): Likewise. (ASM_OUTPUT_POOL_EPILOGUE): Likewise. (GTY): Likewise. * config/aarch64/cortex-a57-fma-steering.cc: Likewise. * config/aarch64/driver-aarch64.cc (contains_core_p): Likewise. * config/aarch64/t-aarch64: Likewise. * config/aarch64/x-aarch64: Likewise. * config/aarch64/x-darwin: Likewise. * config/alpha/alpha-protos.h: Likewise. * config/alpha/alpha.cc (alpha_scalar_mode_supported_p): Likewise. * config/alpha/alpha.h (LONG_DOUBLE_TYPE_SIZE): Likewise. (enum reg_class): Likewise. * config/alpha/alpha.md: Likewise. * config/alpha/driver-alpha.cc (AMASK_LOCKPFTCHOK): Likewise. * config/alpha/x-alpha: Likewise. * config/arc/arc-protos.h (arc_eh_uses): Likewise. * config/arc/arc.cc (ARC_OPT): Likewise. (arc_ccfsm_advance): Likewise. (arc_arg_partial_bytes): Likewise. (conditionalize_nonjump): Likewise. * config/arc/arc.md: Likewise. * config/arc/builtins.def: Likewise. * config/arc/t-arc: Likewise. * config/arm/arm-c.cc (arm_resolve_overloaded_builtin): Likewise. (arm_pragma_target_parse): Likewise. * config/arm/arm-protos.h (save_restore_target_globals): Likewise. (arm_cpu_cpp_builtins): Likewise. * config/arm/arm.cc (vfp3_const_double_index): Likewise. (shift_op): Likewise. (thumb2_final_prescan_insn): Likewise. (arm_final_prescan_insn): Likewise. (arm_asm_output_labelref): Likewise. (arm_small_register_classes_for_mode_p): Likewise. * config/arm/arm.h: Likewise. * config/arm/arm.md: Likewise. * config/arm/driver-arm.cc: Likewise. * config/arm/symbian.h: Likewise. * config/arm/t-arm: Likewise. * config/arm/thumb1.md: Likewise. * config/arm/x-arm: Likewise. * config/avr/avr-c.cc (avr_register_target_pragmas): Likewise. * config/avr/avr-fixed.md: Likewise. * config/avr/avr-log.cc (avr_log_vadump): Likewise. * config/avr/avr-mcus.def: Likewise. * config/avr/avr-modes.def (FRACTIONAL_INT_MODE): Likewise. * config/avr/avr-passes.def (INSERT_PASS_BEFORE): Likewise. * config/avr/avr-protos.h (make_avr_pass_casesi): Likewise. * config/avr/avr.cc (avr_option_override): Likewise. (avr_build_builtin_va_list): Likewise. (avr_mode_dependent_address_p): Likewise. (avr_function_arg_advance): Likewise. (avr_asm_output_aligned_decl_common): Likewise. * config/avr/avr.h (RETURN_ADDR_RTX): Likewise. (SUPPORTS_INIT_PRIORITY): Likewise. * config/avr/avr.md: Likewise. * config/avr/builtins.def: Likewise. * config/avr/gen-avr-mmcu-specs.cc (IN_GEN_AVR_MMCU_TEXI): Likewise. * config/avr/gen-avr-mmcu-texi.cc (IN_GEN_AVR_MMCU_TEXI): Likewise. (main): Likewise. * config/avr/t-avr: Likewise. * config/bfin/bfin.cc (frame_related_constant_load): Likewise. * config/bpf/bpf-protos.h (GCC_BPF_PROTOS_H): Likewise. * config/bpf/bpf.h (enum reg_class): Likewise. * config/bpf/t-bpf: Likewise. * config/c6x/c6x-protos.h (GCC_C6X_PROTOS_H): Likewise. * config/cr16/cr16-protos.h: Likewise. * config/cris/cris.cc (cris_address_cost): Likewise. (cris_side_effect_mode_ok): Likewise. (cris_init_machine_status): Likewise. (cris_emit_movem_store): Likewise. * config/cris/cris.h (INDEX_REG_CLASS): Likewise. (enum reg_class): Likewise. (struct cum_args): Likewise. * config/cris/cris.opt: Likewise. * config/cris/sync.md: Likewise. * config/csky/csky.cc (csky_expand_prologue): Likewise. * config/darwin-c.cc: Likewise. * config/darwin-f.cc: Likewise. * config/darwin-sections.def (zobj_const_section): Likewise. * config/darwin.cc (output_objc_section_asm_op): Likewise. (fprintf): Likewise. * config/darwin.h (GTY): Likewise. * config/elfos.h: Likewise. * config/epiphany/epiphany-sched.md: Likewise. * config/epiphany/epiphany.cc (epiphany_function_value): Likewise. * config/epiphany/epiphany.h (GTY): Likewise. (NO_FUNCTION_CSE): Likewise. * config/epiphany/mode-switch-use.cc: Likewise. * config/epiphany/predicates.md: Likewise. * config/epiphany/t-epiphany: Likewise. * config/fr30/fr30-protos.h: Likewise. * config/frv/frv-protos.h: Likewise. * config/frv/frv.cc (TLS_BIAS): Likewise. * config/frv/frv.h (ASM_OUTPUT_ALIGNED_LOCAL): Likewise. * config/ft32/ft32-protos.h: Likewise. * config/gcn/gcn-hsa.h (ASM_APP_OFF): Likewise. * config/gcn/gcn.cc (gcn_init_libfuncs): Likewise. * config/gcn/mkoffload.cc (copy_early_debug_info): Likewise. * config/gcn/t-gcn-hsa: Likewise. * config/gcn/t-omp-device: Likewise. * config/h8300/h8300-protos.h (GCC_H8300_PROTOS_H): Likewise. (same_cmp_following_p): Likewise. * config/h8300/h8300.cc (F): Likewise. * config/h8300/h8300.h (struct cum_arg): Likewise. (BRANCH_COST): Likewise. * config/i386/cygming.h (DEFAULT_PCC_STRUCT_RETURN): Likewise. * config/i386/djgpp.h (TARGET_ASM_LTO_END): Likewise. * config/i386/dragonfly.h (NO_PROFILE_COUNTERS): Likewise. * config/i386/driver-i386.cc (detect_caches_intel): Likewise. * config/i386/freebsd.h (NO_PROFILE_COUNTERS): Likewise. * config/i386/i386-c.cc (ix86_target_macros): Likewise. * config/i386/i386-expand.cc (get_mode_wider_vector): Likewise. * config/i386/i386-options.cc (ix86_set_func_type): Likewise. * config/i386/i386-protos.h (ix86_extract_perm_from_pool_constant): Likewise. (ix86_register_pragmas): Likewise. (ix86_d_has_stdcall_convention): Likewise. (i386_pe_seh_init_sections): Likewise. * config/i386/i386.cc (ix86_function_arg_regno_p): Likewise. (ix86_function_value_regno_p): Likewise. (ix86_compute_frame_layout): Likewise. (legitimize_pe_coff_symbol): Likewise. (output_pic_addr_const): Likewise. * config/i386/i386.h (defined): Likewise. (host_detect_local_cpu): Likewise. (CONSTANT_ADDRESS_P): Likewise. (DEFAULT_LARGE_SECTION_THRESHOLD): Likewise. (struct machine_frame_state): Likewise. * config/i386/i386.md: Likewise. * config/i386/lynx.h (ASM_OUTPUT_ALIGN): Likewise. * config/i386/mmx.md: Likewise. * config/i386/sse.md: Likewise. * config/i386/t-cygming: Likewise. * config/i386/t-djgpp: Likewise. * config/i386/t-gnu-property: Likewise. * config/i386/t-i386: Likewise. * config/i386/t-intelmic: Likewise. * config/i386/t-omp-device: Likewise. * config/i386/winnt-cxx.cc (i386_pe_type_dllimport_p): Likewise. (i386_pe_adjust_class_at_definition): Likewise. * config/i386/winnt.cc (gen_stdcall_or_fastcall_suffix): Likewise. (i386_pe_mangle_decl_assembler_name): Likewise. (i386_pe_encode_section_info): Likewise. * config/i386/x-cygwin: Likewise. * config/i386/x-darwin: Likewise. * config/i386/x-i386: Likewise. * config/i386/x-mingw32: Likewise. * config/i386/x86-tune-sched-core.cc: Likewise. * config/i386/x86-tune.def: Likewise. * config/i386/xm-djgpp.h (STANDARD_STARTFILE_PREFIX_1): Likewise. * config/ia64/freebsd.h: Likewise. * config/ia64/hpux.h (REGISTER_TARGET_PRAGMAS): Likewise. * config/ia64/ia64-protos.h (ia64_except_unwind_info): Likewise. * config/ia64/ia64.cc (ia64_function_value_regno_p): Likewise. (ia64_secondary_reload_class): Likewise. (bundling): Likewise. * config/ia64/ia64.h: Likewise. * config/ia64/ia64.md: Likewise. * config/ia64/predicates.md: Likewise. * config/ia64/sysv4.h: Likewise. * config/ia64/t-ia64: Likewise. * config/iq2000/iq2000.h (FUNCTION_MODE): Likewise. * config/iq2000/iq2000.md: Likewise. * config/linux.h (TARGET_HAS_BIONIC): Likewise. (if): Likewise. * config/m32c/m32c.cc (m32c_function_needs_enter): Likewise. * config/m32c/m32c.h (MAX_REGS_PER_ADDRESS): Likewise. * config/m32c/t-m32c: Likewise. * config/m32r/m32r-protos.h: Likewise. * config/m32r/m32r.cc (m32r_print_operand): Likewise. * config/m32r/m32r.h: Likewise. * config/m32r/m32r.md: Likewise. * config/m68k/m68k-isas.def: Likewise. * config/m68k/m68k-microarchs.def: Likewise. * config/m68k/m68k-protos.h (strict_low_part_peephole_ok): Likewise. (m68k_epilogue_uses): Likewise. * config/m68k/m68k.cc (m68k_call_tls_get_addr): Likewise. (m68k_sched_adjust_cost): Likewise. (m68k_sched_md_init): Likewise. * config/m68k/m68k.h (__transfer_from_trampoline): Likewise. (enum m68k_function_kind): Likewise. * config/m68k/m68k.md: Likewise. * config/m68k/m68kemb.h: Likewise. * config/m68k/uclinux.h (ENDFILE_SPEC): Likewise. * config/mcore/mcore-protos.h: Likewise. * config/mcore/mcore.cc (mcore_expand_insv): Likewise. (mcore_expand_prolog): Likewise. * config/mcore/mcore.h (TARGET_MCORE): Likewise. * config/mcore/mcore.md: Likewise. * config/microblaze/microblaze-protos.h: Likewise. * config/microblaze/microblaze.cc (microblaze_legitimate_pic_operand): Likewise. (microblaze_function_prologue): Likewise. (microblaze_function_epilogue): Likewise. (microblaze_select_section): Likewise. (microblaze_asm_output_mi_thunk): Likewise. (microblaze_eh_return): Likewise. * config/microblaze/microblaze.h: Likewise. * config/microblaze/microblaze.md: Likewise. * config/microblaze/t-microblaze: Likewise. * config/mips/driver-native.cc: Likewise. * config/mips/loongson2ef.md: Likewise. * config/mips/mips-protos.h (mips_expand_vec_cmp_expr): Likewise. * config/mips/mips.cc (mips_rtx_costs): Likewise. (mips_output_filename): Likewise. (mips_output_function_prologue): Likewise. (mips_output_function_epilogue): Likewise. (mips_output_mi_thunk): Likewise. * config/mips/mips.h: Likewise. * config/mips/mips.md: Likewise. * config/mips/t-mips: Likewise. * config/mips/x-native: Likewise. * config/mmix/mmix-protos.h: Likewise. * config/mmix/mmix.cc (mmix_option_override): Likewise. (mmix_dbx_register_number): Likewise. (mmix_expand_prologue): Likewise. * config/mmix/mmix.h: Likewise. * config/mmix/mmix.md: Likewise. * config/mmix/predicates.md: Likewise. * config/mn10300/mn10300.cc (mn10300_symbolic_operand): Likewise. (mn10300_legitimate_pic_operand_p): Likewise. * config/mn10300/mn10300.h (enum reg_class): Likewise. (NO_FUNCTION_CSE): Likewise. * config/moxie/moxie-protos.h: Likewise. * config/moxie/uclinux.h (TARGET_LIBC_HAS_FUNCTION): Likewise. * config/msp430/msp430-devices.cc (extract_devices_dir_from_exec_prefix): Likewise. * config/msp430/msp430.cc (msp430_gimplify_va_arg_expr): Likewise. (msp430_incoming_return_addr_rtx): Likewise. * config/msp430/msp430.h (msp430_get_linker_devices_include_path): Likewise. * config/msp430/t-msp430: Likewise. * config/nds32/nds32-cost.cc (nds32_rtx_costs_speed_prefer): Likewise. (nds32_rtx_costs_size_prefer): Likewise. (nds32_init_rtx_costs): Likewise. * config/nds32/nds32-doubleword.md: Likewise. * config/nds32/nds32.cc (nds32_memory_move_cost): Likewise. (nds32_builtin_decl): Likewise. * config/nds32/nds32.h (enum nds32_16bit_address_type): Likewise. (enum nds32_isr_nested_type): Likewise. (enum reg_class): Likewise. * config/nds32/predicates.md: Likewise. * config/nds32/t-nds32: Likewise. * config/nios2/nios2.cc (nios2_pragma_target_parse): Likewise. * config/nvptx/nvptx-protos.h: Likewise. * config/nvptx/nvptx.cc (nvptx_goacc_expand_var_decl): Likewise. * config/nvptx/nvptx.h (TARGET_CPU_CPP_BUILTINS): Likewise. * config/nvptx/t-nvptx: Likewise. * config/nvptx/t-omp-device: Likewise. * config/pa/elf.h: Likewise. * config/pa/pa-linux.h (GLOBAL_ASM_OP): Likewise. * config/pa/pa-netbsd.h (GLOBAL_ASM_OP): Likewise. * config/pa/pa-openbsd.h (TARGET_ASM_GLOBALIZE_LABEL): Likewise. * config/pa/pa-protos.h (pa_eh_return_handler_rtx): Likewise. (pa_legitimize_reload_address): Likewise. (pa_can_use_return_insn): Likewise. * config/pa/pa.cc (mem_shadd_or_shadd_rtx_p): Likewise. (som_output_text_section_asm_op): Likewise. * config/pa/pa.h (PROFILE_BEFORE_PROLOGUE): Likewise. * config/pa/pa.md: Likewise. * config/pa/som.h: Likewise. * config/pa/t-pa: Likewise. * config/pdp11/pdp11.cc (decode_pdp11_d): Likewise. * config/pdp11/pdp11.h: Likewise. * config/pdp11/pdp11.md: Likewise. * config/pdp11/t-pdp11: Likewise. * config/pru/pru.md: Likewise. * config/pru/t-pru: Likewise. * config/riscv/riscv-protos.h (NUM_SYMBOL_TYPES): Likewise. (riscv_gpr_save_operation_p): Likewise. (riscv_d_register_target_info): Likewise. (riscv_init_builtins): Likewise. * config/riscv/riscv.cc (riscv_output_mi_thunk): Likewise. * config/riscv/riscv.h (CSW_MAX_OFFSET): Likewise. * config/riscv/t-riscv: Likewise. * config/rl78/rl78.cc (rl78_asm_ctor_dtor): Likewise. * config/rl78/t-rl78: Likewise. * config/rs6000/aix.h: Likewise. * config/rs6000/aix71.h (ASM_SPEC_COMMON): Likewise. * config/rs6000/aix72.h (ASM_SPEC_COMMON): Likewise. * config/rs6000/aix73.h (ASM_SPEC_COMMON): Likewise. * config/rs6000/darwin.h (TARGET_ASM_GLOBALIZE_LABEL): Likewise. * config/rs6000/driver-rs6000.cc: Likewise. * config/rs6000/freebsd.h: Likewise. * config/rs6000/freebsd64.h: Likewise. * config/rs6000/lynx.h (ASM_OUTPUT_ALIGN): Likewise. * config/rs6000/rbtree.cc: Likewise. * config/rs6000/rbtree.h: Likewise. * config/rs6000/rs6000-c.cc (rs6000_target_modify_macros): Likewise. * config/rs6000/rs6000-call.cc (rs6000_invalid_builtin): Likewise. (rs6000_expand_builtin): Likewise. (rs6000_init_builtins): Likewise. * config/rs6000/rs6000-cpus.def: Likewise. * config/rs6000/rs6000-gen-builtins.cc (write_init_ovld_table): Likewise. * config/rs6000/rs6000-internal.h (ALTIVEC_REG_BIT): Likewise. (quad_address_offset_p): Likewise. * config/rs6000/rs6000-logue.cc (interesting_frame_related_regno): Likewise. (rs6000_emit_epilogue): Likewise. * config/rs6000/rs6000-overload.def: Likewise. * config/rs6000/rs6000-p8swap.cc: Likewise. * config/rs6000/rs6000-protos.h (GCC_RS6000_PROTOS_H): Likewise. (rs6000_const_f32_to_i32): Likewise. * config/rs6000/rs6000.cc (legitimate_lo_sum_address_p): Likewise. (rs6000_debug_legitimize_address): Likewise. (rs6000_mode_dependent_address): Likewise. (rs6000_adjust_priority): Likewise. (rs6000_c_mode_for_suffix): Likewise. * config/rs6000/rs6000.h (defined): Likewise. (LONG_DOUBLE_TYPE_SIZE): Likewise. * config/rs6000/rs6000.md: Likewise. * config/rs6000/sysv4.h: Likewise. * config/rs6000/t-linux: Likewise. * config/rs6000/t-linux64: Likewise. * config/rs6000/t-rs6000: Likewise. * config/rs6000/x-darwin: Likewise. * config/rs6000/x-darwin64: Likewise. * config/rs6000/x-rs6000: Likewise. * config/rs6000/xcoff.h (ASM_OUTPUT_LABELREF): Likewise. * config/rx/rx.cc (rx_expand_builtin): Likewise. * config/s390/constraints.md: Likewise. * config/s390/driver-native.cc: Likewise. * config/s390/htmxlintrin.h: Likewise. * config/s390/s390-builtins.def (B_DEF): Likewise. (OB_DEF_VAR): Likewise. * config/s390/s390-builtins.h: Likewise. * config/s390/s390-c.cc: Likewise. * config/s390/s390-opts.h: Likewise. * config/s390/s390-protos.h (s390_check_symref_alignment): Likewise. (s390_register_target_pragmas): Likewise. * config/s390/s390.cc (s390_init_builtins): Likewise. (s390_expand_plus_operand): Likewise. (s390_expand_atomic): Likewise. (s390_valid_target_attribute_inner_p): Likewise. * config/s390/s390.h (LONG_DOUBLE_TYPE_SIZE): Likewise. * config/s390/s390.md: Likewise. * config/s390/t-s390: Likewise. * config/s390/vx-builtins.md: Likewise. * config/s390/x-native: Likewise. * config/sh/divtab-sh4-300.cc (main): Likewise. * config/sh/divtab-sh4.cc (main): Likewise. * config/sh/divtab.cc (main): Likewise. * config/sh/elf.h: Likewise. * config/sh/sh-protos.h (sh_fsca_int2sf): Likewise. * config/sh/sh.cc (SYMBOL_FLAG_FUNCVEC_FUNCTION): Likewise. (sh_struct_value_rtx): Likewise. (sh_remove_reg_dead_or_unused_notes): Likewise. * config/sh/sh.h (MIN_UNITS_PER_WORD): Likewise. * config/sh/t-sh: Likewise. * config/sol2-protos.h (solaris_override_options): Likewise. * config/sol2.h: Likewise. * config/sparc/driver-sparc.cc: Likewise. * config/sparc/freebsd.h: Likewise. * config/sparc/sparc-protos.h (make_pass_work_around_errata): Likewise. * config/sparc/sparc.cc (sparc_output_mi_thunk): Likewise. (sparc_asan_shadow_offset): Likewise. * config/sparc/sparc.h: Likewise. * config/sparc/sparc.md: Likewise. * config/sparc/t-sparc: Likewise. * config/sparc/x-sparc: Likewise. * config/stormy16/stormy16.cc (xstormy16_mode_dependent_address_p): Likewise. * config/t-darwin: Likewise. * config/t-dragonfly: Likewise. * config/t-freebsd: Likewise. * config/t-glibc: Likewise. * config/t-linux: Likewise. * config/t-netbsd: Likewise. * config/t-openbsd: Likewise. * config/t-pnt16-warn: Likewise. * config/t-sol2: Likewise. * config/t-vxworks: Likewise. * config/t-winnt: Likewise. * config/tilegx/t-tilegx: Likewise. * config/tilegx/tilegx-c.cc: Likewise. * config/tilegx/tilegx-protos.h (tilegx_function_profiler): Likewise. * config/tilegx/tilegx.md: Likewise. * config/tilepro/t-tilepro: Likewise. * config/tilepro/tilepro-c.cc: Likewise. * config/v850/t-v850: Likewise. * config/v850/v850-protos.h: Likewise. * config/v850/v850.cc (F): Likewise. * config/v850/v850.h (enum reg_class): Likewise. (SLOW_BYTE_ACCESS): Likewise. * config/vax/vax.cc (vax_mode_dependent_address_p): Likewise. * config/vax/vax.h (enum reg_class): Likewise. * config/vax/vax.md: Likewise. * config/visium/visium.cc (visium_legitimate_address_p): Likewise. * config/visium/visium.h: Likewise. * config/vms/t-vms: Likewise. * config/vms/vms-crtlmap.map: Likewise. * config/vms/vms-protos.h (vms_c_get_vms_ver): Likewise. * config/vx-common.h: Likewise. * config/x-darwin: Likewise. * config/x-hpux: Likewise. * config/x-linux: Likewise. * config/x-netbsd: Likewise. * config/x-openbsd: Likewise. * config/x-solaris: Likewise. * config/xtensa/xtensa-protos.h (xtensa_mem_offset): Likewise. * config/xtensa/xtensa.cc (xtensa_option_override): Likewise. * config/xtensa/xtensa.h: Likewise. * configure.ac: Likewise. * context.cc: Likewise. * convert.h: Likewise. * coretypes.h: Likewise. * coverage.cc: Likewise. * coverage.h: Likewise. * cppdefault.h (struct default_include): Likewise. * cprop.cc (local_cprop_pass): Likewise. (one_cprop_pass): Likewise. * cse.cc (hash_rtx_cb): Likewise. (fold_rtx): Likewise. * ctfc.h (ctfc_get_num_vlen_bytes): Likewise. * data-streamer.h (bp_unpack_var_len_int): Likewise. (streamer_write_widest_int): Likewise. * dbgcnt.def: Likewise. * dbxout.cc (dbxout_early_global_decl): Likewise. (dbxout_common_check): Likewise. * dbxout.h: Likewise. * debug.h (struct gcc_debug_hooks): Likewise. (dump_go_spec_init): Likewise. * df-core.cc: Likewise. * df-scan.cc (df_insn_info_delete): Likewise. (df_insn_delete): Likewise. * df.h (debug_df_chain): Likewise. (can_move_insns_across): Likewise. * dfp.cc (decimal_from_binary): Likewise. * diagnostic-color.cc: Likewise. * diagnostic-event-id.h: Likewise. * diagnostic-show-locus.cc (test_one_liner_labels): Likewise. * diagnostic.cc (bt_callback): Likewise. (num_digits): Likewise. * doc/avr-mmcu.texi: Likewise. * doc/cfg.texi: Likewise. * doc/contrib.texi: Likewise. * doc/cppinternals.texi: Likewise. * doc/extend.texi: Likewise. * doc/generic.texi: Likewise. * doc/gimple.texi: Likewise. * doc/gty.texi: Likewise. * doc/invoke.texi: Likewise. * doc/loop.texi: Likewise. * doc/lto.texi: Likewise. * doc/match-and-simplify.texi: Likewise. * doc/md.texi: Likewise. * doc/optinfo.texi: Likewise. * doc/options.texi: Likewise. * doc/passes.texi: Likewise. * doc/plugins.texi: Likewise. * doc/rtl.texi: Likewise. * doc/sourcebuild.texi: Likewise. * doc/tm.texi: Likewise. * doc/tm.texi.in: Likewise. * doc/tree-ssa.texi: Likewise. * dojump.cc (do_jump): Likewise. * dojump.h: Likewise. * dumpfile.cc (test_impl_location): Likewise. (test_capture_of_dump_calls): Likewise. * dumpfile.h (enum dump_kind): Likewise. (class dump_location_t): Likewise. (dump_enabled_p): Likewise. (enable_rtl_dump_file): Likewise. (dump_combine_total_stats): Likewise. * dwarf2asm.cc (dw2_asm_output_delta_uleb128): Likewise. * dwarf2ctf.h (ctf_debug_finish): Likewise. * dwarf2out.cc (dwarf2out_begin_prologue): Likewise. (struct loc_descr_context): Likewise. (rtl_for_decl_location): Likewise. (gen_subprogram_die): Likewise. (gen_label_die): Likewise. (is_trivial_indirect_ref): Likewise. (dwarf2out_late_global_decl): Likewise. (dwarf_file_hasher::hash): Likewise. (dwarf2out_end_source_file): Likewise. (dwarf2out_define): Likewise. (dwarf2out_early_finish): Likewise. * dwarf2out.h (struct dw_fde_node): Likewise. (struct dw_discr_list_node): Likewise. (output_loc_sequence_raw): Likewise. * emit-rtl.cc (gen_raw_REG): Likewise. (maybe_set_max_label_num): Likewise. * emit-rtl.h (struct rtl_data): Likewise. * errors.cc (internal_error): Likewise. (trim_filename): Likewise. * et-forest.cc: Likewise. * except.cc (init_eh_for_function): Likewise. * explow.cc (promote_ssa_mode): Likewise. (get_dynamic_stack_size): Likewise. * explow.h: Likewise. * expmed.h: Likewise. * expr.cc (safe_from_p): Likewise. (expand_expr_real_2): Likewise. (expand_expr_real_1): Likewise. * file-prefix-map.cc (remap_filename): Likewise. * final.cc (app_enable): Likewise. (make_pass_compute_alignments): Likewise. (final_scan_insn_1): Likewise. (final_scan_insn): Likewise. * fixed-value.h (fixed_from_string): Likewise. * flag-types.h (NO_DEBUG): Likewise. (DWARF2_DEBUG): Likewise. (VMS_DEBUG): Likewise. (BTF_DEBUG): Likewise. (enum ctf_debug_info_levels): Likewise. * fold-const.cc (const_binop): Likewise. (fold_binary_loc): Likewise. (fold_checksum_tree): Likewise. * fp-test.cc: Likewise. * function.cc (expand_function_end): Likewise. * function.h (struct function): Likewise. * fwprop.cc (should_replace_address): Likewise. * gcc-main.cc: Likewise. * gcc-rich-location.h (class gcc_rich_location): Likewise. * gcc-symtab.h: Likewise. * gcc.cc (MIN_FATAL_STATUS): Likewise. (driver_handle_option): Likewise. (quote_spec_arg): Likewise. (driver::finalize): Likewise. * gcc.h (set_input): Likewise. * gcov-dump.cc: Likewise. * gcov.cc (solve_flow_graph): Likewise. * gcse-common.cc: Likewise. * gcse.cc (make_pass_rtl_hoist): Likewise. * genattr-common.cc: Likewise. * genattrtab.cc (min_fn): Likewise. (write_const_num_delay_slots): Likewise. * genautomata.cc: Likewise. * genconditions.cc (write_one_condition): Likewise. * genconstants.cc: Likewise. * genemit.cc (gen_exp): Likewise. * generic-match-head.cc: Likewise. * genextract.cc: Likewise. * gengenrtl.cc (always_void_p): Likewise. * gengtype-parse.cc (gtymarker_opt): Likewise. * gengtype-state.cc (state_writer::state_writer): Likewise. (write_state_trailer): Likewise. (equals_type_number): Likewise. (read_state): Likewise. * gengtype.cc (open_base_files): Likewise. (struct file_rule_st): Likewise. (header_dot_h_frul): Likewise. * gengtype.h: Likewise. * genmatch.cc (main): Likewise. * genmddeps.cc: Likewise. * genmodes.cc (emit_mode_inner): Likewise. (emit_mode_unit_size): Likewise. * genpeep.cc (gen_peephole): Likewise. * genpreds.cc (write_tm_preds_h): Likewise. * genrecog.cc (validate_pattern): Likewise. (write_header): Likewise. (main): Likewise. * gensupport.cc (change_subst_attribute): Likewise. (traverse_c_tests): Likewise. (add_predicate): Likewise. (init_predicate_table): Likewise. * gensupport.h (struct optab_pattern): Likewise. (get_num_insn_codes): Likewise. (maybe_eval_c_test): Likewise. (struct pred_data): Likewise. * ggc-internal.h: Likewise. * gimple-fold.cc (maybe_fold_reference): Likewise. (get_range_strlen_tree): Likewise. * gimple-fold.h (gimple_stmt_integer_valued_real_p): Likewise. * gimple-low.cc: Likewise. * gimple-match-head.cc (directly_supported_p): Likewise. * gimple-pretty-print.h: Likewise. * gimple-ssa-sprintf.cc (format_percent): Likewise. (adjust_range_for_overflow): Likewise. * gimple-streamer.h: Likewise. * gimple.h (struct GTY): Likewise. (is_gimple_resx): Likewise. * gimplify.cc (gimplify_expr): Likewise. (gimplify_init_constructor): Likewise. (omp_construct_selector_matches): Likewise. (gimplify_omp_target_update): Likewise. (gimplify_omp_ordered): Likewise. (gimplify_va_arg_expr): Likewise. * graphite-isl-ast-to-gimple.cc (should_copy_to_new_region): Likewise. * haifa-sched.cc (increase_insn_priority): Likewise. (try_ready): Likewise. (sched_create_recovery_edges): Likewise. * ifcvt.cc (find_if_case_1): Likewise. (find_if_case_2): Likewise. * inchash.h: Likewise. * incpath.cc (add_env_var_paths): Likewise. * input.cc (dump_location_info): Likewise. (assert_loceq): Likewise. (test_lexer_string_locations_concatenation_1): Likewise. (test_lexer_string_locations_concatenation_2): Likewise. (test_lexer_string_locations_concatenation_3): Likewise. * input.h (BUILTINS_LOCATION): Likewise. (class string_concat_db): Likewise. * internal-fn.cc (expand_MUL_OVERFLOW): Likewise. (expand_LOOP_VECTORIZED): Likewise. * ipa-cp.cc (make_pass_ipa_cp): Likewise. * ipa-fnsummary.cc (remap_freqcounting_preds_after_dup): Likewise. (ipa_fn_summary_t::duplicate): Likewise. (make_pass_ipa_fn_summary): Likewise. * ipa-fnsummary.h (enum ipa_hints_vals): Likewise. * ipa-free-lang-data.cc (fld_simplified_type): Likewise. (free_lang_data_in_decl): Likewise. * ipa-inline.cc (compute_inlined_call_time): Likewise. (inline_always_inline_functions): Likewise. * ipa-inline.h (free_growth_caches): Likewise. (inline_account_function_p): Likewise. * ipa-modref.cc (modref_access_analysis::analyze_stmt): Likewise. (modref_eaf_analysis::analyze_ssa_name): Likewise. * ipa-param-manipulation.cc (ipa_param_body_adjustments::mark_dead_statements): Likewise. (ipa_param_body_adjustments::remap_with_debug_expressions): Likewise. * ipa-prop.cc (ipa_set_node_agg_value_chain): Likewise. * ipa-prop.h (IPA_UNDESCRIBED_USE): Likewise. (unadjusted_ptr_and_unit_offset): Likewise. * ipa-reference.cc (make_pass_ipa_reference): Likewise. * ipa-reference.h (GCC_IPA_REFERENCE_H): Likewise. * ipa-split.cc (consider_split): Likewise. * ipa-sra.cc (isra_read_node_info): Likewise. * ipa-utils.h (struct ipa_dfs_info): Likewise. (recursive_call_p): Likewise. (ipa_make_function_pure): Likewise. * ira-build.cc (ira_create_allocno): Likewise. (ira_flattening): Likewise. * ira-color.cc (do_coloring): Likewise. (update_curr_costs): Likewise. * ira-conflicts.cc (process_regs_for_copy): Likewise. * ira-int.h (struct ira_emit_data): Likewise. (ira_prohibited_mode_move_regs): Likewise. (ira_get_dup_out_num): Likewise. (ira_destroy): Likewise. (ira_tune_allocno_costs): Likewise. (ira_implicitly_set_insn_hard_regs): Likewise. (ira_build_conflicts): Likewise. (ira_color): Likewise. * ira-lives.cc (process_bb_node_lives): Likewise. * ira.cc (class ira_spilled_reg_stack_slot): Likewise. (setup_uniform_class_p): Likewise. (def_dominates_uses): Likewise. * ira.h (ira_nullify_asm_goto): Likewise. * langhooks.cc (lhd_post_options): Likewise. * langhooks.h (class substring_loc): Likewise. (struct lang_hooks_for_tree_inlining): Likewise. (struct lang_hooks_for_types): Likewise. (struct lang_hooks): Likewise. * libfuncs.h (synchronize_libfunc): Likewise. * loop-doloop.cc (doloop_condition_get): Likewise. * loop-init.cc (fix_loop_structure): Likewise. * loop-invariant.cc: Likewise. * lower-subreg.h: Likewise. * lra-constraints.cc (curr_insn_transform): Likewise. * lra-int.h (struct lra_insn_reg): Likewise. (lra_undo_inheritance): Likewise. (lra_setup_reload_pseudo_preferenced_hard_reg): Likewise. (lra_split_hard_reg_for): Likewise. (lra_coalesce): Likewise. (lra_final_code_change): Likewise. * lra-spills.cc (lra_final_code_change): Likewise. * lra.cc (lra_process_new_insns): Likewise. * lto-compress.h (struct lto_compression_stream): Likewise. * lto-streamer-out.cc (DFS::DFS_write_tree_body): Likewise. (write_symbol): Likewise. * lto-streamer.h (enum LTO_tags): Likewise. (lto_value_range_error): Likewise. (lto_append_block): Likewise. (lto_streamer_hooks_init): Likewise. (stream_read_tree_ref): Likewise. (lto_prepare_function_for_streaming): Likewise. (select_what_to_stream): Likewise. (omp_lto_input_declare_variant_alt): Likewise. (cl_optimization_stream_in): Likewise. * lto-wrapper.cc (append_compiler_options): Likewise. * machmode.def: Likewise. * machmode.h (struct int_n_data_t): Likewise. * main.cc (main): Likewise. * match.pd: Likewise. * omp-builtins.def (BUILT_IN_GOMP_CRITICAL_NAME_END): Likewise. (BUILT_IN_GOMP_LOOP_ULL_ORDERED_RUNTIME_NEXT): Likewise. * omp-expand.cc (expand_omp_atomic_fetch_op): Likewise. (make_pass_expand_omp_ssa): Likewise. * omp-low.cc (struct omp_context): Likewise. (struct omp_taskcopy_context): Likewise. (lower_omp): Likewise. * omp-oacc-neuter-broadcast.cc (omp_sese_active_worker_call): Likewise. (mask_name): Likewise. (omp_sese_dump_pars): Likewise. (worker_single_simple): Likewise. * omp-offload.cc (omp_finish_file): Likewise. (execute_oacc_loop_designation): Likewise. * optabs-query.cc (lshift_cheap_p): Likewise. * optc-gen.awk: Likewise. * optc-save-gen.awk: Likewise. * optinfo-emit-json.cc (optrecord_json_writer::optrecord_json_writer): Likewise. * opts-common.cc: Likewise. * output.h (app_enable): Likewise. (output_operand_lossage): Likewise. (insn_current_reference_address): Likewise. (get_insn_template): Likewise. (output_quoted_string): Likewise. * pass_manager.h (struct register_pass_info): Likewise. * plugin.cc: Likewise. * plugin.def (PLUGIN_ANALYZER_INIT): Likewise. * plugin.h (invoke_plugin_callbacks): Likewise. * pointer-query.cc (handle_mem_ref): Likewise. * postreload-gcse.cc (alloc_mem): Likewise. * predict.h (enum prediction): Likewise. (add_reg_br_prob_note): Likewise. * prefix.h: Likewise. * profile.h (get_working_sets): Likewise. * read-md.cc: Likewise. * read-md.h (struct mapping): Likewise. (class md_reader): Likewise. (class noop_reader): Likewise. * read-rtl-function.cc (function_reader::create_function): Likewise. (function_reader::extra_parsing_for_operand_code_0): Likewise. * read-rtl.cc (initialize_iterators): Likewise. * real.cc: Likewise. * real.h (struct real_value): Likewise. (format_helper::format_helper): Likewise. (real_hash): Likewise. (real_can_shorten_arithmetic): Likewise. * recog.cc (struct target_recog): Likewise. (offsettable_nonstrict_memref_p): Likewise. (constrain_operands): Likewise. * recog.h (MAX_RECOG_ALTERNATIVES): Likewise. (which_op_alt): Likewise. (struct insn_gen_fn): Likewise. * reg-notes.def (REG_NOTE): Likewise. * reg-stack.cc: Likewise. * regs.h (reg_is_parm_p): Likewise. * regset.h: Likewise. * reload.cc (push_reload): Likewise. (find_reloads): Likewise. (find_reloads_address_1): Likewise. (find_replacement): Likewise. (refers_to_regno_for_reload_p): Likewise. (refers_to_mem_for_reload_p): Likewise. * reload.h (push_reload): Likewise. (deallocate_reload_reg): Likewise. * reload1.cc (emit_input_reload_insns): Likewise. * reorg.cc (relax_delay_slots): Likewise. * rtl.def (UNKNOWN): Likewise. (SEQUENCE): Likewise. (BARRIER): Likewise. (ASM_OPERANDS): Likewise. (EQ_ATTR_ALT): Likewise. * rtl.h (struct GTY): Likewise. (LABEL_NAME): Likewise. (LABEL_ALT_ENTRY_P): Likewise. (SUBREG_BYTE): Likewise. (get_stack_check_protect): Likewise. (dump_rtx_statistics): Likewise. (unwrap_const_vec_duplicate): Likewise. (subreg_promoted_mode): Likewise. (gen_lowpart_common): Likewise. (operand_subword): Likewise. (immed_wide_int_const): Likewise. (decide_function_section): Likewise. (active_insn_p): Likewise. (delete_related_insns): Likewise. (try_split): Likewise. (val_signbit_known_clear_p): Likewise. (simplifiable_subregs): Likewise. (set_insn_deleted): Likewise. (subreg_get_info): Likewise. (remove_free_EXPR_LIST_node): Likewise. (finish_subregs_of_mode): Likewise. (get_mem_attrs): Likewise. (lookup_constant_def): Likewise. (rtx_to_tree_code): Likewise. (hash_rtx): Likewise. (condjump_in_parallel_p): Likewise. (validate_subreg): Likewise. (make_compound_operation): Likewise. (schedule_ebbs): Likewise. (print_inline_rtx): Likewise. (fixup_args_size_notes): Likewise. (expand_dec): Likewise. (prepare_copy_insn): Likewise. (mark_elimination): Likewise. (valid_mode_changes_for_regno): Likewise. (make_debug_expr_from_rtl): Likewise. (delete_vta_debug_insns): Likewise. (simplify_using_condition): Likewise. (set_insn_locations): Likewise. (fatal_insn_not_found): Likewise. (word_register_operation_p): Likewise. * rtlanal.cc (get_call_fndecl): Likewise. (side_effects_p): Likewise. (subreg_nregs): Likewise. (rtx_cost): Likewise. (canonicalize_condition): Likewise. * rtlanal.h (rtx_properties::try_to_add_note): Likewise. * run-rtl-passes.cc (run_rtl_passes): Likewise. * sanitizer.def (BUILT_IN_ASAN_VERSION_MISMATCH_CHECK): Likewise. * sched-deps.cc (add_dependence_1): Likewise. * sched-ebb.cc (begin_move_insn): Likewise. (add_deps_for_risky_insns): Likewise. (advance_target_bb): Likewise. * sched-int.h (reemit_notes): Likewise. (struct _haifa_insn_data): Likewise. (HID): Likewise. (DEP_CANCELLED): Likewise. (debug_ds): Likewise. (number_in_ready): Likewise. (schedule_ebbs_finish): Likewise. (find_modifiable_mems): Likewise. * sched-rgn.cc (debug_rgn_dependencies): Likewise. * sel-sched-dump.cc (dump_lv_set): Likewise. * sel-sched-dump.h: Likewise. * sel-sched-ir.cc (sel_insn_rtx_cost): Likewise. (setup_id_reg_sets): Likewise. (has_dependence_p): Likewise. (sel_num_cfg_preds_gt_1): Likewise. (bb_ends_ebb_p): Likewise. * sel-sched-ir.h (struct _list_node): Likewise. (struct idata_def): Likewise. (bb_next_bb): Likewise. * sel-sched.cc (vinsn_writes_one_of_regs_p): Likewise. (choose_best_pseudo_reg): Likewise. (verify_target_availability): Likewise. (can_speculate_dep_p): Likewise. (sel_rank_for_schedule): Likewise. * selftest-run-tests.cc (selftest::run_tests): Likewise. * selftest.h (class auto_fix_quotes): Likewise. * shrink-wrap.cc (handle_simple_exit): Likewise. * shrink-wrap.h: Likewise. * simplify-rtx.cc (simplify_context::simplify_associative_operation): Likewise. (simplify_context::simplify_gen_vec_select): Likewise. * spellcheck-tree.h: Likewise. * spellcheck.h: Likewise. * statistics.h (struct function): Likewise. * stmt.cc (conditional_probability): Likewise. * stmt.h: Likewise. * stor-layout.h: Likewise. * streamer-hooks.h: Likewise. * stringpool.h: Likewise. * symtab.cc (symbol_table::change_decl_assembler_name): Likewise. * target.def (HOOK_VECTOR_END): Likewise. (type.): Likewise. * target.h (union cumulative_args_t): Likewise. (by_pieces_ninsns): Likewise. (class predefined_function_abi): Likewise. * targhooks.cc (default_translate_mode_attribute): Likewise. * timevar.def: Likewise. * timevar.h (class timer): Likewise. * toplev.h (enable_rtl_dump_file): Likewise. * trans-mem.cc (collect_bb2reg): Likewise. * tree-call-cdce.cc (gen_conditions_for_pow): Likewise. * tree-cfg.cc (remove_bb): Likewise. (verify_gimple_debug): Likewise. (remove_edge_and_dominated_blocks): Likewise. (push_fndecl): Likewise. * tree-cfgcleanup.h (GCC_TREE_CFGCLEANUP_H): Likewise. * tree-complex.cc (expand_complex_multiplication): Likewise. (expand_complex_div_straight): Likewise. * tree-core.h (enum tree_index): Likewise. (enum operand_equal_flag): Likewise. * tree-eh.cc (honor_protect_cleanup_actions): Likewise. * tree-if-conv.cc (if_convertible_gimple_assign_stmt_p): Likewise. * tree-inline.cc (initialize_inlined_parameters): Likewise. * tree-inline.h (force_value_to_type): Likewise. * tree-nested.cc (get_chain_decl): Likewise. (walk_all_functions): Likewise. * tree-object-size.h: Likewise. * tree-outof-ssa.cc: Likewise. * tree-parloops.cc (create_parallel_loop): Likewise. * tree-pretty-print.cc (print_generic_expr_to_str): Likewise. (dump_generic_node): Likewise. * tree-profile.cc (tree_profiling): Likewise. * tree-sra.cc (maybe_add_sra_candidate): Likewise. * tree-ssa-address.cc: Likewise. * tree-ssa-alias.cc: Likewise. * tree-ssa-alias.h (ao_ref::max_size_known_p): Likewise. (dump_alias_stats): Likewise. * tree-ssa-ccp.cc: Likewise. * tree-ssa-coalesce.h: Likewise. * tree-ssa-live.cc (remove_unused_scope_block_p): Likewise. * tree-ssa-loop-manip.cc (copy_phi_node_args): Likewise. * tree-ssa-loop-unswitch.cc: Likewise. * tree-ssa-math-opts.cc: Likewise. * tree-ssa-operands.cc (class operands_scanner): Likewise. * tree-ssa-pre.cc: Likewise. * tree-ssa-reassoc.cc (optimize_ops_list): Likewise. (debug_range_entry): Likewise. * tree-ssa-sccvn.cc (eliminate_dom_walker::eliminate_stmt): Likewise. * tree-ssa-sccvn.h (TREE_SSA_SCCVN_H): Likewise. * tree-ssa-scopedtables.cc (add_expr_commutative): Likewise. (equal_mem_array_ref_p): Likewise. * tree-ssa-strlen.cc (is_strlen_related_p): Likewise. * tree-ssa-strlen.h (get_range_strlen_dynamic): Likewise. * tree-ssa-tail-merge.cc (stmt_local_def): Likewise. * tree-ssa-ter.h: Likewise. * tree-ssa-threadupdate.h (enum bb_dom_status): Likewise. * tree-streamer-in.cc (lto_input_ts_block_tree_pointers): Likewise. * tree-streamer-out.cc (pack_ts_block_value_fields): Likewise. (write_ts_block_tree_pointers): Likewise. * tree-streamer.h (struct streamer_tree_cache_d): Likewise. (streamer_read_tree_bitfields): Likewise. (streamer_write_integer_cst): Likewise. * tree-vect-patterns.cc (apply_binop_and_append_stmt): Likewise. (vect_synth_mult_by_constant): Likewise. * tree-vect-stmts.cc (vectorizable_operation): Likewise. * tree-vectorizer.cc: Likewise. * tree-vectorizer.h (class auto_purge_vect_location): Likewise. (vect_update_inits_of_drs): Likewise. (vect_get_mask_type_for_stmt): Likewise. (vect_rgroup_iv_might_wrap_p): Likewise. (cse_and_gimplify_to_preheader): Likewise. (vect_free_slp_tree): Likewise. (vect_pattern_recog): Likewise. (vect_stmt_dominates_stmt_p): Likewise. * tree.cc (initialize_tree_contains_struct): Likewise. (need_assembler_name_p): Likewise. (type_with_interoperable_signedness): Likewise. * tree.def (SWITCH_EXPR): Likewise. * tree.h (TYPE_SYMTAB_ADDRESS): Likewise. (poly_int_tree_p): Likewise. (inlined_function_outer_scope_p): Likewise. (tree_code_for_canonical_type_merging): Likewise. * value-prof.cc: Likewise. * value-prof.h (get_nth_most_common_value): Likewise. (find_func_by_profile_id): Likewise. * value-range.cc (vrp_operand_equal_p): Likewise. * value-range.h: Likewise. * var-tracking.cc: Likewise. * varasm.cc (default_function_section): Likewise. (function_section_1): Likewise. (assemble_variable): Likewise. (handle_vtv_comdat_section): Likewise. * vec.h (struct vec_prefix): Likewise. * vmsdbgout.cc (full_name): Likewise. * vtable-verify.cc: Likewise. * vtable-verify.h (struct vtv_graph_node): Likewise. * xcoffout.cc: Likewise. * xcoffout.h (DEBUG_SYMS_TEXT): Likewise. gcc/ada/ChangeLog: * Make-generated.in: Rename .c names to .cc. * adaint.c: Likewise. * ctrl_c.c (dummy_handler): Likewise. * gcc-interface/Makefile.in: Likewise. * gcc-interface/config-lang.in: Likewise. * gcc-interface/decl.cc (concat_name): Likewise. (init_gnat_decl): Likewise. * gcc-interface/gigi.h (concat_name): Likewise. (init_gnat_utils): Likewise. (build_call_raise_range): Likewise. (gnat_mark_addressable): Likewise. (gnat_protect_expr): Likewise. (gnat_rewrite_reference): Likewise. * gcc-interface/lang-specs.h (ADA_DUMPS_OPTIONS): Likewise. * gcc-interface/utils.cc (GTY): Likewise. (add_deferred_type_context): Likewise. (init_gnat_utils): Likewise. * gcc-interface/utils2.cc (gnat_stable_expr_p): Likewise. (gnat_protect_expr): Likewise. (gnat_stabilize_reference_1): Likewise. (gnat_rewrite_reference): Likewise. * gsocket.h: Likewise. * init.cc (__gnat_error_handler): Likewise. * libgnarl/s-intman.ads: Likewise. * libgnarl/s-osinte__android.ads: Likewise. * libgnarl/s-osinte__darwin.ads: Likewise. * libgnarl/s-osinte__hpux.ads: Likewise. * libgnarl/s-osinte__linux.ads: Likewise. * libgnarl/s-osinte__qnx.ads: Likewise. * libgnarl/s-taskin.ads: Likewise. * rtfinal.cc: Likewise. * s-oscons-tmplt.c (CND): Likewise. * set_targ.ads: Likewise. gcc/analyzer/ChangeLog: * analyzer.cc (is_special_named_call_p): Rename .c names to .cc. (is_named_call_p): Likewise. * region-model-asm.cc (deterministic_p): Likewise. * region.cc (field_region::get_relative_concrete_offset): Likewise. * sm-malloc.cc (method_p): Likewise. * supergraph.cc (superedge::dump_dot): Likewise. gcc/c-family/ChangeLog: * c-ada-spec.cc: Rename .c names to .cc. * c-ada-spec.h: Likewise. * c-common.cc (c_build_vec_convert): Likewise. (warning_candidate_p): Likewise. * c-common.h (enum rid): Likewise. (build_real_imag_expr): Likewise. (finish_label_address_expr): Likewise. (c_get_substring_location): Likewise. (c_build_bind_expr): Likewise. (conflict_marker_get_final_tok_kind): Likewise. (c_parse_error): Likewise. (check_missing_format_attribute): Likewise. (invalid_array_size_error): Likewise. (warn_for_multistatement_macros): Likewise. (build_attr_access_from_parms): Likewise. * c-cppbuiltin.cc (c_cpp_builtins): Likewise. * c-format.cc: Likewise. * c-gimplify.cc (c_gimplify_expr): Likewise. * c-indentation.h: Likewise. * c-objc.h (objc_prop_attr_kind_for_rid): Likewise. * c-omp.cc (c_omp_predetermined_mapping): Likewise. * c-opts.cc (c_common_post_options): Likewise. (set_std_cxx23): Likewise. * c-pragma.cc (handle_pragma_redefine_extname): Likewise. * c-pretty-print.h: Likewise. gcc/c/ChangeLog: * Make-lang.in: Rename .c names to .cc. * c-convert.cc: Likewise. * c-decl.cc (struct lang_identifier): Likewise. (pop_scope): Likewise. (finish_decl): Likewise. * c-objc-common.h (GCC_C_OBJC_COMMON): Likewise. * c-parser.cc (c_parser_skip_to_end_of_block_or_statement): Likewise. * c-parser.h (GCC_C_PARSER_H): Likewise. * c-tree.h (c_keyword_starts_typename): Likewise. (finish_declspecs): Likewise. (c_get_alias_set): Likewise. (enum c_oracle_request): Likewise. (tag_exists_p): Likewise. (set_c_expr_source_range): Likewise. * c-typeck.cc (c_common_type): Likewise. (c_finish_omp_clauses): Likewise. * config-lang.in: Likewise. gcc/cp/ChangeLog: * Make-lang.in: Rename .c names to .cc. * config-lang.in: Likewise. * constexpr.cc (cxx_eval_constant_expression): Likewise. * coroutines.cc (morph_fn_to_coro): Likewise. * cp-gimplify.cc (cp_gimplify_expr): Likewise. * cp-lang.cc (struct lang_hooks): Likewise. (get_template_argument_pack_elems_folded): Likewise. * cp-objcp-common.cc (cp_tree_size): Likewise. (cp_unit_size_without_reusable_padding): Likewise. (pop_file_scope): Likewise. (cp_pushdecl): Likewise. * cp-objcp-common.h (GCC_CP_OBJCP_COMMON): Likewise. (cxx_simulate_record_decl): Likewise. * cp-tree.h (struct named_label_entry): Likewise. (current_function_return_value): Likewise. (more_aggr_init_expr_args_p): Likewise. (get_function_version_dispatcher): Likewise. (common_enclosing_class): Likewise. (strip_fnptr_conv): Likewise. (current_decl_namespace): Likewise. (do_aggregate_paren_init): Likewise. (cp_check_const_attributes): Likewise. (qualified_name_lookup_error): Likewise. (generic_targs_for): Likewise. (mark_exp_read): Likewise. (is_global_friend): Likewise. (maybe_reject_flexarray_init): Likewise. (module_token_lang): Likewise. (handle_module_option): Likewise. (literal_integer_zerop): Likewise. (build_extra_args): Likewise. (build_if_nonnull): Likewise. (maybe_check_overriding_exception_spec): Likewise. (finish_omp_target_clauses): Likewise. (maybe_warn_zero_as_null_pointer_constant): Likewise. (cxx_print_error_function): Likewise. (decl_in_std_namespace_p): Likewise. (merge_exception_specifiers): Likewise. (mangle_module_global_init): Likewise. (cxx_block_may_fallthru): Likewise. (fold_builtin_source_location): Likewise. (enum cp_oracle_request): Likewise. (subsumes): Likewise. (cp_finish_injected_record_type): Likewise. (vtv_build_vtable_verify_fndecl): Likewise. (cp_tree_c_finish_parsing): Likewise. * cvt.cc (diagnose_ref_binding): Likewise. (convert_to_void): Likewise. (convert_force): Likewise. (type_promotes_to): Likewise. * decl.cc (make_unbound_class_template_raw): Likewise. (cxx_init_decl_processing): Likewise. (check_class_member_definition_namespace): Likewise. (cxx_maybe_build_cleanup): Likewise. * decl2.cc (maybe_emit_vtables): Likewise. * error.cc (dump_function_name): Likewise. * init.cc (is_class_type): Likewise. (build_new_1): Likewise. * lang-specs.h: Likewise. * method.cc (make_alias_for_thunk): Likewise. * module.cc (specialization_add): Likewise. (module_state::read_cluster): Likewise. * name-lookup.cc (check_extern_c_conflict): Likewise. * name-lookup.h (struct cxx_binding): Likewise. * parser.cc (cp_parser_identifier): Likewise. * parser.h (struct cp_parser): Likewise. * pt.cc (has_value_dependent_address): Likewise. (push_tinst_level_loc): Likewise. * semantics.cc (finish_omp_clauses): Likewise. (finish_omp_atomic): Likewise. * tree.cc (cp_save_expr): Likewise. (cp_free_lang_data): Likewise. * typeck.cc (cp_common_type): Likewise. (strip_array_domain): Likewise. (rationalize_conditional_expr): Likewise. (check_return_expr): Likewise. * vtable-class-hierarchy.cc: Likewise. gcc/d/ChangeLog: * d-gimplify.cc: Rename .c names to .cc. * d-incpath.cc: Likewise. * lang-specs.h: Likewise. gcc/fortran/ChangeLog: * check.cc (gfc_check_all_any): Rename .c names to .cc. * class.cc (find_intrinsic_vtab): Likewise. * config-lang.in: Likewise. * cpp.cc (cpp_define_builtins): Likewise. * data.cc (get_array_index): Likewise. * decl.cc (match_clist_expr): Likewise. (get_proc_name): Likewise. (gfc_verify_c_interop_param): Likewise. (gfc_get_pdt_instance): Likewise. (gfc_match_formal_arglist): Likewise. (gfc_get_type_attr_spec): Likewise. * dependency.cc: Likewise. * error.cc (gfc_format_decoder): Likewise. * expr.cc (check_restricted): Likewise. (gfc_build_default_init_expr): Likewise. * f95-lang.cc: Likewise. * gfc-internals.texi: Likewise. * gfortran.h (enum match): Likewise. (enum procedure_type): Likewise. (enum oacc_routine_lop): Likewise. (gfc_get_pdt_instance): Likewise. (gfc_end_source_files): Likewise. (gfc_mpz_set_hwi): Likewise. (gfc_get_option_string): Likewise. (gfc_find_sym_in_expr): Likewise. (gfc_errors_to_warnings): Likewise. (gfc_real_4_kind): Likewise. (gfc_free_finalizer): Likewise. (gfc_sym_get_dummy_args): Likewise. (gfc_check_intrinsic_standard): Likewise. (gfc_free_case_list): Likewise. (gfc_resolve_oacc_routines): Likewise. (gfc_check_vardef_context): Likewise. (gfc_free_association_list): Likewise. (gfc_implicit_pure_function): Likewise. (gfc_ref_dimen_size): Likewise. (gfc_compare_actual_formal): Likewise. (gfc_resolve_wait): Likewise. (gfc_dt_upper_string): Likewise. (gfc_generate_module_code): Likewise. (gfc_delete_bbt): Likewise. (debug): Likewise. (gfc_build_block_ns): Likewise. (gfc_dep_difference): Likewise. (gfc_invalid_null_arg): Likewise. (gfc_is_finalizable): Likewise. (gfc_fix_implicit_pure): Likewise. (gfc_is_size_zero_array): Likewise. (gfc_is_reallocatable_lhs): Likewise. * gfortranspec.cc: Likewise. * interface.cc (compare_actual_expr): Likewise. * intrinsic.cc (add_functions): Likewise. * iresolve.cc (gfc_resolve_matmul): Likewise. (gfc_resolve_alarm_sub): Likewise. * iso-c-binding.def: Likewise. * lang-specs.h: Likewise. * libgfortran.h (GFC_STDERR_UNIT_NUMBER): Likewise. * match.cc (gfc_match_label): Likewise. (gfc_match_symbol): Likewise. (match_derived_type_spec): Likewise. (copy_ts_from_selector_to_associate): Likewise. * match.h (gfc_match_call): Likewise. (gfc_get_common): Likewise. (gfc_match_omp_end_single): Likewise. (gfc_match_volatile): Likewise. (gfc_match_bind_c): Likewise. (gfc_match_literal_constant): Likewise. (gfc_match_init_expr): Likewise. (gfc_match_array_constructor): Likewise. (gfc_match_end_interface): Likewise. (gfc_match_print): Likewise. (gfc_match_expr): Likewise. * matchexp.cc (next_operator): Likewise. * mathbuiltins.def: Likewise. * module.cc (free_true_name): Likewise. * openmp.cc (gfc_resolve_omp_parallel_blocks): Likewise. (gfc_omp_save_and_clear_state): Likewise. * parse.cc (parse_union): Likewise. (set_syms_host_assoc): Likewise. * resolve.cc (resolve_actual_arglist): Likewise. (resolve_elemental_actual): Likewise. (check_host_association): Likewise. (resolve_typebound_function): Likewise. (resolve_typebound_subroutine): Likewise. (gfc_resolve_expr): Likewise. (resolve_assoc_var): Likewise. (resolve_typebound_procedures): Likewise. (resolve_equivalence_derived): Likewise. * simplify.cc (simplify_bound): Likewise. * symbol.cc (gfc_set_default_type): Likewise. (gfc_add_ext_attribute): Likewise. * target-memory.cc (gfc_target_interpret_expr): Likewise. * target-memory.h (gfc_target_interpret_expr): Likewise. * trans-array.cc (gfc_get_cfi_dim_sm): Likewise. (gfc_conv_shift_descriptor_lbound): Likewise. (gfc_could_be_alias): Likewise. (gfc_get_dataptr_offset): Likewise. * trans-const.cc: Likewise. * trans-decl.cc (trans_function_start): Likewise. (gfc_trans_deferred_vars): Likewise. (generate_local_decl): Likewise. (gfc_generate_function_code): Likewise. * trans-expr.cc (gfc_vptr_size_get): Likewise. (gfc_trans_class_array_init_assign): Likewise. (POWI_TABLE_SIZE): Likewise. (gfc_conv_procedure_call): Likewise. (gfc_trans_arrayfunc_assign): Likewise. * trans-intrinsic.cc (gfc_conv_intrinsic_len): Likewise. (gfc_conv_intrinsic_loc): Likewise. (conv_intrinsic_event_query): Likewise. * trans-io.cc (gfc_build_st_parameter): Likewise. * trans-openmp.cc (gfc_omp_check_optional_argument): Likewise. (gfc_omp_unshare_expr_r): Likewise. (gfc_trans_omp_array_section): Likewise. (gfc_trans_omp_clauses): Likewise. * trans-stmt.cc (trans_associate_var): Likewise. (gfc_trans_deallocate): Likewise. * trans-stmt.h (gfc_trans_class_init_assign): Likewise. (gfc_trans_deallocate): Likewise. (gfc_trans_oacc_declare): Likewise. * trans-types.cc: Likewise. * trans-types.h (enum gfc_packed): Likewise. * trans.cc (N_): Likewise. (trans_code): Likewise. * trans.h (gfc_build_compare_string): Likewise. (gfc_conv_expr_type): Likewise. (gfc_trans_deferred_vars): Likewise. (getdecls): Likewise. (gfc_get_array_descr_info): Likewise. (gfc_omp_firstprivatize_type_sizes): Likewise. (GTY): Likewise. gcc/go/ChangeLog: * config-lang.in: Rename .c names to .cc. * go-backend.cc: Likewise. * go-lang.cc: Likewise. * gospec.cc: Likewise. * lang-specs.h: Likewise. gcc/jit/ChangeLog: * config-lang.in: Rename .c names to .cc. * docs/_build/texinfo/libgccjit.texi: Likewise. * docs/internals/index.rst: Likewise. * jit-builtins.cc (builtins_manager::make_builtin_function): Likewise. * jit-playback.cc (fold_const_var): Likewise. (playback::context::~context): Likewise. (new_field): Likewise. (new_bitfield): Likewise. (new_compound_type): Likewise. (playback::compound_type::set_fields): Likewise. (global_set_init_rvalue): Likewise. (load_blob_in_ctor): Likewise. (new_global_initialized): Likewise. (double>): Likewise. (new_string_literal): Likewise. (as_truth_value): Likewise. (build_call): Likewise. (playback::context::build_cast): Likewise. (new_array_access): Likewise. (new_field_access): Likewise. (dereference): Likewise. (postprocess): Likewise. (add_jump): Likewise. (add_switch): Likewise. (build_goto_operands): Likewise. (playback::context::read_dump_file): Likewise. (init_types): Likewise. * jit-recording.cc (recording::context::get_int_type): Likewise. * jit-recording.h: Likewise. * libgccjit.cc (compatible_types): Likewise. (gcc_jit_context_acquire): Likewise. (gcc_jit_context_release): Likewise. (gcc_jit_context_new_child_context): Likewise. (gcc_jit_type_as_object): Likewise. (gcc_jit_context_get_type): Likewise. (gcc_jit_context_get_int_type): Likewise. (gcc_jit_type_get_pointer): Likewise. (gcc_jit_type_get_const): Likewise. (gcc_jit_type_get_volatile): Likewise. (gcc_jit_type_dyncast_array): Likewise. (gcc_jit_type_is_bool): Likewise. (gcc_jit_type_is_pointer): Likewise. (gcc_jit_type_is_integral): Likewise. (gcc_jit_type_dyncast_vector): Likewise. (gcc_jit_type_is_struct): Likewise. (gcc_jit_vector_type_get_num_units): Likewise. (gcc_jit_vector_type_get_element_type): Likewise. (gcc_jit_type_unqualified): Likewise. (gcc_jit_type_dyncast_function_ptr_type): Likewise. (gcc_jit_function_type_get_return_type): Likewise. (gcc_jit_function_type_get_param_count): Likewise. (gcc_jit_function_type_get_param_type): Likewise. (gcc_jit_context_new_array_type): Likewise. (gcc_jit_context_new_field): Likewise. (gcc_jit_field_as_object): Likewise. (gcc_jit_context_new_struct_type): Likewise. (gcc_jit_struct_as_type): Likewise. (gcc_jit_struct_set_fields): Likewise. (gcc_jit_struct_get_field_count): Likewise. (gcc_jit_context_new_union_type): Likewise. (gcc_jit_context_new_function_ptr_type): Likewise. (gcc_jit_param_as_rvalue): Likewise. (gcc_jit_context_new_function): Likewise. (gcc_jit_function_get_return_type): Likewise. (gcc_jit_function_dump_to_dot): Likewise. (gcc_jit_block_get_function): Likewise. (gcc_jit_global_set_initializer_rvalue): Likewise. (gcc_jit_rvalue_get_type): Likewise. (gcc_jit_context_new_rvalue_from_int): Likewise. (gcc_jit_context_one): Likewise. (gcc_jit_context_new_rvalue_from_double): Likewise. (gcc_jit_context_null): Likewise. (gcc_jit_context_new_string_literal): Likewise. (valid_binary_op_p): Likewise. (gcc_jit_context_new_binary_op): Likewise. (gcc_jit_context_new_comparison): Likewise. (gcc_jit_context_new_call): Likewise. (is_valid_cast): Likewise. (gcc_jit_context_new_cast): Likewise. (gcc_jit_object_get_context): Likewise. (gcc_jit_object_get_debug_string): Likewise. (gcc_jit_lvalue_access_field): Likewise. (gcc_jit_rvalue_access_field): Likewise. (gcc_jit_rvalue_dereference_field): Likewise. (gcc_jit_rvalue_dereference): Likewise. (gcc_jit_lvalue_get_address): Likewise. (gcc_jit_lvalue_set_tls_model): Likewise. (gcc_jit_lvalue_set_link_section): Likewise. (gcc_jit_function_new_local): Likewise. (gcc_jit_block_add_eval): Likewise. (gcc_jit_block_add_assignment): Likewise. (is_bool): Likewise. (gcc_jit_block_end_with_conditional): Likewise. (gcc_jit_block_add_comment): Likewise. (gcc_jit_block_end_with_jump): Likewise. (gcc_jit_block_end_with_return): Likewise. (gcc_jit_block_end_with_void_return): Likewise. (case_range_validator::case_range_validator): Likewise. (case_range_validator::validate): Likewise. (case_range_validator::get_wide_int): Likewise. (gcc_jit_block_end_with_switch): Likewise. (gcc_jit_context_set_str_option): Likewise. (gcc_jit_context_set_int_option): Likewise. (gcc_jit_context_set_bool_option): Likewise. (gcc_jit_context_set_bool_allow_unreachable_blocks): Likewise. (gcc_jit_context_set_bool_use_external_driver): Likewise. (gcc_jit_context_add_command_line_option): Likewise. (gcc_jit_context_add_driver_option): Likewise. (gcc_jit_context_enable_dump): Likewise. (gcc_jit_context_compile): Likewise. (gcc_jit_context_compile_to_file): Likewise. (gcc_jit_context_set_logfile): Likewise. (gcc_jit_context_dump_reproducer_to_file): Likewise. (gcc_jit_context_get_first_error): Likewise. (gcc_jit_context_get_last_error): Likewise. (gcc_jit_result_get_code): Likewise. (gcc_jit_result_get_global): Likewise. (gcc_jit_rvalue_set_bool_require_tail_call): Likewise. (gcc_jit_type_get_aligned): Likewise. (gcc_jit_type_get_vector): Likewise. (gcc_jit_function_get_address): Likewise. (gcc_jit_version_patchlevel): Likewise. (gcc_jit_block_add_extended_asm): Likewise. (gcc_jit_extended_asm_as_object): Likewise. (gcc_jit_extended_asm_set_volatile_flag): Likewise. (gcc_jit_extended_asm_set_inline_flag): Likewise. (gcc_jit_extended_asm_add_output_operand): Likewise. (gcc_jit_extended_asm_add_input_operand): Likewise. (gcc_jit_extended_asm_add_clobber): Likewise. * notes.txt: Likewise. gcc/lto/ChangeLog: * config-lang.in: Rename .c names to .cc. * lang-specs.h: Likewise. * lto-common.cc (gimple_register_canonical_type_1): Likewise. * lto-common.h: Likewise. * lto-dump.cc (lto_main): Likewise. * lto-lang.cc (handle_fnspec_attribute): Likewise. (lto_getdecls): Likewise. (lto_init): Likewise. * lto.cc (lto_main): Likewise. * lto.h: Likewise. gcc/objc/ChangeLog: * Make-lang.in: Rename .c names to .cc. * config-lang.in: Likewise. * lang-specs.h: Likewise. * objc-act.cc (objc_build_component_ref): Likewise. (objc_copy_binfo): Likewise. (lookup_method_in_hash_lists): Likewise. (objc_finish_foreach_loop): Likewise. * objc-act.h (objc_common_init_ts): Likewise. * objc-gnu-runtime-abi-01.cc: Likewise. * objc-lang.cc (struct lang_hooks): Likewise. * objc-map.cc: Likewise. * objc-next-runtime-abi-01.cc (generate_objc_symtab_decl): Likewise. * objc-runtime-shared-support.cc: Likewise. * objc-runtime-shared-support.h (build_protocol_initializer): Likewise. gcc/objcp/ChangeLog: * Make-lang.in: Rename .c names to .cc. * config-lang.in: Likewise. * lang-specs.h: Likewise. * objcp-decl.cc (objcp_end_compound_stmt): Likewise. * objcp-lang.cc (struct lang_hooks): Likewise. gcc/po/ChangeLog: * EXCLUDES: Rename .c names to .cc. libcpp/ChangeLog: * Makefile.in: Rename .c names to .cc. * charset.cc (convert_escape): Likewise. * directives.cc (directive_diagnostics): Likewise. (_cpp_handle_directive): Likewise. (lex_macro_node): Likewise. * include/cpplib.h (struct _cpp_file): Likewise. (PURE_ZERO): Likewise. (cpp_defined): Likewise. (cpp_error_at): Likewise. (cpp_forall_identifiers): Likewise. (cpp_compare_macros): Likewise. (cpp_get_converted_source): Likewise. (cpp_read_state): Likewise. (cpp_directive_only_process): Likewise. (struct cpp_decoded_char): Likewise. * include/line-map.h (enum lc_reason): Likewise. (enum location_aspect): Likewise. * include/mkdeps.h: Likewise. * init.cc (cpp_destroy): Likewise. (cpp_finish): Likewise. * internal.h (struct cpp_reader): Likewise. (_cpp_defined_macro_p): Likewise. (_cpp_backup_tokens_direct): Likewise. (_cpp_destroy_hashtable): Likewise. (_cpp_has_header): Likewise. (_cpp_expand_op_stack): Likewise. (_cpp_commit_buff): Likewise. (_cpp_restore_special_builtin): Likewise. (_cpp_bracket_include): Likewise. (_cpp_replacement_text_len): Likewise. (ufputs): Likewise. * line-map.cc (linemap_macro_loc_to_exp_point): Likewise. (linemap_check_files_exited): Likewise. (line_map_new_raw): Likewise. * traditional.cc (enum ls): Likewise. --- gcc/c/Make-lang.in | 10 +++++----- gcc/c/c-convert.cc | 10 +++++----- gcc/c/c-decl.cc | 6 +++--- gcc/c/c-objc-common.h | 2 +- gcc/c/c-parser.cc | 2 +- gcc/c/c-parser.h | 2 +- gcc/c/c-tree.h | 22 +++++++++++----------- gcc/c/c-typeck.cc | 4 ++-- gcc/c/config-lang.in | 2 +- 9 files changed, 30 insertions(+), 30 deletions(-) (limited to 'gcc/c') diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in index b0e9994..1367a10 100644 --- a/gcc/c/Make-lang.in +++ b/gcc/c/Make-lang.in @@ -71,15 +71,15 @@ endif # compute checksum over all object files and the options # re-use the checksum from the prev-final stage so it passes # the bootstrap comparison and allows comparing of the cc1 binary -cc1-checksum.c : build/genchecksum$(build_exeext) checksum-options \ +cc1-checksum.cc : build/genchecksum$(build_exeext) checksum-options \ $(C_OBJS) $(BACKEND) $(LIBDEPS) if [ -f ../stage_final ] \ && cmp -s ../stage_current ../stage_final; then \ - cp ../prev-gcc/cc1-checksum.c cc1-checksum.c; \ + cp ../prev-gcc/cc1-checksum.cc cc1-checksum.cc; \ else \ build/genchecksum$(build_exeext) $(C_OBJS) $(BACKEND) $(LIBDEPS) \ - checksum-options > cc1-checksum.c.tmp && \ - $(srcdir)/../move-if-change cc1-checksum.c.tmp cc1-checksum.c; \ + checksum-options > cc1-checksum.cc.tmp && \ + $(srcdir)/../move-if-change cc1-checksum.cc.tmp cc1-checksum.cc; \ fi cc1$(exeext): $(C_OBJS) cc1-checksum.o $(BACKEND) $(LIBDEPS) @@ -106,7 +106,7 @@ c.all.cross: c.start.encap: c.rest.encap: c.srcinfo: -c.srcextra: gengtype-lex.c +c.srcextra: gengtype-lex.cc -cp -p $^ $(srcdir) c.tags: force cd $(srcdir)/c; $(ETAGS) -o TAGS.sub *.c *.h; \ diff --git a/gcc/c/c-convert.cc b/gcc/c/c-convert.cc index 5e92759..18083d5 100644 --- a/gcc/c/c-convert.cc +++ b/gcc/c/c-convert.cc @@ -45,12 +45,12 @@ along with GCC; see the file COPYING3. If not see Here is a list of all the functions that assume that widening and narrowing is always done with a NOP_EXPR: - In convert.c, convert_to_integer. - In c-typeck.c, build_binary_op (boolean ops), and + In convert.cc, convert_to_integer. + In c-typeck.cc, build_binary_op (boolean ops), and c_common_truthvalue_conversion. - In expr.c: expand_expr, for operands of a MULT_EXPR. - In fold-const.c: fold. - In tree.c: get_narrower and get_unwidened. */ + In expr.cc: expand_expr, for operands of a MULT_EXPR. + In fold-const.cc: fold. + In tree.cc: get_narrower and get_unwidened. */ /* Subroutines of `convert'. */ diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 29a79eb..c701f07 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -225,7 +225,7 @@ struct GTY(()) lang_identifier { struct c_binding *label_binding; /* labels */ }; -/* Validate c-lang.c's assumptions. */ +/* Validate c-lang.cc's assumptions. */ extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate [(sizeof(struct lang_identifier) == C_SIZEOF_STRUCT_LANG_IDENTIFIER) ? 1 : -1]; @@ -1367,7 +1367,7 @@ pop_scope (void) gcc_fallthrough (); /* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have already been put there by store_parm_decls. Unused- - parameter warnings are handled by function.c. + parameter warnings are handled by function.cc. error_mark_node obviously does not go in BLOCK_VARS and does not get unused-variable warnings. */ case PARM_DECL: @@ -5527,7 +5527,7 @@ finish_decl (tree decl, location_t init_loc, tree init, if (TREE_PUBLIC (decl)) c_determine_visibility (decl); - /* This is a no-op in c-lang.c or something real in objc-act.c. */ + /* This is a no-op in c-lang.cc or something real in objc-act.cc. */ if (c_dialect_objc ()) objc_check_decl (decl); diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h index d23bdea..0b60df9 100644 --- a/gcc/c/c-objc-common.h +++ b/gcc/c/c-objc-common.h @@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see #define GCC_C_OBJC_COMMON /* Lang hooks that are shared between C and ObjC are defined here. Hooks - specific to C or ObjC go in c-lang.c and objc/objc-lang.c, respectively. */ + specific to C or ObjC go in c-lang.cc and objc/objc-lang.cc, respectively. */ #undef LANG_HOOKS_IDENTIFIER_SIZE #define LANG_HOOKS_IDENTIFIER_SIZE C_SIZEOF_STRUCT_LANG_IDENTIFIER diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 20774f7..e9086c5 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -1413,7 +1413,7 @@ c_parser_skip_to_end_of_block_or_statement (c_parser *parser) parser->error = false; } -/* CPP's options (initialized by c-opts.c). */ +/* CPP's options (initialized by c-opts.cc). */ extern cpp_options *cpp_opts; /* Save the warning flags which are controlled by __extension__. */ diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h index 8d5fc30..3d256b6 100644 --- a/gcc/c/c-parser.h +++ b/gcc/c/c-parser.h @@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_C_PARSER_H #define GCC_C_PARSER_H -/* The C lexer intermediates between the lexer in cpplib and c-lex.c +/* The C lexer intermediates between the lexer in cpplib and c-lex.cc and the C parser. Unlike the C++ lexer, the parser structure stores the lexer information instead of using a separate structure. Identifiers are separated into ordinary identifiers, type names, diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index df03fd2..c70f0ba 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -23,8 +23,8 @@ along with GCC; see the file COPYING3. If not see #include "c-family/c-common.h" #include "diagnostic.h" -/* struct lang_identifier is private to c-decl.c, but langhooks.c needs to - know how big it is. This is sanity-checked in c-decl.c. */ +/* struct lang_identifier is private to c-decl.cc, but langhooks.cc needs to + know how big it is. This is sanity-checked in c-decl.cc. */ #define C_SIZEOF_STRUCT_LANG_IDENTIFIER \ (sizeof (struct c_common_identifier) + 3 * sizeof (void *)) @@ -538,14 +538,14 @@ enum c_inline_static_type { }; -/* in c-parser.c */ +/* in c-parser.cc */ extern void c_parse_init (void); extern bool c_keyword_starts_typename (enum rid keyword); -/* in c-aux-info.c */ +/* in c-aux-info.cc */ extern void gen_aux_info_record (tree, int, int, int); -/* in c-decl.c */ +/* in c-decl.cc */ struct c_spot_bindings; class c_struct_parse_info; extern struct obstack parser_obstack; @@ -660,7 +660,7 @@ extern struct c_declspecs *declspecs_add_alignas (location_t, struct c_declspecs *, tree); extern struct c_declspecs *finish_declspecs (struct c_declspecs *); -/* in c-objc-common.c */ +/* in c-objc-common.cc */ extern bool c_objc_common_init (void); extern bool c_missing_noreturn_ok_p (tree); extern bool c_warn_unused_global_decl (const_tree); @@ -668,7 +668,7 @@ extern void c_initialize_diagnostics (diagnostic_context *); extern bool c_vla_unspec_p (tree x, tree fn); extern alias_set_type c_get_alias_set (tree); -/* in c-typeck.c */ +/* in c-typeck.cc */ extern int in_alignof; extern int in_sizeof; extern int in_typeof; @@ -783,7 +783,7 @@ extern int current_function_returns_null; extern int current_function_returns_abnormally; -/* In c-decl.c */ +/* In c-decl.cc */ /* Tell the binding oracle what kind of binding we are looking for. */ @@ -798,7 +798,7 @@ enum c_oracle_request create bindings when needed by the C compiler. The oracle is told the name and type of the binding to create. It can call pushdecl or the like to ensure the binding is visible; or do nothing, - leaving the binding untouched. c-decl.c takes note of when the + leaving the binding untouched. c-decl.cc takes note of when the oracle has been called and will not call it again if it fails to create a given binding. */ @@ -816,7 +816,7 @@ extern void c_pushtag (location_t, tree, tree); extern void c_bind (location_t, tree, bool); extern bool tag_exists_p (enum tree_code, tree); -/* In c-errors.c */ +/* In c-errors.cc */ extern bool pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); extern bool pedwarn_c99 (location_t, int opt, const char *, ...) @@ -832,7 +832,7 @@ extern void set_c_expr_source_range (c_expr *expr, source_range src_range); -/* In c-fold.c */ +/* In c-fold.cc */ extern vec incomplete_record_decls; #if CHECKING_P diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index ac6618e..b06f078 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1009,7 +1009,7 @@ c_common_type (tree t1, tree t2) return t2; } -/* Wrapper around c_common_type that is used by c-common.c and other +/* Wrapper around c_common_type that is used by c-common.cc and other front end optimizations that remove promotions. ENUMERAL_TYPEs are allowed here and are converted to their compatible integer types. BOOLEAN_TYPEs are allowed here and return either boolean_type_node or @@ -14996,7 +14996,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)) /* For attach/detach clauses, set OMP_CLAUSE_SIZE (representing a bias) to zero here, so it is not set erroneously to the pointer - size later on in gimplify.c. */ + size later on in gimplify.cc. */ OMP_CLAUSE_SIZE (c) = size_zero_node; while (TREE_CODE (t) == INDIRECT_REF || TREE_CODE (t) == ARRAY_REF) diff --git a/gcc/c/config-lang.in b/gcc/c/config-lang.in index cb697e8..4526f63 100644 --- a/gcc/c/config-lang.in +++ b/gcc/c/config-lang.in @@ -29,4 +29,4 @@ compilers="cc1\$(exeext)" target_libs= -gtfiles="\$(srcdir)/c/c-lang.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/c-family/c-format.c \$(srcdir)/c/c-objc-common.c \$(srcdir)/c/c-parser.h \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-lang.h" +gtfiles="\$(srcdir)/c/c-lang.cc \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.cc \$(srcdir)/c-family/c-common.cc \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.cc \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.cc \$(srcdir)/c-family/c-format.cc \$(srcdir)/c/c-objc-common.cc \$(srcdir)/c/c-parser.h \$(srcdir)/c/c-parser.cc \$(srcdir)/c/c-lang.h" -- cgit v1.1 From fc82978278e9339233d1824cb774d7e33fac8d68 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 18 Jan 2022 00:16:54 +0000 Subject: Daily bump. --- gcc/c/ChangeLog | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'gcc/c') diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 8463f0d..012800a 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,52 @@ +2022-01-17 Martin Liska + + * Make-lang.in: Rename .c names to .cc. + * c-convert.cc: Likewise. + * c-decl.cc (struct lang_identifier): Likewise. + (pop_scope): Likewise. + (finish_decl): Likewise. + * c-objc-common.h (GCC_C_OBJC_COMMON): Likewise. + * c-parser.cc (c_parser_skip_to_end_of_block_or_statement): Likewise. + * c-parser.h (GCC_C_PARSER_H): Likewise. + * c-tree.h (c_keyword_starts_typename): Likewise. + (finish_declspecs): Likewise. + (c_get_alias_set): Likewise. + (enum c_oracle_request): Likewise. + (tag_exists_p): Likewise. + (set_c_expr_source_range): Likewise. + * c-typeck.cc (c_common_type): Likewise. + (c_finish_omp_clauses): Likewise. + * config-lang.in: Likewise. + +2022-01-17 Martin Liska + + * 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. + +2022-01-17 Andrew Stubbs + + * c-parser.c (c_parser_omp_requires): Don't "sorry" dynamic_allocators. + 2022-01-14 Chung-Lin Tang PR c++/103705 -- cgit v1.1