From 39dabefd0e5e21b7829ec4ddf811ab19346983d7 Mon Sep 17 00:00:00 2001 From: Steven Bosscher Date: Sat, 5 Jun 2010 20:33:22 +0000 Subject: c-common.c: Move to c-family/. gcc/ChangeLog: * c-common.c: Move to c-family/. * c-common.def: Likewise. * c-common.h: Likewise. * c-cppbuiltin.c: Likewise. * c-dump.c: Likewise. * c-format.c: Likewise. * c-format.h : Likewise. * c-gimplify.c: Likewise. * c-lex.c: Likewise. * c-omp.c: Likewise. * c.opt: Likewise. * c-opts.c: Likewise. * c-pch.c: Likewise. * c-ppoutput.c: Likewise. * c-pragma.c: Likewise. * c-pragma.h: Likewise. * c-pretty-print.c: Likewise. * c-pretty-print.h: Likewise. * c-semantics.c: Likewise. * stub-objc.c: Likewise. * gengtype.c (get_file_langdir): Special-case files in c-family/. (get_output_file_with_visibility): Fix name for c-common.h. * c-config-lang.in: Update paths in gtfiles for files in c-family/. * c-tree.h: Update include path for moved files. * c-lang.c: Likewise. * c-lang.h: Likewise. * c-parser.c: Likewise. * c-convert.c: Likewise. * c-decl.c: Likewise. * c-objc-common.c: Likewise. * configure.ac: Make sure c-family/ exists in the build directory. * configure: Regenerate. * Makefile.in: Update paths for moved files. Regroup files per location and update dependencies. Move generated_files down after ALL_GTFILES_H. * config/spu/spu-c.c: Update paths for moved files. * config/mep/mep-pragma.c: Likewise. * config/darwin-c.c: Likewise. * config/i386/msformat-c.c: Likewise. * config/i386/i386-c.c: Likewise. * config/avr/avr-c.c: Likewise. * config/sol2-c.c: Likewise. * config/ia64/ia64-c.c: Likewise. * config/rs6000/rs6000-c.c: Likewise. * config/arm/arm.c: Likewise. * config/arm/arm-c.c: Likewise. * config/h8300/h8300.c: Likewise. * config/v850/v850-c.c: Likewise. * config/t-darwin: Fix dependencies for moved files. * config/t-sol2: Fix dependencies for moved files. * config/mep/t-mep: Fix dependencies for moved files. * config/ia64/t-ia64: Fix dependencies for moved files. * config/rs6000/t-rs6000: Fix dependencies for moved files. * config/v850/t-v850: Fix dependencies for moved files. * config/v850/t-v850e: Fix dependencies for moved files. * config/m32c/m32c-pragma.c * po/exgettext: Look in c-family/ also. c-family/ChangeLog: * c-common.c: Include gt-c-family-c-common.h. * c-pragma.c: Include gt-c-family-c-pragma.h. objc/ChangeLog: * objc-act.c: Update include path for moved files. * objc-lang.c: Likewise. * config-lang.in: Update paths in gtfiles for files in c-family/. objcp/ChangeLog: * objcp-lang.c: Update include path for moved files. * config-lang.in: Update paths in gtfiles for files in c-family/. cp/ChangeLog: * typeck.c: Update include path for moved files. * decl.c: Likewise. * rtti.c: Likewise. * cp-gimplify.c: Likewise. * cp-lang.c: Likewise. * pt.c: Likewise. * semantics.c: Likewise. * cxx-pretty-print.h: Likewise. * decl2.c: Likewise. * parser.c: Likewise. * cp-objcp-common.c: Likewise. * cp-tree.h: Likewise. * name-lookup.c: Likewise. * lex.c: Likewise. * name-lookup.h: Likewise. * config-lang.in: Update paths in gtfiles for files in c-family/. * Make-lang.in: Likewise. From-SVN: r160330 --- gcc/ChangeLog | 66 + gcc/Makefile.in | 278 +- gcc/c-ada-spec.c | 3230 -------------- gcc/c-ada-spec.h | 41 - gcc/c-common.c | 9466 ----------------------------------------- gcc/c-common.def | 53 - gcc/c-common.h | 1191 ------ gcc/c-config-lang.in | 2 +- gcc/c-convert.c | 2 +- gcc/c-cppbuiltin.c | 1107 ----- gcc/c-decl.c | 6 +- gcc/c-dump.c | 61 - gcc/c-family/ChangeLog | 31 + gcc/c-family/c-ada-spec.c | 3230 ++++++++++++++ gcc/c-family/c-ada-spec.h | 41 + gcc/c-family/c-common.c | 9466 +++++++++++++++++++++++++++++++++++++++++ gcc/c-family/c-common.def | 53 + gcc/c-family/c-common.h | 1191 ++++++ gcc/c-family/c-cppbuiltin.c | 1107 +++++ gcc/c-family/c-dump.c | 61 + gcc/c-family/c-format.c | 2870 +++++++++++++ gcc/c-family/c-format.h | 326 ++ gcc/c-family/c-gimplify.c | 190 + gcc/c-family/c-lex.c | 1058 +++++ gcc/c-family/c-omp.c | 531 +++ gcc/c-family/c-opts.c | 1815 ++++++++ gcc/c-family/c-pch.c | 517 +++ gcc/c-family/c-ppoutput.c | 625 +++ gcc/c-family/c-pragma.c | 1336 ++++++ gcc/c-family/c-pragma.h | 133 + gcc/c-family/c-pretty-print.c | 2282 ++++++++++ gcc/c-family/c-pretty-print.h | 213 + gcc/c-family/c-semantics.c | 146 + gcc/c-family/c.opt | 1060 +++++ gcc/c-family/stub-objc.c | 327 ++ gcc/c-format.c | 2870 ------------- gcc/c-format.h | 326 -- gcc/c-gimplify.c | 190 - gcc/c-lang.c | 4 +- gcc/c-lang.h | 2 +- gcc/c-lex.c | 1058 ----- gcc/c-objc-common.c | 2 +- gcc/c-omp.c | 531 --- gcc/c-opts.c | 1815 -------- gcc/c-parser.c | 4 +- gcc/c-pch.c | 517 --- gcc/c-ppoutput.c | 625 --- gcc/c-pragma.c | 1336 ------ gcc/c-pragma.h | 133 - gcc/c-pretty-print.c | 2282 ---------- gcc/c-pretty-print.h | 213 - gcc/c-semantics.c | 146 - gcc/c-tree.h | 2 +- gcc/c.opt | 1060 ----- gcc/config/arm/arm-c.c | 2 +- gcc/config/arm/arm.c | 2 +- gcc/config/avr/avr-c.c | 2 +- gcc/config/darwin-c.c | 4 +- gcc/config/h8300/h8300.c | 2 +- gcc/config/i386/i386-c.c | 4 +- gcc/config/i386/msformat-c.c | 4 +- gcc/config/ia64/ia64-c.c | 4 +- gcc/config/ia64/t-ia64 | 2 +- gcc/config/m32c/m32c-pragma.c | 2 +- gcc/config/mep/mep-pragma.c | 2 +- gcc/config/mep/t-mep | 2 +- gcc/config/rs6000/rs6000-c.c | 4 +- gcc/config/rs6000/t-rs6000 | 2 +- gcc/config/sol2-c.c | 6 +- gcc/config/spu/spu-c.c | 4 +- gcc/config/t-darwin | 2 +- gcc/config/t-sol2 | 4 +- gcc/config/v850/t-v850 | 2 +- gcc/config/v850/t-v850e | 2 +- gcc/config/v850/v850-c.c | 2 +- gcc/configure | 2 +- gcc/configure.ac | 2 +- gcc/cp/ChangeLog | 20 + gcc/cp/Make-lang.in | 10 +- gcc/cp/config-lang.in | 2 +- gcc/cp/cp-gimplify.c | 2 +- gcc/cp/cp-lang.c | 2 +- gcc/cp/cp-objcp-common.c | 2 +- gcc/cp/cp-tree.h | 2 +- gcc/cp/cxx-pretty-print.h | 2 +- gcc/cp/decl.c | 4 +- gcc/cp/decl2.c | 6 +- gcc/cp/lex.c | 2 +- gcc/cp/name-lookup.c | 2 +- gcc/cp/name-lookup.h | 2 +- gcc/cp/parser.c | 4 +- gcc/cp/pt.c | 2 +- gcc/cp/rtti.c | 2 +- gcc/cp/semantics.c | 2 +- gcc/cp/typeck.c | 2 +- gcc/gengtype.c | 16 +- gcc/objc/ChangeLog | 6 + gcc/objc/config-lang.in | 2 +- gcc/objc/objc-act.c | 4 +- gcc/objc/objc-lang.c | 2 +- gcc/objcp/ChangeLog | 5 + gcc/objcp/config-lang.in | 2 +- gcc/objcp/objcp-lang.c | 2 +- gcc/po/exgettext | 2 +- gcc/stub-objc.c | 327 -- 105 files changed, 28948 insertions(+), 28782 deletions(-) delete mode 100644 gcc/c-ada-spec.c delete mode 100644 gcc/c-ada-spec.h delete mode 100644 gcc/c-common.c delete mode 100644 gcc/c-common.def delete mode 100644 gcc/c-common.h delete mode 100644 gcc/c-cppbuiltin.c delete mode 100644 gcc/c-dump.c create mode 100644 gcc/c-family/ChangeLog create mode 100644 gcc/c-family/c-ada-spec.c create mode 100644 gcc/c-family/c-ada-spec.h create mode 100644 gcc/c-family/c-common.c create mode 100644 gcc/c-family/c-common.def create mode 100644 gcc/c-family/c-common.h create mode 100644 gcc/c-family/c-cppbuiltin.c create mode 100644 gcc/c-family/c-dump.c create mode 100644 gcc/c-family/c-format.c create mode 100644 gcc/c-family/c-format.h create mode 100644 gcc/c-family/c-gimplify.c create mode 100644 gcc/c-family/c-lex.c create mode 100644 gcc/c-family/c-omp.c create mode 100644 gcc/c-family/c-opts.c create mode 100644 gcc/c-family/c-pch.c create mode 100644 gcc/c-family/c-ppoutput.c create mode 100644 gcc/c-family/c-pragma.c create mode 100644 gcc/c-family/c-pragma.h create mode 100644 gcc/c-family/c-pretty-print.c create mode 100644 gcc/c-family/c-pretty-print.h create mode 100644 gcc/c-family/c-semantics.c create mode 100644 gcc/c-family/c.opt create mode 100644 gcc/c-family/stub-objc.c delete mode 100644 gcc/c-format.c delete mode 100644 gcc/c-format.h delete mode 100644 gcc/c-gimplify.c delete mode 100644 gcc/c-lex.c delete mode 100644 gcc/c-omp.c delete mode 100644 gcc/c-opts.c delete mode 100644 gcc/c-pch.c delete mode 100644 gcc/c-ppoutput.c delete mode 100644 gcc/c-pragma.c delete mode 100644 gcc/c-pragma.h delete mode 100644 gcc/c-pretty-print.c delete mode 100644 gcc/c-pretty-print.h delete mode 100644 gcc/c-semantics.c delete mode 100644 gcc/c.opt delete mode 100644 gcc/stub-objc.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7f7ce36..f9415a2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,69 @@ +2010-06-05 Steven Bosscher + + * c-common.c: Move to c-family/. + * c-common.def: Likewise. + * c-common.h: Likewise. + * c-cppbuiltin.c: Likewise. + * c-dump.c: Likewise. + * c-format.c: Likewise. + * c-format.h : Likewise. + * c-gimplify.c: Likewise. + * c-lex.c: Likewise. + * c-omp.c: Likewise. + * c.opt: Likewise. + * c-opts.c: Likewise. + * c-pch.c: Likewise. + * c-ppoutput.c: Likewise. + * c-pragma.c: Likewise. + * c-pragma.h: Likewise. + * c-pretty-print.c: Likewise. + * c-pretty-print.h: Likewise. + * c-semantics.c: Likewise. + * stub-objc.c: Likewise. + + * gengtype.c (get_file_langdir): Special-case files in c-family/. + (get_output_file_with_visibility): Fix name for c-common.h. + * c-config-lang.in: Update paths in gtfiles for files in c-family/. + + * c-tree.h: Update include path for moved files. + * c-lang.c: Likewise. + * c-lang.h: Likewise. + * c-parser.c: Likewise. + * c-convert.c: Likewise. + * c-decl.c: Likewise. + * c-objc-common.c: Likewise. + * configure.ac: Make sure c-family/ exists in the build directory. + * configure: Regenerate. + * Makefile.in: Update paths for moved files. Regroup files per + location and update dependencies. Move generated_files down after + ALL_GTFILES_H. + + * config/spu/spu-c.c: Update paths for moved files. + * config/mep/mep-pragma.c: Likewise. + * config/darwin-c.c: Likewise. + * config/i386/msformat-c.c: Likewise. + * config/i386/i386-c.c: Likewise. + * config/avr/avr-c.c: Likewise. + * config/sol2-c.c: Likewise. + * config/ia64/ia64-c.c: Likewise. + * config/rs6000/rs6000-c.c: Likewise. + * config/arm/arm.c: Likewise. + * config/arm/arm-c.c: Likewise. + * config/h8300/h8300.c: Likewise. + * config/v850/v850-c.c: Likewise. + + * config/t-darwin: Fix dependencies for moved files. + * config/t-sol2: Fix dependencies for moved files. + * config/mep/t-mep: Fix dependencies for moved files. + * config/ia64/t-ia64: Fix dependencies for moved files. + * config/rs6000/t-rs6000: Fix dependencies for moved files. + * config/v850/t-v850: Fix dependencies for moved files. + * config/v850/t-v850e: Fix dependencies for moved files. + + * config/m32c/m32c-pragma.c + + * po/exgettext: Look in c-family/ also. + 2010-06-05 Eric Botcazou * tree-ssa-dce.c (mark_last_stmt_necessary): New function. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index b469850..8d9b808 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -502,7 +502,7 @@ check_gcc_parallelize=execute.exp=execute/2* \ compile.exp dg.exp \ dg-torture.exp,builtins.exp \ struct-layout-1.exp,unsorted.exp,stackalign.exp,i386.exp -lang_opt_files=@lang_opt_files@ $(srcdir)/c.opt $(srcdir)/common.opt +lang_opt_files=@lang_opt_files@ $(srcdir)/c-family/c.opt $(srcdir)/common.opt lang_specs_files=@lang_specs_files@ lang_tree_files=@lang_tree_files@ target_cpu_default=@target_cpu_default@ @@ -873,11 +873,11 @@ FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h RTL_H = $(RTL_BASE_H) genrtl.h vecir.h PARAMS_H = params.h params.def BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def -TREE_H = tree.h all-tree.def tree.def c-common.def $(lang_tree_files) \ - $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \ - $(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \ - double-int.h alias.h $(SYMTAB_H) options.h vecir.h \ - $(REAL_H) $(FIXED_VALUE_H) +TREE_H = tree.h all-tree.def tree.def c-family/c-common.def \ + $(lang_tree_files) $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \ + $(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \ + double-int.h alias.h $(SYMTAB_H) options.h vecir.h \ + $(REAL_H) $(FIXED_VALUE_H) REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) cfghooks.h GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h $(VEC_H) \ @@ -917,8 +917,9 @@ GGC_H = ggc.h gtype-desc.h statistics.h TIMEVAR_H = timevar.h timevar.def INSN_ATTR_H = insn-attr.h $(INSN_ADDR_H) INSN_ADDR_H = $(srcdir)/insn-addr.h vecprim.h -C_COMMON_H = c-common.h $(SPLAY_TREE_H) $(CPPLIB_H) $(GGC_H) $(DIAGNOSTIC_CORE_H) -C_PRAGMA_H = c-pragma.h $(CPPLIB_H) +C_COMMON_H = c-family/c-common.h c-family/c-common.def \ + $(SPLAY_TREE_H) $(CPPLIB_H) $(GGC_H) $(DIAGNOSTIC_CORE_H) +C_PRAGMA_H = c-family/c-pragma.h $(CPPLIB_H) C_TREE_H = c-tree.h $(C_COMMON_H) $(TOPLEV_H) $(DIAGNOSTIC_H) SYSTEM_H = system.h hwint.h $(srcdir)/../include/libiberty.h \ $(srcdir)/../include/safe-ctype.h $(srcdir)/../include/filenames.h @@ -945,7 +946,8 @@ SSAEXPAND_H = ssaexpand.h $(TREE_SSA_LIVE_H) PRETTY_PRINT_H = pretty-print.h $(INPUT_H) $(OBSTACK_H) DIAGNOSTIC_CORE_H = diagnostic-core.h input.h diagnostic.def DIAGNOSTIC_H = diagnostic.h $(DIAGNOSTIC_CORE_H) $(PRETTY_PRINT_H) -C_PRETTY_PRINT_H = c-pretty-print.h $(PRETTY_PRINT_H) $(C_COMMON_H) $(TREE_H) +C_PRETTY_PRINT_H = c-family/c-pretty-print.h $(PRETTY_PRINT_H) \ + $(C_COMMON_H) $(TREE_H) SCEV_H = tree-scalar-evolution.h $(GGC_H) tree-chrec.h $(PARAMS_H) LAMBDA_H = lambda.h $(TREE_H) $(VEC_H) $(GGC_H) TREE_DATA_REF_H = tree-data-ref.h $(LAMBDA_H) omega.h graphds.h $(SCEV_H) @@ -1128,15 +1130,20 @@ FORTRAN_TARGET_OBJS=@fortran_target_objs@ GCC_OBJS = gcc.o opts-common.o gcc-options.o diagnostic.o pretty-print.o \ input.o +# Language-specific object files shared by all C-family front ends. +C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \ + c-family/c-format.o c-family/c-gimplify.o c-family/c-lex.o \ + c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \ + c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \ + c-family/c-semantics.o c-family/c-ada-spec.o + # Language-specific object files for C and Objective C. -C_AND_OBJC_OBJS = attribs.o c-errors.o c-lex.o c-pragma.o c-decl.o c-typeck.o \ - c-convert.o c-aux-info.o c-common.o c-opts.o c-format.o c-semantics.o \ - c-ppoutput.o c-cppbuiltin.o \ - c-objc-common.o c-dump.o c-pch.o c-parser.o $(C_TARGET_OBJS) \ - c-gimplify.o tree-mudflap.o c-pretty-print.o c-omp.o c-ada-spec.o +C_AND_OBJC_OBJS = attribs.o c-errors.o c-decl.o c-typeck.o \ + c-convert.o c-aux-info.o c-objc-common.o c-parser.o tree-mudflap.o \ + $(C_COMMON_OBJS) $(C_TARGET_OBJS) # Language-specific object files for C. -C_OBJS = c-lang.o stub-objc.o $(C_AND_OBJC_OBJS) +C_OBJS = c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS) # Language-independent object files. # We put the insn-*.o files first so that a parallel make will build @@ -1571,7 +1578,7 @@ s-alltree: Makefile rm -f tmp-all-tree.def echo '#include "tree.def"' > tmp-all-tree.def echo 'END_OF_BASE_TREE_CODES' >> tmp-all-tree.def - echo '#include "c-common.def"' >> tmp-all-tree.def + echo '#include "c-family/c-common.def"' >> tmp-all-tree.def ltf="$(lang_tree_files)"; for f in $$ltf; do \ echo "#include \"$$f\""; \ done | sed 's|$(srcdir)/||' >> tmp-all-tree.def @@ -1970,62 +1977,58 @@ s-crt0: $(CRT0_S) $(MCRT0_S) $(GCC_PASSES) $(CONFIG_H) # Note that dependencies on obstack.h are not written # because that file is not part of GCC. -# C language specific files. - -c-errors.o: c-errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) $(TM_P_H) -c-parser.o : c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(GGC_H) $(TIMEVAR_H) $(C_TREE_H) $(INPUT_H) $(FLAGS_H) $(TOPLEV_H) output.h \ - $(CPPLIB_H) gt-c-parser.h $(RTL_H) langhooks.h $(C_COMMON_H) $(C_PRAGMA_H) \ - $(VEC_H) $(TARGET_H) $(CGRAPH_H) $(PLUGIN_H) - srcextra: gcc.srcextra lang.srcextra gcc.srcextra: gengtype-lex.c -cp -p $^ $(srcdir) -incpath.o: incpath.c incpath.h $(CONFIG_H) $(SYSTEM_H) $(CPPLIB_H) \ - intl.h prefix.h coretypes.h $(TM_H) cppdefault.h $(TARGET_H) \ - $(MACHMODE_H) +# C language specific files. +c-aux-info.o : c-aux-info.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(C_TREE_H) $(TREE_H) $(FLAGS_H) $(TOPLEV_H) -c-decl.o : c-decl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(RTL_H) $(C_TREE_H) $(GGC_H) $(TARGET_H) $(FLAGS_H) $(FUNCTION_H) output.h \ - debug.h $(TOPLEV_H) intl.h $(TM_P_H) $(TREE_INLINE_H) $(TIMEVAR_H) \ - opts.h $(C_PRAGMA_H) gt-c-decl.h $(CGRAPH_H) $(HASHTAB_H) libfuncs.h \ - $(EXCEPT_H) $(LANGHOOKS_DEF_H) $(TREE_DUMP_H) $(C_COMMON_H) $(CPPLIB_H) \ - $(DIAGNOSTIC_CORE_H) $(INPUT_H) langhooks.h tree-mudflap.h \ - pointer-set.h tree-iterator.h c-lang.h $(PLUGIN_H) c-ada-spec.h -c-typeck.o : c-typeck.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(C_TREE_H) $(TARGET_H) $(FLAGS_H) intl.h output.h $(EXPR_H) \ - $(TOPLEV_H) langhooks.h $(TREE_FLOW_H) tree-iterator.h c-lang.h -c-lang.o : c-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) $(DIAGNOSTIC_CORE_H) \ - langhooks.h $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-c.h \ - c-objc-common.h $(C_PRAGMA_H) c-common.def $(TREE_INLINE_H) -stub-objc.o : stub-objc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ - $(C_COMMON_H) -c-lex.o : c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(FIXED_VALUE_H) debug.h $(C_TREE_H) $(C_COMMON_H) $(SPLAY_TREE_H) \ - $(C_PRAGMA_H) $(INPUT_H) intl.h $(FLAGS_H) $(TOPLEV_H) output.h \ - $(CPPLIB_H) $(TARGET_H) $(TIMEVAR_H) -c-ppoutput.o : c-ppoutput.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(C_COMMON_H) $(TREE_H) $(CPPLIB_H) $(CPP_INTERNAL_H) $(C_PRAGMA_H) -c-objc-common.o : c-objc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TREE_H) $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) \ - langhooks.h $(GGC_H) $(C_PRETTY_PRINT_H) c-objc-common.h intl.h \ - tree-pretty-print.h -c-aux-info.o : c-aux-info.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) $(FLAGS_H) $(TOPLEV_H) c-convert.o : c-convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(FLAGS_H) $(TOPLEV_H) $(C_COMMON_H) convert.h $(C_TREE_H) \ - langhooks.h $(TARGET_H) -c-pragma.o: c-pragma.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FUNCTION_H) $(C_PRAGMA_H) $(TOPLEV_H) output.h $(TM_P_H) \ - $(C_COMMON_H) $(TARGET_H) gt-c-pragma.h $(CPPLIB_H) $(FLAGS_H) $(DIAGNOSTIC_H) \ - opts.h $(PLUGINS_H) + $(TREE_H) $(C_TREE_H) $(FLAGS_H) $(TOPLEV_H) $(C_COMMON_H) convert.h \ + langhooks.h $(TARGET_H) + +c-decl.o : c-decl.c c-lang.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) $(C_TREE_H) $(GGC_H) $(TARGET_H) $(FLAGS_H) $(FUNCTION_H) \ + output.h debug.h $(TOPLEV_H) intl.h $(TM_P_H) $(TREE_INLINE_H) $(TIMEVAR_H) \ + opts.h $(C_PRAGMA_H) gt-c-decl.h $(CGRAPH_H) $(HASHTAB_H) libfuncs.h \ + $(EXCEPT_H) $(LANGHOOKS_DEF_H) $(TREE_DUMP_H) $(C_COMMON_H) $(CPPLIB_H) \ + $(DIAGNOSTIC_CORE_H) $(INPUT_H) langhooks.h tree-mudflap.h \ + pointer-set.h tree-iterator.h $(PLUGIN_H) c-family/c-ada-spec.h + +c-errors.o: c-errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) $(TM_P_H) + +c-lang.o : c-lang.c c-objc-common.h \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(C_TREE_H) $(DIAGNOSTIC_CORE_H) \ + langhooks.h $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-c.h \ + $(C_PRAGMA_H) $(TREE_INLINE_H) + +c-objc-common.o : c-objc-common.c c-objc-common.h \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TREE_H) $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) \ + langhooks.h $(GGC_H) $(C_PRETTY_PRINT_H) intl.h \ + tree-pretty-print.h + +c-parser.o : c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TREE_H) $(C_TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) $(CPPLIB_H) \ + $(GGC_H) $(TIMEVAR_H) $(INPUT_H) $(FLAGS_H) $(TOPLEV_H) output.h \ + gt-c-parser.h langhooks.h \ + $(VEC_H) $(TARGET_H) $(CGRAPH_H) $(PLUGIN_H) + +c-typeck.o : c-typeck.c c-lang.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) $(C_TREE_H) $(TARGET_H) $(FLAGS_H) intl.h output.h $(EXPR_H) \ + $(TOPLEV_H) langhooks.h $(TREE_FLOW_H) tree-iterator.h + + + graph.o: graph.c $(SYSTEM_H) coretypes.h $(TM_H) $(TOPLEV_H) $(FLAGS_H) output.h \ $(RTL_H) $(FUNCTION_H) hard-reg-set.h $(BASIC_BLOCK_H) graph.h $(OBSTACK_H) \ $(CONFIG_H) $(EMIT_RTL_H) + sbitmap.o: sbitmap.c sbitmap.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(BASIC_BLOCK_H) ebitmap.o: ebitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(EBITMAP_H) $(RTL_H) $(FLAGS_H) $(OBSTACK_H) @@ -2058,62 +2061,104 @@ lto-wrapper$(exeext): lto-wrapper.o intl.o $(LIBDEPS) lto-wrapper.o: lto-wrapper.c $(CONFIG_H) $(SYSTEM_H) defaults.h intl.h \ $(OBSTACK_H) -# A file used by all variants of C. - -c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ +# Files used by all variants of C. +c-family/c-common.o : c-family/c-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TREE_H) \ $(OBSTACK_H) $(C_COMMON_H) $(FLAGS_H) $(TOPLEV_H) output.h $(C_PRAGMA_H) \ $(GGC_H) $(EXPR_H) builtin-types.def builtin-attrs.def \ - $(DIAGNOSTIC_H) gt-c-common.h langhooks.h $(RTL_H) \ - $(TARGET_H) $(C_TREE_H) tree-iterator.h langhooks.h tree-mudflap.h \ + $(DIAGNOSTIC_H) langhooks.h $(RTL_H) \ + $(TARGET_H) tree-iterator.h langhooks.h tree-mudflap.h \ intl.h opts.h $(CPPLIB_H) $(TREE_INLINE_H) $(HASHTAB_H) \ $(BUILTINS_DEF) $(CGRAPH_H) $(BASIC_BLOCK_H) $(TARGET_DEF_H) \ - libfuncs.h + libfuncs.h \ + gt-c-family-c-common.h -c-pretty-print.o : c-pretty-print.c $(C_PRETTY_PRINT_H) \ - $(C_TREE_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(DIAGNOSTIC_H) tree-iterator.h intl.h tree-pretty-print.h +c-family/c-cppbuiltin.o : c-family/c-cppbuiltin.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TM_H) $(TREE_H) version.h $(C_COMMON_H) $(C_PRAGMA_H) \ + $(FLAGS_H) $(TOPLEV_H) output.h $(EXCEPT_H) $(TREE_H) $(TARGET_H) \ + $(TM_P_H) $(BASEVER) debug.h + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \ + -DBASEVER=$(BASEVER_s) $< $(OUTPUT_OPTION) + +c-family/c-dump.o : c-family/c-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TREE_H) $(TREE_DUMP_H) -c-opts.o : c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ +c-family/c-format.o : c-family/c-format.c c-family/c-format.h \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) langhooks.h \ + $(C_COMMON_H) $(FLAGS_H) $(TOPLEV_H) intl.h \ + $(DIAGNOSTIC_CORE_H) alloc-pool.h + +c-family/c-gimplify.o : c-family/c-gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ + $(C_COMMON_H) $(DIAGNOSTIC_CORE_H) $(GIMPLE_H) \ + $(FLAGS_H) langhooks.h $(TOPLEV_H) $(TREE_FLOW_H) $(LANGHOOKS_DEF_H) \ + $(TM_H) coretypes.h $(C_PRETTY_PRINT_H) $(CGRAPH_H) $(BASIC_BLOCK_H) \ + hard-reg-set.h $(TREE_DUMP_H) $(TREE_INLINE_H) + +c-family/c-lex.o : c-family/c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TREE_H) $(FIXED_VALUE_H) debug.h $(C_COMMON_H) $(SPLAY_TREE_H) \ + $(C_PRAGMA_H) $(INPUT_H) intl.h $(FLAGS_H) $(TOPLEV_H) output.h \ + $(CPPLIB_H) $(TARGET_H) $(TIMEVAR_H) + +c-family/c-omp.o : c-family/c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TREE_H) $(C_COMMON_H) $(TOPLEV_H) $(GIMPLE_H) langhooks.h + +c-family/c-opts.o : c-family/c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TREE_H) $(C_PRAGMA_H) $(FLAGS_H) $(TOPLEV_H) langhooks.h \ $(DIAGNOSTIC_H) intl.h debug.h $(C_COMMON_H) \ - opts.h options.h $(MKDEPS_H) incpath.h cppdefault.h $(C_TREE_H) + opts.h options.h $(MKDEPS_H) incpath.h cppdefault.h $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \ $< $(OUTPUT_OPTION) @TARGET_SYSTEM_ROOT_DEFINE@ -c-cppbuiltin.o : c-cppbuiltin.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) version.h $(C_COMMON_H) $(C_PRAGMA_H) $(FLAGS_H) \ - $(TOPLEV_H) output.h $(EXCEPT_H) $(TREE_H) $(TARGET_H) $(TM_P_H) \ - $(BASEVER) debug.h +c-family/c-pch.o : c-family/c-pch.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(CPPLIB_H) $(TREE_H) $(C_COMMON_H) output.h $(TOPLEV_H) $(C_PRAGMA_H) \ + $(GGC_H) debug.h langhooks.h $(FLAGS_H) hosthooks.h version.h \ + $(TARGET_H) opts.h $(TIMEVAR_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \ - -DBASEVER=$(BASEVER_s) $< $(OUTPUT_OPTION) + -DHOST_MACHINE=\"$(host)\" -DTARGET_MACHINE=\"$(target)\" \ + $< $(OUTPUT_OPTION) -# A file used by all variants of C and some other languages. +c-family/c-ppoutput.o : c-family/c-ppoutput.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(C_COMMON_H) $(TREE_H) $(CPPLIB_H) $(CPP_INTERNAL_H) \ + $(C_PRAGMA_H) -attribs.o : attribs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(FLAGS_H) $(TOPLEV_H) output.h $(GGC_H) $(TM_P_H) \ - $(TARGET_H) langhooks.h $(CPPLIB_H) $(PLUGIN_H) +c-family/c-pragma.o: c-family/c-pragma.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TREE_H) $(FUNCTION_H) $(C_PRAGMA_H) $(TOPLEV_H) output.h \ + $(TM_P_H) $(C_COMMON_H) $(TARGET_H) $(CPPLIB_H) $(FLAGS_H) \ + $(DIAGNOSTIC_H) opts.h $(PLUGINS_H) \ + gt-c-family-c-pragma.h -c-format.o : c-format.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) langhooks.h \ - $(C_COMMON_H) $(FLAGS_H) $(TOPLEV_H) intl.h $(DIAGNOSTIC_CORE_H) alloc-pool.h \ - c-format.h +c-family/c-pretty-print.o : c-family/c-pretty-print.c $(C_PRETTY_PRINT_H) \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(DIAGNOSTIC_H) tree-iterator.h intl.h tree-pretty-print.h -c-semantics.o : c-semantics.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(FLAGS_H) $(TOPLEV_H) output.h $(C_COMMON_H) $(FUNCTION_H) \ - langhooks.h $(SPLAY_TREE_H) $(TIMEVAR_H) tree-iterator.h +c-family/c-semantics.o : c-family/c-semantics.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TM_H) $(TREE_H) $(FLAGS_H) $(TOPLEV_H) output.h \ + $(C_COMMON_H) $(FUNCTION_H) langhooks.h $(SPLAY_TREE_H) $(TIMEVAR_H) \ + tree-iterator.h -c-dump.o : c-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) $(TREE_DUMP_H) +c-family/c-ada-spec.o : c-family/c-ada-spec.c c-family/c-ada-spec.h \ + $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(CPP_ID_DATA_H) $(TM_H) \ + coretypes.h tree-iterator.h tree-pass.h output.h + +c-family/stub-objc.o : c-family/stub-objc.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TREE_H) $(C_COMMON_H) -c-pch.o : c-pch.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) $(TREE_H) \ - $(C_COMMON_H) output.h $(TOPLEV_H) $(C_PRAGMA_H) $(GGC_H) debug.h \ - langhooks.h $(FLAGS_H) hosthooks.h version.h $(TARGET_H) opts.h \ - $(TIMEVAR_H) - $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \ - -DHOST_MACHINE=\"$(host)\" -DTARGET_MACHINE=\"$(target)\" \ - $< $(OUTPUT_OPTION) -c-omp.o : c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ - $(C_COMMON_H) $(TOPLEV_H) $(GIMPLE_H) langhooks.h +# Files used by all variants of C and some other languages. + +attribs.o : attribs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(FLAGS_H) $(TOPLEV_H) output.h $(GGC_H) $(TM_P_H) \ + $(TARGET_H) langhooks.h $(CPPLIB_H) $(PLUGIN_H) + +incpath.o: incpath.c incpath.h $(CONFIG_H) $(SYSTEM_H) $(CPPLIB_H) \ + intl.h prefix.h coretypes.h $(TM_H) cppdefault.h $(TARGET_H) \ + $(MACHMODE_H) + +prefix.o: prefix.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) prefix.h \ + Makefile $(BASEVER) + $(COMPILER) $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \ + -DPREFIX=\"$(prefix)\" -DBASEVER=$(BASEVER_s) \ + -c $(srcdir)/prefix.c $(OUTPUT_OPTION) # Language-independent files. @@ -2216,12 +2261,6 @@ ggc-none.o: ggc-none.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GGC_H) \ stringpool.o: stringpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(GGC_H) gt-stringpool.h $(CPPLIB_H) $(SYMTAB_H) -prefix.o: prefix.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) prefix.h \ - Makefile $(BASEVER) - $(COMPILER) $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \ - -DPREFIX=\"$(prefix)\" -DBASEVER=$(BASEVER_s) \ - -c $(srcdir)/prefix.c $(OUTPUT_OPTION) - convert.o: convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(FLAGS_H) convert.h $(TOPLEV_H) langhooks.h @@ -2560,11 +2599,6 @@ tree-optimize.o : tree-optimize.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(TREE_INLINE_H) tree-mudflap.h $(GGC_H) graph.h $(CGRAPH_H) \ $(TREE_PASS_H) $(CFGLOOP_H) $(EXCEPT_H) $(REGSET_H) -c-gimplify.o : c-gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ - $(C_TREE_H) $(C_COMMON_H) $(DIAGNOSTIC_CORE_H) $(GIMPLE_H) \ - $(FLAGS_H) langhooks.h $(TOPLEV_H) $(RTL_H) $(TREE_FLOW_H) $(LANGHOOKS_DEF_H) \ - $(TM_H) coretypes.h $(C_PRETTY_PRINT_H) $(CGRAPH_H) $(BASIC_BLOCK_H) \ - hard-reg-set.h $(TREE_DUMP_H) $(TREE_INLINE_H) gimplify.o : gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(GIMPLE_H) \ $(DIAGNOSTIC_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h \ $(LANGHOOKS_DEF_H) $(TREE_FLOW_H) $(CGRAPH_H) $(TIMEVAR_H) $(TM_H) \ @@ -2744,10 +2778,6 @@ tree-pretty-print.o : tree-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \ $(TREE_PASS_H) value-prof.h output.h tree-pretty-print.h tree-diagnostic.o : tree-diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TREE_H) $(DIAGNOSTIC_H) tree-diagnostic.h langhooks.h $(LANGHOOKS_DEF_H) -c-ada-spec.o : c-ada-spec.c c-ada-spec.h $(CONFIG_H) $(SYSTEM_H) \ - $(TREE_H) $(REAL_H) $(HASHTAB_H) $(TREE_FLOW_H) \ - $(CPP_ID_DATA_H) $(TM_H) coretypes.h tree-iterator.h tree-pass.h \ - value-prof.h fixed-value.h output.h fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(FLAGS_H) $(TOPLEV_H) $(HASHTAB_H) $(EXPR_H) $(RTL_H) \ $(GGC_H) $(TM_P_H) langhooks.h $(MD5_H) intl.h $(TARGET_H) \ @@ -3553,16 +3583,6 @@ $(simple_generated_c:insn-%.c=s-%): s-%: build/gen%$(build_exeext) \ $(SHELL) $(srcdir)/../move-if-change tmp-$*.c insn-$*.c $(STAMP) s-$* -generated_files = config.h tm.h $(TM_P_H) $(TM_H) multilib.h \ - $(simple_generated_h) specs.h \ - tree-check.h genrtl.h insn-modes.h tm-preds.h tm-constrs.h \ - $(ALL_GTFILES_H) gtype-desc.c gtype-desc.h gcov-iov.h - -# In order for parallel make to really start compiling the expensive -# objects from $(OBJS-common) as early as possible, build all their -# prerequisites strictly before all objects. -$(ALL_HOST_OBJS) : | $(generated_files) - # genconstants needs to run before insn-conditions.md is available # (because the constants may be used in the conditions). insn-constants.h: s-constants; @true @@ -3721,6 +3741,16 @@ s-gtype: build/gengtype$(build_exeext) $(filter-out [%], $(GTFILES)) \ $(RUN_GEN) build/gengtype$(build_exeext) $(srcdir) gtyp-input.list $(STAMP) s-gtype +generated_files = config.h tm.h $(TM_P_H) $(TM_H) multilib.h \ + $(simple_generated_h) specs.h \ + tree-check.h genrtl.h insn-modes.h tm-preds.h tm-constrs.h \ + $(ALL_GTFILES_H) gtype-desc.c gtype-desc.h gcov-iov.h + +# In order for parallel make to really start compiling the expensive +# objects from $(OBJS-common) as early as possible, build all their +# prerequisites strictly before all objects. +$(ALL_HOST_OBJS) : | $(generated_files) + # # How to compile object files to run on the build machine. diff --git a/gcc/c-ada-spec.c b/gcc/c-ada-spec.c deleted file mode 100644 index 697b963..0000000 --- a/gcc/c-ada-spec.c +++ /dev/null @@ -1,3230 +0,0 @@ -/* Print GENERIC declaration (functions, variables, types) trees coming from - the C and C++ front-ends as well as macros in Ada syntax. - Copyright (C) 2010 Free Software Foundation, Inc. - Adapted from tree-pretty-print.c by Arnaud Charlet - -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 "tree.h" -#include "tree-pass.h" /* For TDI_ada and friends. */ -#include "output.h" -#include "c-ada-spec.h" -#include "cpplib.h" -#include "c-pragma.h" -#include "cpp-id-data.h" - -/* Local functions, macros and variables. */ -static int dump_generic_ada_node (pretty_printer *, tree, tree, - int (*)(tree, cpp_operation), int, int, bool); -static int print_ada_declaration (pretty_printer *, tree, tree, - int (*cpp_check)(tree, cpp_operation), int); -static void print_ada_struct_decl (pretty_printer *, tree, tree, - int (*cpp_check)(tree, cpp_operation), int, - bool); -static void dump_sloc (pretty_printer *buffer, tree node); -static void print_comment (pretty_printer *, const char *); -static void print_generic_ada_decl (pretty_printer *, tree, - int (*)(tree, cpp_operation), const char *); -static char *get_ada_package (const char *); -static void dump_ada_nodes (pretty_printer *, const char *, - int (*)(tree, cpp_operation)); -static void reset_ada_withs (void); -static void dump_ada_withs (FILE *); -static void dump_ads (const char *, void (*)(const char *), - int (*)(tree, cpp_operation)); -static char *to_ada_name (const char *, int *); - -#define LOCATION_COL(LOC) ((expand_location (LOC)).column) - -#define INDENT(SPACE) do { \ - int i; for (i = 0; ifun_like) - { - param_len++; - for (i = 0; i < macro->paramc; i++) - { - cpp_hashnode *param = macro->params[i]; - - *param_len += NODE_LEN (param); - - if (i + 1 < macro->paramc) - { - *param_len += 2; /* ", " */ - } - else if (macro->variadic) - { - *supported = 0; - return; - } - } - *param_len += 2; /* ")\0" */ - } - - for (j = 0; j < macro->count; j++) - { - cpp_token *token = ¯o->exp.tokens[j]; - - if (token->flags & PREV_WHITE) - (*buffer_len)++; - - if (token->flags & STRINGIFY_ARG || token->flags & PASTE_LEFT) - { - *supported = 0; - return; - } - - if (token->type == CPP_MACRO_ARG) - *buffer_len += - NODE_LEN (macro->params[token->val.macro_arg.arg_no - 1]); - else - /* Include enough extra space to handle e.g. special characters. */ - *buffer_len += (cpp_token_len (token) + 1) * 8; - } - - (*buffer_len)++; -} - -/* Dump into PP a set of MAX_ADA_MACROS MACROS (C/C++) as Ada constants when - possible. */ - -static void -print_ada_macros (pretty_printer *pp, cpp_hashnode **macros, int max_ada_macros) -{ - int j, num_macros = 0, prev_line = -1; - - for (j = 0; j < max_ada_macros; j++) - { - cpp_hashnode *node = macros [j]; - const cpp_macro *macro = node->value.macro; - unsigned i; - int supported = 1, prev_is_one = 0, buffer_len, param_len; - int is_string = 0, is_char = 0; - char *ada_name; - unsigned char *s, *params, *buffer, *buf_param, *char_one = NULL; - - macro_length (macro, &supported, &buffer_len, ¶m_len); - s = buffer = XALLOCAVEC (unsigned char, buffer_len); - params = buf_param = XALLOCAVEC (unsigned char, param_len); - - if (supported) - { - if (macro->fun_like) - { - *buf_param++ = '('; - for (i = 0; i < macro->paramc; i++) - { - cpp_hashnode *param = macro->params[i]; - - memcpy (buf_param, NODE_NAME (param), NODE_LEN (param)); - buf_param += NODE_LEN (param); - - if (i + 1 < macro->paramc) - { - *buf_param++ = ','; - *buf_param++ = ' '; - } - else if (macro->variadic) - { - supported = 0; - break; - } - } - *buf_param++ = ')'; - *buf_param = '\0'; - } - - for (i = 0; supported && i < macro->count; i++) - { - cpp_token *token = ¯o->exp.tokens[i]; - int is_one = 0; - - if (token->flags & PREV_WHITE) - *buffer++ = ' '; - - if (token->flags & STRINGIFY_ARG || token->flags & PASTE_LEFT) - { - supported = 0; - break; - } - - switch (token->type) - { - case CPP_MACRO_ARG: - { - cpp_hashnode *param = - macro->params[token->val.macro_arg.arg_no - 1]; - memcpy (buffer, NODE_NAME (param), NODE_LEN (param)); - buffer += NODE_LEN (param); - } - break; - - case CPP_EQ_EQ: *buffer++ = '='; break; - case CPP_GREATER: *buffer++ = '>'; break; - case CPP_LESS: *buffer++ = '<'; break; - case CPP_PLUS: *buffer++ = '+'; break; - case CPP_MINUS: *buffer++ = '-'; break; - case CPP_MULT: *buffer++ = '*'; break; - case CPP_DIV: *buffer++ = '/'; break; - case CPP_COMMA: *buffer++ = ','; break; - case CPP_OPEN_SQUARE: - case CPP_OPEN_PAREN: *buffer++ = '('; break; - case CPP_CLOSE_SQUARE: /* fallthrough */ - case CPP_CLOSE_PAREN: *buffer++ = ')'; break; - case CPP_DEREF: /* fallthrough */ - case CPP_SCOPE: /* fallthrough */ - case CPP_DOT: *buffer++ = '.'; break; - - case CPP_EQ: *buffer++ = ':'; *buffer++ = '='; break; - case CPP_NOT_EQ: *buffer++ = '/'; *buffer++ = '='; break; - case CPP_GREATER_EQ: *buffer++ = '>'; *buffer++ = '='; break; - case CPP_LESS_EQ: *buffer++ = '<'; *buffer++ = '='; break; - - case CPP_NOT: - *buffer++ = 'n'; *buffer++ = 'o'; *buffer++ = 't'; break; - case CPP_MOD: - *buffer++ = 'm'; *buffer++ = 'o'; *buffer++ = 'd'; break; - case CPP_AND: - *buffer++ = 'a'; *buffer++ = 'n'; *buffer++ = 'd'; break; - case CPP_OR: - *buffer++ = 'o'; *buffer++ = 'r'; break; - case CPP_XOR: - *buffer++ = 'x'; *buffer++ = 'o'; *buffer++ = 'r'; break; - case CPP_AND_AND: - strcpy ((char *) buffer, " and then "); - buffer += 10; - break; - case CPP_OR_OR: - strcpy ((char *) buffer, " or else "); - buffer += 9; - break; - - case CPP_PADDING: - *buffer++ = ' '; - is_one = prev_is_one; - break; - - case CPP_COMMENT: break; - - case CPP_WSTRING: - case CPP_STRING16: - case CPP_STRING32: - case CPP_UTF8STRING: - case CPP_WCHAR: - case CPP_CHAR16: - case CPP_CHAR32: - case CPP_NAME: - case CPP_STRING: - case CPP_NUMBER: - if (!macro->fun_like) - supported = 0; - else - buffer = cpp_spell_token (parse_in, token, buffer, false); - break; - - case CPP_CHAR: - is_char = 1; - { - unsigned chars_seen; - int ignored; - cppchar_t c; - - c = cpp_interpret_charconst (parse_in, token, - &chars_seen, &ignored); - if (c >= 32 && c <= 126) - { - *buffer++ = '\''; - *buffer++ = (char) c; - *buffer++ = '\''; - } - else - { - chars_seen = sprintf - ((char *) buffer, "Character'Val (%d)", (int) c); - buffer += chars_seen; - } - } - break; - - case CPP_LSHIFT: - if (prev_is_one) - { - /* Replace "1 << N" by "2 ** N" */ - *char_one = '2'; - *buffer++ = '*'; - *buffer++ = '*'; - break; - } - /* fallthrough */ - - case CPP_RSHIFT: - case CPP_COMPL: - case CPP_QUERY: - case CPP_EOF: - case CPP_PLUS_EQ: - case CPP_MINUS_EQ: - case CPP_MULT_EQ: - case CPP_DIV_EQ: - case CPP_MOD_EQ: - case CPP_AND_EQ: - case CPP_OR_EQ: - case CPP_XOR_EQ: - case CPP_RSHIFT_EQ: - case CPP_LSHIFT_EQ: - case CPP_PRAGMA: - case CPP_PRAGMA_EOL: - case CPP_HASH: - case CPP_PASTE: - case CPP_OPEN_BRACE: - case CPP_CLOSE_BRACE: - case CPP_SEMICOLON: - case CPP_ELLIPSIS: - case CPP_PLUS_PLUS: - case CPP_MINUS_MINUS: - case CPP_DEREF_STAR: - case CPP_DOT_STAR: - case CPP_ATSIGN: - case CPP_HEADER_NAME: - case CPP_AT_NAME: - case CPP_OTHER: - case CPP_OBJC_STRING: - default: - if (!macro->fun_like) - supported = 0; - else - buffer = cpp_spell_token (parse_in, token, buffer, false); - break; - } - - prev_is_one = is_one; - } - - if (supported) - *buffer = '\0'; - } - - if (macro->fun_like && supported) - { - char *start = (char *) s; - int is_function = 0; - - pp_string (pp, " -- arg-macro: "); - - if (*start == '(' && buffer [-1] == ')') - { - start++; - buffer [-1] = '\0'; - is_function = 1; - pp_string (pp, "function "); - } - else - { - pp_string (pp, "procedure "); - } - - pp_string (pp, (const char *) NODE_NAME (node)); - pp_space (pp); - pp_string (pp, (char *) params); - pp_newline (pp); - pp_string (pp, " -- "); - - if (is_function) - { - pp_string (pp, "return "); - pp_string (pp, start); - pp_semicolon (pp); - } - else - pp_string (pp, start); - - pp_newline (pp); - } - else if (supported) - { - expanded_location sloc = expand_location (macro->line); - - if (sloc.line != prev_line + 1) - pp_newline (pp); - - num_macros++; - prev_line = sloc.line; - - pp_string (pp, " "); - ada_name = to_ada_name ((const char *) NODE_NAME (node), NULL); - pp_string (pp, ada_name); - free (ada_name); - pp_string (pp, " : "); - - if (is_string) - pp_string (pp, "aliased constant String"); - else if (is_char) - pp_string (pp, "aliased constant Character"); - else - pp_string (pp, "constant"); - - pp_string (pp, " := "); - pp_string (pp, (char *) s); - - if (is_string) - pp_string (pp, " & ASCII.NUL"); - - pp_string (pp, "; -- "); - pp_string (pp, sloc.file); - pp_character (pp, ':'); - pp_scalar (pp, "%d", sloc.line); - pp_newline (pp); - } - else - { - pp_string (pp, " -- unsupported macro: "); - pp_string (pp, (const char *) cpp_macro_definition (parse_in, node)); - pp_newline (pp); - } - } - - if (num_macros > 0) - pp_newline (pp); -} - -static const char *source_file; -static int max_ada_macros; - -/* Callback used to count the number of relevant macros from - cpp_forall_identifiers. PFILE and V are not used. NODE is the current macro - to consider. */ - -static int -count_ada_macro (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *node, - void *v ATTRIBUTE_UNUSED) -{ - const cpp_macro *macro = node->value.macro; - - if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN) - && macro->count - && *NODE_NAME (node) != '_' - && LOCATION_FILE (macro->line) == source_file) - max_ada_macros++; - - return 1; -} - -static int store_ada_macro_index; - -/* Callback used to store relevant macros from cpp_forall_identifiers. - PFILE is not used. NODE is the current macro to store if relevant. - MACROS is an array of cpp_hashnode* used to store NODE. */ - -static int -store_ada_macro (cpp_reader *pfile ATTRIBUTE_UNUSED, - cpp_hashnode *node, void *macros) -{ - const cpp_macro *macro = node->value.macro; - - if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN) - && macro->count - && *NODE_NAME (node) != '_' - && LOCATION_FILE (macro->line) == source_file) - ((cpp_hashnode **) macros)[store_ada_macro_index++] = node; - - return 1; -} - -/* Callback used to compare (during qsort) macros. NODE1 and NODE2 are the - two macro nodes to compare. */ - -static int -compare_macro (const void *node1, const void *node2) -{ - typedef const cpp_hashnode *const_hnode; - - const_hnode n1 = *(const const_hnode *) node1; - const_hnode n2 = *(const const_hnode *) node2; - - return n1->value.macro->line - n2->value.macro->line; -} - -/* Dump in PP all relevant macros appearing in FILE. */ - -static void -dump_ada_macros (pretty_printer *pp, const char* file) -{ - cpp_hashnode **macros; - - /* Initialize file-scope variables. */ - max_ada_macros = 0; - store_ada_macro_index = 0; - source_file = file; - - /* Count all potentially relevant macros, and then sort them by sloc. */ - cpp_forall_identifiers (parse_in, count_ada_macro, NULL); - macros = XALLOCAVEC (cpp_hashnode *, max_ada_macros); - cpp_forall_identifiers (parse_in, store_ada_macro, macros); - qsort (macros, max_ada_macros, sizeof (cpp_hashnode *), compare_macro); - - print_ada_macros (pp, macros, max_ada_macros); -} - -/* Current source file being handled. */ - -static const char *source_file_base; - -/* Compare the declaration (DECL) of struct-like types based on the sloc of - their last field (if LAST is true), so that more nested types collate before - less nested ones. - If ORIG_TYPE is true, also consider struct with a DECL_ORIGINAL_TYPE. */ - -static location_t -decl_sloc_common (const_tree decl, bool last, bool orig_type) -{ - tree type = TREE_TYPE (decl); - - if (TREE_CODE (decl) == TYPE_DECL - && (orig_type || !DECL_ORIGINAL_TYPE (decl)) - && RECORD_OR_UNION_TYPE_P (type) - && TYPE_FIELDS (type)) - { - tree f = TYPE_FIELDS (type); - - if (last) - while (TREE_CHAIN (f)) - f = TREE_CHAIN (f); - - return DECL_SOURCE_LOCATION (f); - } - else - return DECL_SOURCE_LOCATION (decl); -} - -/* Return sloc of DECL, using sloc of last field if LAST is true. */ - -location_t -decl_sloc (const_tree decl, bool last) -{ - return decl_sloc_common (decl, last, false); -} - -/* Compare two declarations (LP and RP) by their source location. */ - -static int -compare_node (const void *lp, const void *rp) -{ - const_tree lhs = *((const tree *) lp); - const_tree rhs = *((const tree *) rp); - - return decl_sloc (lhs, true) - decl_sloc (rhs, true); -} - -/* Compare two comments (LP and RP) by their source location. */ - -static int -compare_comment (const void *lp, const void *rp) -{ - const cpp_comment *lhs = (const cpp_comment *) lp; - const cpp_comment *rhs = (const cpp_comment *) rp; - - if (LOCATION_FILE (lhs->sloc) != LOCATION_FILE (rhs->sloc)) - return strcmp (LOCATION_FILE (lhs->sloc), LOCATION_FILE (rhs->sloc)); - - if (LOCATION_LINE (lhs->sloc) != LOCATION_LINE (rhs->sloc)) - return LOCATION_LINE (lhs->sloc) - LOCATION_LINE (rhs->sloc); - - if (LOCATION_COL (lhs->sloc) != LOCATION_COL (rhs->sloc)) - return LOCATION_COL (lhs->sloc) - LOCATION_COL (rhs->sloc); - - return 0; -} - -static tree *to_dump = NULL; -static int to_dump_count = 0; - -/* Collect a list of declarations from T relevant to SOURCE_FILE to be dumped - by a subsequent call to dump_ada_nodes. */ - -void -collect_ada_nodes (tree t, const char *source_file) -{ - tree n; - int i = to_dump_count; - - /* Count the likely relevant nodes. */ - for (n = t; n; n = TREE_CHAIN (n)) - if (!DECL_IS_BUILTIN (n) - && LOCATION_FILE (decl_sloc (n, false)) == source_file) - to_dump_count++; - - /* Allocate sufficient storage for all nodes. */ - to_dump = XRESIZEVEC (tree, to_dump, to_dump_count); - - /* Store the relevant nodes. */ - for (n = t; n; n = TREE_CHAIN (n)) - if (!DECL_IS_BUILTIN (n) - && LOCATION_FILE (decl_sloc (n, false)) == source_file) - to_dump [i++] = n; -} - -/* Call back for walk_tree to clear the TREE_VISITED flag of TP. */ - -static tree -unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - if (TREE_VISITED (*tp)) - TREE_VISITED (*tp) = 0; - else - *walk_subtrees = 0; - - return NULL_TREE; -} - -/* Dump nodes into PP relevant to SOURCE_FILE, as collected by previous calls - to collect_ada_nodes. CPP_CHECK is used to perform C++ queries on nodes. */ - -static void -dump_ada_nodes (pretty_printer *pp, const char *source_file, - int (*cpp_check)(tree, cpp_operation)) -{ - int i, j; - cpp_comment_table *comments; - - /* Sort the table of declarations to dump by sloc. */ - qsort (to_dump, to_dump_count, sizeof (tree), compare_node); - - /* Fetch the table of comments. */ - comments = cpp_get_comments (parse_in); - - /* Sort the comments table by sloc. */ - qsort (comments->entries, comments->count, sizeof (cpp_comment), - compare_comment); - - /* Interleave comments and declarations in line number order. */ - i = j = 0; - do - { - /* Advance j until comment j is in this file. */ - while (j != comments->count - && LOCATION_FILE (comments->entries[j].sloc) != source_file) - j++; - - /* Advance j until comment j is not a duplicate. */ - while (j < comments->count - 1 - && !compare_comment (&comments->entries[j], - &comments->entries[j + 1])) - j++; - - /* Write decls until decl i collates after comment j. */ - while (i != to_dump_count) - { - if (j == comments->count - || LOCATION_LINE (decl_sloc (to_dump[i], false)) - < LOCATION_LINE (comments->entries[j].sloc)) - print_generic_ada_decl (pp, to_dump[i++], cpp_check, source_file); - else - break; - } - - /* Write comment j, if there is one. */ - if (j != comments->count) - print_comment (pp, comments->entries[j++].comment); - - } while (i != to_dump_count || j != comments->count); - - /* Clear the TREE_VISITED flag over each subtree we've dumped. */ - for (i = 0; i < to_dump_count; i++) - walk_tree (&to_dump[i], unmark_visited_r, NULL, NULL); - - /* Finalize the to_dump table. */ - if (to_dump) - { - free (to_dump); - to_dump = NULL; - to_dump_count = 0; - } -} - -/* Print a COMMENT to the output stream PP. */ - -static void -print_comment (pretty_printer *pp, const char *comment) -{ - int len = strlen (comment); - char *str = XALLOCAVEC (char, len + 1); - char *tok; - bool extra_newline = false; - - memcpy (str, comment, len + 1); - - /* Trim C/C++ comment indicators. */ - if (str[len - 2] == '*' && str[len - 1] == '/') - { - str[len - 2] = ' '; - str[len - 1] = '\0'; - } - str += 2; - - tok = strtok (str, "\n"); - while (tok) { - pp_string (pp, " --"); - pp_string (pp, tok); - pp_newline (pp); - tok = strtok (NULL, "\n"); - - /* Leave a blank line after multi-line comments. */ - if (tok) - extra_newline = true; - } - - if (extra_newline) - pp_newline (pp); -} - -/* Prints declaration DECL to PP in Ada syntax. The current source file being - handled is SOURCE_FILE, and CPP_CHECK is used to perform C++ queries on - nodes. */ - -static void -print_generic_ada_decl (pretty_printer *pp, tree decl, - int (*cpp_check)(tree, cpp_operation), - const char* source_file) -{ - source_file_base = source_file; - - if (print_ada_declaration (pp, decl, 0, cpp_check, INDENT_INCR)) - { - pp_newline (pp); - pp_newline (pp); - } -} - -/* Dump a newline and indent BUFFER by SPC chars. */ - -static void -newline_and_indent (pretty_printer *buffer, int spc) -{ - pp_newline (buffer); - INDENT (spc); -} - -struct with { char *s; const char *in_file; int limited; }; -static struct with *withs = NULL; -static int withs_max = 4096; -static int with_len = 0; - -/* Record a "with" clause on package S (a limited with if LIMITED_ACCESS is - true), if not already done. */ - -static void -append_withs (const char *s, int limited_access) -{ - int i; - - if (withs == NULL) - withs = XNEWVEC (struct with, withs_max); - - if (with_len == withs_max) - { - withs_max *= 2; - withs = XRESIZEVEC (struct with, withs, withs_max); - } - - for (i = 0; i < with_len; i++) - if (!strcmp (s, withs [i].s) - && source_file_base == withs [i].in_file) - { - withs [i].limited &= limited_access; - return; - } - - withs [with_len].s = xstrdup (s); - withs [with_len].in_file = source_file_base; - withs [with_len].limited = limited_access; - with_len++; -} - -/* Reset "with" clauses. */ - -static void -reset_ada_withs (void) -{ - int i; - - if (!withs) - return; - - for (i = 0; i < with_len; i++) - free (withs [i].s); - free (withs); - withs = NULL; - withs_max = 4096; - with_len = 0; -} - -/* Dump "with" clauses in F. */ - -static void -dump_ada_withs (FILE *f) -{ - int i; - - fprintf (f, "with Interfaces.C; use Interfaces.C;\n"); - - for (i = 0; i < with_len; i++) - fprintf - (f, "%swith %s;\n", withs [i].limited ? "limited " : "", withs [i].s); -} - -/* Return suitable Ada package name from FILE. */ - -static char * -get_ada_package (const char *file) -{ - const char *base; - char *res; - const char *s; - int i; - - s = strstr (file, "/include/"); - if (s) - base = s + 9; - else - base = lbasename (file); - res = XNEWVEC (char, strlen (base) + 1); - - for (i = 0; *base; base++, i++) - switch (*base) - { - case '+': - res [i] = 'p'; - break; - - case '.': - case '-': - case '_': - case '/': - case '\\': - res [i] = (i == 0 || res [i - 1] == '_') ? 'u' : '_'; - break; - - default: - res [i] = *base; - break; - } - res [i] = '\0'; - - return res; -} - -static const char *ada_reserved[] = { - "abort", "abs", "abstract", "accept", "access", "aliased", "all", "and", - "array", "at", "begin", "body", "case", "constant", "declare", "delay", - "delta", "digits", "do", "else", "elsif", "end", "entry", "exception", - "exit", "for", "function", "generic", "goto", "if", "in", "interface", "is", - "limited", "loop", "mod", "new", "not", "null", "others", "out", "of", "or", - "overriding", "package", "pragma", "private", "procedure", "protected", - "raise", "range", "record", "rem", "renames", "requeue", "return", "reverse", - "select", "separate", "subtype", "synchronized", "tagged", "task", - "terminate", "then", "type", "until", "use", "when", "while", "with", "xor", - NULL}; - -/* ??? would be nice to specify this list via a config file, so that users - can create their own dictionary of conflicts. */ -static const char *c_duplicates[] = { - /* system will cause troubles with System.Address. */ - "system", - - /* The following values have other definitions with same name/other - casing. */ - "funmap", - "rl_vi_fWord", - "rl_vi_bWord", - "rl_vi_eWord", - "rl_readline_version", - "_Vx_ushort", - "USHORT", - "XLookupKeysym", - NULL}; - -/* Return a declaration tree corresponding to TYPE. */ - -static tree -get_underlying_decl (tree type) -{ - tree decl = NULL_TREE; - - if (type == NULL_TREE) - return NULL_TREE; - - /* type is a declaration. */ - if (DECL_P (type)) - decl = type; - - /* type is a typedef. */ - if (TYPE_P (type) && TYPE_NAME (type) && DECL_P (TYPE_NAME (type))) - decl = TYPE_NAME (type); - - /* TYPE_STUB_DECL has been set for type. */ - if (TYPE_P (type) && TYPE_STUB_DECL (type) && - DECL_P (TYPE_STUB_DECL (type))) - decl = TYPE_STUB_DECL (type); - - return decl; -} - -/* Return whether TYPE has static fields. */ - -static int -has_static_fields (const_tree type) -{ - tree tmp; - - for (tmp = TYPE_FIELDS (type); tmp; tmp = TREE_CHAIN (tmp)) - { - if (DECL_NAME (tmp) && TREE_STATIC (tmp)) - return true; - } - return false; -} - -/* Return whether TYPE corresponds to an Ada tagged type (has a dispatch - table). */ - -static int -is_tagged_type (const_tree type) -{ - tree tmp; - - if (!type || !RECORD_OR_UNION_TYPE_P (type)) - return false; - - for (tmp = TYPE_METHODS (type); tmp; tmp = TREE_CHAIN (tmp)) - if (DECL_VINDEX (tmp)) - return true; - - return false; -} - -/* Generate a legal Ada name from a C NAME, returning a malloc'd string. - SPACE_FOUND, if not NULL, is used to indicate whether a space was found in - NAME. */ - -static char * -to_ada_name (const char *name, int *space_found) -{ - const char **names; - int len = strlen (name); - int j, len2 = 0; - int found = false; - char *s = XNEWVEC (char, len * 2 + 5); - char c; - - if (space_found) - *space_found = false; - - /* Add trailing "c_" if name is an Ada reserved word. */ - for (names = ada_reserved; *names; names++) - if (!strcasecmp (name, *names)) - { - s [len2++] = 'c'; - s [len2++] = '_'; - found = true; - break; - } - - if (!found) - /* Add trailing "c_" if name is an potential case sensitive duplicate. */ - for (names = c_duplicates; *names; names++) - if (!strcmp (name, *names)) - { - s [len2++] = 'c'; - s [len2++] = '_'; - found = true; - break; - } - - for (j = 0; name [j] == '_'; j++) - s [len2++] = 'u'; - - if (j > 0) - s [len2++] = '_'; - else if (*name == '.' || *name == '$') - { - s [0] = 'a'; - s [1] = 'n'; - s [2] = 'o'; - s [3] = 'n'; - len2 = 4; - j++; - } - - /* Replace unsuitable characters for Ada identifiers. */ - - for (; j < len; j++) - switch (name [j]) - { - case ' ': - if (space_found) - *space_found = true; - s [len2++] = '_'; - break; - - /* ??? missing some C++ operators. */ - case '=': - s [len2++] = '_'; - - if (name [j + 1] == '=') - { - j++; - s [len2++] = 'e'; - s [len2++] = 'q'; - } - else - { - s [len2++] = 'a'; - s [len2++] = 's'; - } - break; - - case '!': - s [len2++] = '_'; - if (name [j + 1] == '=') - { - j++; - s [len2++] = 'n'; - s [len2++] = 'e'; - } - break; - - case '~': - s [len2++] = '_'; - s [len2++] = 't'; - s [len2++] = 'i'; - break; - - case '&': - case '|': - case '^': - s [len2++] = '_'; - s [len2++] = name [j] == '&' ? 'a' : name [j] == '|' ? 'o' : 'x'; - - if (name [j + 1] == '=') - { - j++; - s [len2++] = 'e'; - } - break; - - case '+': - case '-': - case '*': - case '/': - case '(': - case '[': - if (s [len2 - 1] != '_') - s [len2++] = '_'; - - switch (name [j + 1]) { - case '\0': - j++; - switch (name [j - 1]) { - case '+': s [len2++] = 'p'; break; /* + */ - case '-': s [len2++] = 'm'; break; /* - */ - case '*': s [len2++] = 't'; break; /* * */ - case '/': s [len2++] = 'd'; break; /* / */ - } - break; - - case '=': - j++; - switch (name [j - 1]) { - case '+': s [len2++] = 'p'; break; /* += */ - case '-': s [len2++] = 'm'; break; /* -= */ - case '*': s [len2++] = 't'; break; /* *= */ - case '/': s [len2++] = 'd'; break; /* /= */ - } - s [len2++] = 'a'; - break; - - case '-': /* -- */ - j++; - s [len2++] = 'm'; - s [len2++] = 'm'; - break; - - case '+': /* ++ */ - j++; - s [len2++] = 'p'; - s [len2++] = 'p'; - break; - - case ')': /* () */ - j++; - s [len2++] = 'o'; - s [len2++] = 'p'; - break; - - case ']': /* [] */ - j++; - s [len2++] = 'o'; - s [len2++] = 'b'; - break; - } - - break; - - case '<': - case '>': - c = name [j] == '<' ? 'l' : 'g'; - s [len2++] = '_'; - - switch (name [j + 1]) { - case '\0': - s [len2++] = c; - s [len2++] = 't'; - break; - case '=': - j++; - s [len2++] = c; - s [len2++] = 'e'; - break; - case '>': - j++; - s [len2++] = 's'; - s [len2++] = 'r'; - break; - case '<': - j++; - s [len2++] = 's'; - s [len2++] = 'l'; - break; - default: - break; - } - break; - - case '_': - if (len2 && s [len2 - 1] == '_') - s [len2++] = 'u'; - /* fall through */ - - default: - s [len2++] = name [j]; - } - - if (s [len2 - 1] == '_') - s [len2++] = 'u'; - - s [len2] = '\0'; - - return s; -} - -static bool package_prefix = true; - -/* Dump in BUFFER the name of an identifier NODE of type TYPE, following Ada - syntax. LIMITED_ACCESS indicates whether NODE can be accessed via a limited - 'with' clause rather than a regular 'with' clause. */ - -static void -pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type, - int limited_access) -{ - const char *name = IDENTIFIER_POINTER (node); - int space_found = false; - char *s = to_ada_name (name, &space_found); - tree decl; - - /* If the entity is a type and comes from another file, generate "package" - prefix. */ - - decl = get_underlying_decl (type); - - if (decl) - { - expanded_location xloc = expand_location (decl_sloc (decl, false)); - - if (xloc.file && xloc.line) - { - if (xloc.file != source_file_base) - { - switch (TREE_CODE (type)) - { - case ENUMERAL_TYPE: - case INTEGER_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - case BOOLEAN_TYPE: - case REFERENCE_TYPE: - case POINTER_TYPE: - case ARRAY_TYPE: - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - case TYPE_DECL: - { - char *s1 = get_ada_package (xloc.file); - - if (package_prefix) - { - append_withs (s1, limited_access); - pp_string (buffer, s1); - pp_character (buffer, '.'); - } - free (s1); - } - break; - default: - break; - } - } - } - } - - if (space_found) - if (!strcmp (s, "short_int")) - pp_string (buffer, "short"); - else if (!strcmp (s, "short_unsigned_int")) - pp_string (buffer, "unsigned_short"); - else if (!strcmp (s, "unsigned_int")) - pp_string (buffer, "unsigned"); - else if (!strcmp (s, "long_int")) - pp_string (buffer, "long"); - else if (!strcmp (s, "long_unsigned_int")) - pp_string (buffer, "unsigned_long"); - else if (!strcmp (s, "long_long_int")) - pp_string (buffer, "Long_Long_Integer"); - else if (!strcmp (s, "long_long_unsigned_int")) - { - if (package_prefix) - { - append_withs ("Interfaces.C.Extensions", false); - pp_string (buffer, "Extensions.unsigned_long_long"); - } - else - pp_string (buffer, "unsigned_long_long"); - } - else - pp_string(buffer, s); - else - if (!strcmp (s, "bool")) - { - if (package_prefix) - { - append_withs ("Interfaces.C.Extensions", false); - pp_string (buffer, "Extensions.bool"); - } - else - pp_string (buffer, "bool"); - } - else - pp_string(buffer, s); - - free (s); -} - -/* Dump in BUFFER the assembly name of T. */ - -static void -pp_asm_name (pretty_printer *buffer, tree t) -{ - tree name = DECL_ASSEMBLER_NAME (t); - char *ada_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (name) + 1), *s; - const char *ident = IDENTIFIER_POINTER (name); - - for (s = ada_name; *ident; ident++) - { - if (*ident == ' ') - break; - else if (*ident != '*') - *s++ = *ident; - } - - *s = '\0'; - pp_string (buffer, ada_name); -} - -/* Dump in BUFFER the name of a DECL node if set, following Ada syntax. - LIMITED_ACCESS indicates whether NODE can be accessed via a limited - 'with' clause rather than a regular 'with' clause. */ - -static void -dump_ada_decl_name (pretty_printer *buffer, tree decl, int limited_access) -{ - if (DECL_NAME (decl)) - pp_ada_tree_identifier (buffer, DECL_NAME (decl), decl, limited_access); - else - { - tree type_name = TYPE_NAME (TREE_TYPE (decl)); - - if (!type_name) - { - pp_string (buffer, "anon"); - if (TREE_CODE (decl) == FIELD_DECL) - pp_scalar (buffer, "%d", DECL_UID (decl)); - else - pp_scalar (buffer, "%d", TYPE_UID (TREE_TYPE (decl))); - } - else if (TREE_CODE (type_name) == IDENTIFIER_NODE) - pp_ada_tree_identifier (buffer, type_name, decl, limited_access); - } -} - -/* Dump in BUFFER a name based on both T1 and T2, followed by S. */ - -static void -dump_ada_double_name (pretty_printer *buffer, tree t1, tree t2, const char *s) -{ - if (DECL_NAME (t1)) - pp_ada_tree_identifier (buffer, DECL_NAME (t1), t1, false); - else - { - pp_string (buffer, "anon"); - pp_scalar (buffer, "%d", TYPE_UID (TREE_TYPE (t1))); - } - - pp_character (buffer, '_'); - - if (DECL_NAME (t1)) - pp_ada_tree_identifier (buffer, DECL_NAME (t2), t2, false); - else - { - pp_string (buffer, "anon"); - pp_scalar (buffer, "%d", TYPE_UID (TREE_TYPE (t2))); - } - - pp_string (buffer, s); -} - -/* Dump in BUFFER pragma Import C/CPP on a given node T. */ - -static void -dump_ada_import (pretty_printer *buffer, tree t) -{ - const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t)); - int is_stdcall = TREE_CODE (t) == FUNCTION_DECL && - lookup_attribute ("stdcall", TYPE_ATTRIBUTES (TREE_TYPE (t))); - - if (is_stdcall) - pp_string (buffer, "pragma Import (Stdcall, "); - else if (name [0] == '_' && name [1] == 'Z') - pp_string (buffer, "pragma Import (CPP, "); - else - pp_string (buffer, "pragma Import (C, "); - - dump_ada_decl_name (buffer, t, false); - pp_string (buffer, ", \""); - - if (is_stdcall) - pp_string (buffer, IDENTIFIER_POINTER (DECL_NAME (t))); - else - pp_asm_name (buffer, t); - - pp_string (buffer, "\");"); -} - -/* Check whether T and its type have different names, and append "the_" - otherwise in BUFFER. */ - -static void -check_name (pretty_printer *buffer, tree t) -{ - const char *s; - tree tmp = TREE_TYPE (t); - - while (TREE_CODE (tmp) == POINTER_TYPE && !TYPE_NAME (tmp)) - tmp = TREE_TYPE (tmp); - - if (TREE_CODE (tmp) != FUNCTION_TYPE) - { - if (TREE_CODE (tmp) == IDENTIFIER_NODE) - s = IDENTIFIER_POINTER (tmp); - else if (!TYPE_NAME (tmp)) - s = ""; - else if (TREE_CODE (TYPE_NAME (tmp)) == IDENTIFIER_NODE) - s = IDENTIFIER_POINTER (TYPE_NAME (tmp)); - else - s = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (tmp))); - - if (!strcasecmp (IDENTIFIER_POINTER (DECL_NAME (t)), s)) - pp_string (buffer, "the_"); - } -} - -/* Dump in BUFFER a function declaration FUNC with Ada syntax. - IS_METHOD indicates whether FUNC is a C++ method. - IS_CONSTRUCTOR whether FUNC is a C++ constructor. - IS_DESTRUCTOR whether FUNC is a C++ destructor. - SPC is the current indentation level. */ - -static int -dump_ada_function_declaration (pretty_printer *buffer, tree func, - int is_method, int is_constructor, - int is_destructor, int spc) -{ - tree arg; - const tree node = TREE_TYPE (func); - char buf [16]; - int num = 0, num_args = 0, have_args = true, have_ellipsis = false; - - /* Compute number of arguments. */ - arg = TYPE_ARG_TYPES (node); - - if (arg) - { - while (TREE_CHAIN (arg) && arg != error_mark_node) - { - num_args++; - arg = TREE_CHAIN (arg); - } - - if (TREE_CODE (TREE_VALUE (arg)) != VOID_TYPE) - { - num_args++; - have_ellipsis = true; - } - } - - if (is_constructor) - num_args--; - - if (is_destructor) - num_args = 1; - - if (num_args > 2) - newline_and_indent (buffer, spc + 1); - - if (num_args > 0) - { - pp_space (buffer); - pp_character (buffer, '('); - } - - if (TREE_CODE (func) == FUNCTION_DECL) - arg = DECL_ARGUMENTS (func); - else - arg = NULL_TREE; - - if (arg == NULL_TREE) - { - have_args = false; - arg = TYPE_ARG_TYPES (node); - - if (arg && TREE_CODE (TREE_VALUE (arg)) == VOID_TYPE) - arg = NULL_TREE; - } - - if (is_constructor) - arg = TREE_CHAIN (arg); - - /* Print the argument names (if available) & types. */ - - for (num = 1; num <= num_args; num++) - { - if (have_args) - { - if (DECL_NAME (arg)) - { - check_name (buffer, arg); - pp_ada_tree_identifier (buffer, DECL_NAME (arg), 0, false); - pp_string (buffer, " : "); - } - else - { - sprintf (buf, "arg%d : ", num); - pp_string (buffer, buf); - } - - dump_generic_ada_node - (buffer, TREE_TYPE (arg), node, NULL, spc, 0, true); - } - else - { - sprintf (buf, "arg%d : ", num); - pp_string (buffer, buf); - dump_generic_ada_node - (buffer, TREE_VALUE (arg), node, NULL, spc, 0, true); - } - - if (TREE_TYPE (arg) && TREE_TYPE (TREE_TYPE (arg)) - && is_tagged_type (TREE_TYPE (TREE_TYPE (arg)))) - { - if (!is_method - || (num != 1 || (!DECL_VINDEX (func) && !is_constructor))) - pp_string (buffer, "'Class"); - } - - arg = TREE_CHAIN (arg); - - if (num < num_args) - { - pp_character (buffer, ';'); - - if (num_args > 2) - newline_and_indent (buffer, spc + INDENT_INCR); - else - pp_space (buffer); - } - } - - if (have_ellipsis) - { - pp_string (buffer, " -- , ..."); - newline_and_indent (buffer, spc + INDENT_INCR); - } - - if (num_args > 0) - pp_character (buffer, ')'); - return num_args; -} - -/* Dump in BUFFER all the domains associated with an array NODE, - using Ada syntax. SPC is the current indentation level. */ - -static void -dump_ada_array_domains (pretty_printer *buffer, tree node, int spc) -{ - int first = 1; - pp_character (buffer, '('); - - for (; TREE_CODE (node) == ARRAY_TYPE; node = TREE_TYPE (node)) - { - tree domain = TYPE_DOMAIN (node); - - if (domain) - { - tree min = TYPE_MIN_VALUE (domain); - tree max = TYPE_MAX_VALUE (domain); - - if (!first) - pp_string (buffer, ", "); - first = 0; - - if (min) - dump_generic_ada_node (buffer, min, NULL_TREE, NULL, spc, 0, true); - pp_string (buffer, " .. "); - - /* If the upper bound is zero, gcc may generate a NULL_TREE - for TYPE_MAX_VALUE rather than an integer_cst. */ - if (max) - dump_generic_ada_node (buffer, max, NULL_TREE, NULL, spc, 0, true); - else - pp_string (buffer, "0"); - } - else - pp_string (buffer, "size_t"); - } - pp_character (buffer, ')'); -} - -/* Dump in BUFFER file:line:col information related to NODE. */ - -static void -dump_sloc (pretty_printer *buffer, tree node) -{ - expanded_location xloc; - - xloc.file = NULL; - - if (TREE_CODE_CLASS (TREE_CODE (node)) == tcc_declaration) - xloc = expand_location (DECL_SOURCE_LOCATION (node)); - else if (EXPR_HAS_LOCATION (node)) - xloc = expand_location (EXPR_LOCATION (node)); - - if (xloc.file) - { - pp_string (buffer, xloc.file); - pp_string (buffer, ":"); - pp_decimal_int (buffer, xloc.line); - pp_string (buffer, ":"); - pp_decimal_int (buffer, xloc.column); - } -} - -/* Return true if T designates a one dimension array of "char". */ - -static bool -is_char_array (tree t) -{ - tree tmp; - int num_dim = 0; - - /* Retrieve array's type. */ - tmp = t; - while (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE) - { - num_dim++; - tmp = TREE_TYPE (tmp); - } - - tmp = TREE_TYPE (tmp); - return num_dim == 1 && TREE_CODE (tmp) == INTEGER_TYPE - && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (tmp))), "char"); -} - -/* Dump in BUFFER an array type T in Ada syntax. Assume that the "type" - keyword and name have already been printed. SPC is the indentation - level. */ - -static void -dump_ada_array_type (pretty_printer *buffer, tree t, int spc) -{ - tree tmp; - bool char_array = is_char_array (t); - - /* Special case char arrays. */ - if (char_array) - { - pp_string (buffer, "Interfaces.C.char_array "); - } - else - pp_string (buffer, "array "); - - /* Print the dimensions. */ - dump_ada_array_domains (buffer, TREE_TYPE (t), spc); - - /* Retrieve array's type. */ - tmp = TREE_TYPE (t); - while (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE) - tmp = TREE_TYPE (tmp); - - /* Print array's type. */ - if (!char_array) - { - pp_string (buffer, " of "); - - if (TREE_CODE (TREE_TYPE (tmp)) != POINTER_TYPE) - pp_string (buffer, "aliased "); - - dump_generic_ada_node - (buffer, TREE_TYPE (tmp), TREE_TYPE (t), NULL, spc, false, true); - } -} - -/* Dump in BUFFER type names associated with a template, each prepended with - '_'. TYPES is the TREE_PURPOSE of a DECL_TEMPLATE_INSTANTIATIONS. - CPP_CHECK is used to perform C++ queries on nodes. - SPC is the indentation level. */ - -static void -dump_template_types (pretty_printer *buffer, tree types, - int (*cpp_check)(tree, cpp_operation), int spc) -{ - size_t i; - size_t len = TREE_VEC_LENGTH (types); - - for (i = 0; i < len; i++) - { - tree elem = TREE_VEC_ELT (types, i); - pp_character (buffer, '_'); - if (!dump_generic_ada_node (buffer, elem, 0, cpp_check, spc, false, true)) - { - pp_string (buffer, "unknown"); - pp_scalar (buffer, "%lu", (unsigned long) TREE_HASH (elem)); - } - } -} - -/* Dump in BUFFER the contents of all instantiations associated with a given - template T. CPP_CHECK is used to perform C++ queries on nodes. - SPC is the indentation level. */ - -static int -dump_ada_template (pretty_printer *buffer, tree t, - int (*cpp_check)(tree, cpp_operation), int spc) -{ - tree inst = DECL_VINDEX (t); - /* DECL_VINDEX is DECL_TEMPLATE_INSTANTIATIONS in this context. */ - int num_inst = 0; - - while (inst && inst != error_mark_node) - { - tree types = TREE_PURPOSE (inst); - tree instance = TREE_VALUE (inst); - - if (TREE_VEC_LENGTH (types) == 0) - break; - - if (!TYPE_METHODS (instance)) - break; - - num_inst++; - INDENT (spc); - pp_string (buffer, "package "); - package_prefix = false; - dump_generic_ada_node (buffer, instance, t, cpp_check, spc, false, true); - dump_template_types (buffer, types, cpp_check, spc); - pp_string (buffer, " is"); - spc += INDENT_INCR; - newline_and_indent (buffer, spc); - - pp_string (buffer, "type "); - dump_generic_ada_node (buffer, instance, t, cpp_check, spc, false, true); - package_prefix = true; - - if (is_tagged_type (instance)) - pp_string (buffer, " is tagged limited "); - else - pp_string (buffer, " is limited "); - - dump_generic_ada_node (buffer, instance, t, cpp_check, spc, false, false); - pp_newline (buffer); - spc -= INDENT_INCR; - newline_and_indent (buffer, spc); - - pp_string (buffer, "end;"); - newline_and_indent (buffer, spc); - pp_string (buffer, "use "); - package_prefix = false; - dump_generic_ada_node (buffer, instance, t, cpp_check, spc, false, true); - dump_template_types (buffer, types, cpp_check, spc); - package_prefix = true; - pp_semicolon (buffer); - pp_newline (buffer); - pp_newline (buffer); - - inst = TREE_CHAIN (inst); - } - - return num_inst > 0; -} - -static bool in_function = true; -static bool bitfield_used = false; - -/* Recursively dump in BUFFER Ada declarations corresponding to NODE of type - TYPE. CPP_CHECK is used to perform C++ queries on nodes. SPC is the - indentation level. LIMITED_ACCESS indicates whether NODE can be referenced - via a "limited with" clause. NAME_ONLY indicates whether we should only - dump the name of NODE, instead of its full declaration. */ - -static int -dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, - int (*cpp_check)(tree, cpp_operation), int spc, - int limited_access, bool name_only) -{ - if (node == NULL_TREE) - return 0; - - switch (TREE_CODE (node)) - { - case ERROR_MARK: - pp_string (buffer, "<<< error >>>"); - return 0; - - case IDENTIFIER_NODE: - pp_ada_tree_identifier (buffer, node, type, limited_access); - break; - - case TREE_LIST: - pp_string (buffer, "--- unexpected node: TREE_LIST"); - return 0; - - case TREE_BINFO: - dump_generic_ada_node - (buffer, BINFO_TYPE (node), type, cpp_check, - spc, limited_access, name_only); - - case TREE_VEC: - pp_string (buffer, "--- unexpected node: TREE_VEC"); - return 0; - - case VOID_TYPE: - if (package_prefix) - { - append_withs ("System", false); - pp_string (buffer, "System.Address"); - } - else - pp_string (buffer, "address"); - break; - - case VECTOR_TYPE: - pp_string (buffer, ""); - break; - - case COMPLEX_TYPE: - pp_string (buffer, ""); - break; - - case ENUMERAL_TYPE: - if (name_only) - dump_generic_ada_node - (buffer, TYPE_NAME (node), node, cpp_check, spc, 0, true); - else - { - tree value; - - pp_string (buffer, "unsigned"); - - for (value = TYPE_VALUES (node); value; value = TREE_CHAIN (value)) - { - pp_semicolon (buffer); - newline_and_indent (buffer, spc); - - pp_ada_tree_identifier - (buffer, TREE_PURPOSE (value), node, false); - pp_string (buffer, " : constant "); - - dump_generic_ada_node - (buffer, DECL_NAME (type) ? type : TYPE_NAME (node), type, - cpp_check, spc, 0, true); - - pp_string (buffer, " := "); - dump_generic_ada_node - (buffer, - TREE_CODE (TREE_VALUE (value)) == INTEGER_CST ? - TREE_VALUE (value) : DECL_INITIAL (TREE_VALUE (value)), - node, - cpp_check, spc, false, true); - } - } - break; - - case INTEGER_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - case BOOLEAN_TYPE: - { - enum tree_code_class tclass; - - tclass = TREE_CODE_CLASS (TREE_CODE (node)); - - if (tclass == tcc_declaration) - { - if (DECL_NAME (node)) - pp_ada_tree_identifier - (buffer, DECL_NAME (node), 0, limited_access); - else - pp_string (buffer, ""); - } - else if (tclass == tcc_type) - { - if (TYPE_NAME (node)) - { - if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) - pp_ada_tree_identifier (buffer, TYPE_NAME (node), - node, limited_access); - else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (node))) - dump_ada_decl_name (buffer, TYPE_NAME (node), limited_access); - else - pp_string (buffer, ""); - } - else if (TREE_CODE (node) == INTEGER_TYPE) - { - append_withs ("Interfaces.C.Extensions", false); - bitfield_used = true; - - if (TYPE_PRECISION (node) == 1) - pp_string (buffer, "Extensions.Unsigned_1"); - else - { - pp_string (buffer, (TYPE_UNSIGNED (node) - ? "Extensions.Unsigned_" - : "Extensions.Signed_")); - pp_decimal_int (buffer, TYPE_PRECISION (node)); - } - } - else - pp_string (buffer, ""); - } - break; - } - - case POINTER_TYPE: - case REFERENCE_TYPE: - if (TREE_CODE (TREE_TYPE (node)) == FUNCTION_TYPE) - { - tree fnode = TREE_TYPE (node); - bool is_function; - bool prev_in_function = in_function; - - if (VOID_TYPE_P (TREE_TYPE (fnode))) - { - is_function = false; - pp_string (buffer, "access procedure"); - } - else - { - is_function = true; - pp_string (buffer, "access function"); - } - - in_function = is_function; - dump_ada_function_declaration - (buffer, node, false, false, false, spc + INDENT_INCR); - in_function = prev_in_function; - - if (is_function) - { - pp_string (buffer, " return "); - dump_generic_ada_node - (buffer, TREE_TYPE (fnode), type, cpp_check, spc, 0, true); - } - } - else - { - int is_access = false; - unsigned int quals = TYPE_QUALS (TREE_TYPE (node)); - - if (name_only && TYPE_NAME (node)) - dump_generic_ada_node - (buffer, TYPE_NAME (node), node, cpp_check, - spc, limited_access, true); - else if (VOID_TYPE_P (TREE_TYPE (node))) - { - if (!name_only) - pp_string (buffer, "new "); - if (package_prefix) - { - append_withs ("System", false); - pp_string (buffer, "System.Address"); - } - else - pp_string (buffer, "address"); - } - else - { - if (TREE_CODE (node) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (node)) == INTEGER_TYPE - && !strcmp - (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME - (TREE_TYPE (node)))), "char")) - { - if (!name_only) - pp_string (buffer, "new "); - - if (package_prefix) - { - pp_string (buffer, "Interfaces.C.Strings.chars_ptr"); - append_withs ("Interfaces.C.Strings", false); - } - else - pp_string (buffer, "chars_ptr"); - } - else - { - /* For now, handle all access-to-access or - access-to-unknown-structs as opaque system.address. */ - - tree typ = TYPE_NAME (TREE_TYPE (node)); - const_tree typ2 = !type || - DECL_P (type) ? type : TYPE_NAME (type); - const_tree underlying_type = - get_underlying_decl (TREE_TYPE (node)); - - if (TREE_CODE (TREE_TYPE (node)) == POINTER_TYPE - /* Pointer to pointer. */ - - || (RECORD_OR_UNION_TYPE_P (TREE_TYPE (node)) - && (!underlying_type - || !TYPE_FIELDS (TREE_TYPE (underlying_type)))) - /* Pointer to opaque structure. */ - - || (typ && typ2 - && DECL_P (underlying_type) - && DECL_P (typ2) - && decl_sloc (underlying_type, true) - > decl_sloc (typ2, true) - && DECL_SOURCE_FILE (underlying_type) - == DECL_SOURCE_FILE (typ2))) - { - if (package_prefix) - { - append_withs ("System", false); - if (!name_only) - pp_string (buffer, "new "); - pp_string (buffer, "System.Address"); - } - else - pp_string (buffer, "address"); - return spc; - } - - if (!package_prefix) - pp_string (buffer, "access"); - else if (AGGREGATE_TYPE_P (TREE_TYPE (node))) - { - if (!type || TREE_CODE (type) != FUNCTION_DECL) - { - pp_string (buffer, "access "); - is_access = true; - - if (quals & TYPE_QUAL_CONST) - pp_string (buffer, "constant "); - else if (!name_only) - pp_string (buffer, "all "); - } - else if (quals & TYPE_QUAL_CONST) - pp_string (buffer, "in "); - else if (in_function) - { - is_access = true; - pp_string (buffer, "access "); - } - else - { - is_access = true; - pp_string (buffer, "access "); - /* ??? should be configurable: access or in out. */ - } - } - else - { - is_access = true; - pp_string (buffer, "access "); - - if (!name_only) - pp_string (buffer, "all "); - } - - if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (node)) - && TYPE_NAME (TREE_TYPE (node))) - { - tree name = TYPE_NAME (TREE_TYPE (node)); - tree tmp; - - if (TREE_CODE (name) == TYPE_DECL - && DECL_ORIGINAL_TYPE (name) - && TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (name))) - { - tmp = TYPE_NAME (TREE_TYPE (TYPE_STUB_DECL - (DECL_ORIGINAL_TYPE (name)))); - - if (tmp == NULL_TREE) - tmp = TYPE_NAME (TREE_TYPE (node)); - } - else - tmp = TYPE_NAME (TREE_TYPE (node)); - - dump_generic_ada_node - (buffer, tmp, - TREE_TYPE (node), cpp_check, spc, is_access, true); - } - else - dump_generic_ada_node - (buffer, TREE_TYPE (node), TREE_TYPE (node), - cpp_check, spc, 0, true); - } - } - } - break; - - case ARRAY_TYPE: - if (name_only) - dump_generic_ada_node - (buffer, TYPE_NAME (node), node, cpp_check, - spc, limited_access, true); - else - dump_ada_array_type (buffer, node, spc); - break; - - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - if (name_only) - { - if (TYPE_NAME (node)) - dump_generic_ada_node - (buffer, TYPE_NAME (node), node, cpp_check, - spc, limited_access, true); - else - { - pp_string (buffer, "anon_"); - pp_scalar (buffer, "%d", TYPE_UID (node)); - } - } - else - print_ada_struct_decl - (buffer, node, type, cpp_check, spc, true); - break; - - case INTEGER_CST: - if (TREE_CODE (TREE_TYPE (node)) == POINTER_TYPE) - { - pp_wide_integer (buffer, TREE_INT_CST_LOW (node)); - pp_string (buffer, "B"); /* pseudo-unit */ - } - else if (! host_integerp (node, 0)) - { - tree val = node; - unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (val); - HOST_WIDE_INT high = TREE_INT_CST_HIGH (val); - - if (tree_int_cst_sgn (val) < 0) - { - pp_character (buffer, '-'); - high = ~high + !low; - low = -low; - } - sprintf (pp_buffer (buffer)->digit_buffer, - HOST_WIDE_INT_PRINT_DOUBLE_HEX, - (unsigned HOST_WIDE_INT) high, low); - pp_string (buffer, pp_buffer (buffer)->digit_buffer); - } - else - pp_wide_integer (buffer, TREE_INT_CST_LOW (node)); - break; - - case REAL_CST: - case FIXED_CST: - case COMPLEX_CST: - case STRING_CST: - case VECTOR_CST: - return 0; - - case FUNCTION_DECL: - case CONST_DECL: - dump_ada_decl_name (buffer, node, limited_access); - break; - - case TYPE_DECL: - if (DECL_IS_BUILTIN (node)) - { - /* Don't print the declaration of built-in types. */ - - if (name_only) - { - /* If we're in the middle of a declaration, defaults to - System.Address. */ - if (package_prefix) - { - append_withs ("System", false); - pp_string (buffer, "System.Address"); - } - else - pp_string (buffer, "address"); - } - break; - } - - if (name_only) - dump_ada_decl_name (buffer, node, limited_access); - else - { - if (is_tagged_type (TREE_TYPE (node))) - { - tree tmp = TYPE_FIELDS (TREE_TYPE (node)); - int first = 1; - - /* Look for ancestors. */ - for (; tmp; tmp = TREE_CHAIN (tmp)) - { - if (!DECL_NAME (tmp) && is_tagged_type (TREE_TYPE (tmp))) - { - if (first) - { - pp_string (buffer, "limited new "); - first = 0; - } - else - pp_string (buffer, " and "); - - dump_ada_decl_name - (buffer, TYPE_NAME (TREE_TYPE (tmp)), false); - } - } - - pp_string (buffer, first ? "tagged limited " : " with "); - } - else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (node)) - && TYPE_METHODS (TREE_TYPE (node))) - pp_string (buffer, "limited "); - - dump_generic_ada_node - (buffer, TREE_TYPE (node), type, cpp_check, spc, false, false); - } - break; - - case VAR_DECL: - case PARM_DECL: - case FIELD_DECL: - case NAMESPACE_DECL: - dump_ada_decl_name (buffer, node, false); - break; - - default: - /* Ignore other nodes (e.g. expressions). */ - return 0; - } - - return 1; -} - -/* Dump in BUFFER NODE's methods. CPP_CHECK is used to perform C++ queries on - nodes. SPC is the indentation level. */ - -static void -print_ada_methods (pretty_printer *buffer, tree node, - int (*cpp_check)(tree, cpp_operation), int spc) -{ - tree tmp = TYPE_METHODS (node); - int res = 1; - - if (tmp) - { - pp_semicolon (buffer); - - for (; tmp; tmp = TREE_CHAIN (tmp)) - { - if (res) - { - pp_newline (buffer); - pp_newline (buffer); - } - res = print_ada_declaration (buffer, tmp, node, cpp_check, spc); - } - } -} - -/* Dump in BUFFER anonymous types nested inside T's definition. - PARENT is the parent node of T. CPP_CHECK is used to perform C++ queries on - nodes. SPC is the indentation level. */ - -static void -dump_nested_types (pretty_printer *buffer, tree t, tree parent, - int (*cpp_check)(tree, cpp_operation), int spc) -{ - tree field, outer, decl; - - /* Avoid recursing over the same tree. */ - if (TREE_VISITED (t)) - return; - - /* Find possible anonymous arrays/unions/structs recursively. */ - - outer = TREE_TYPE (t); - - if (outer == NULL_TREE) - return; - - field = TYPE_FIELDS (outer); - while (field) - { - if ((TREE_TYPE (field) != outer - || (TREE_CODE (TREE_TYPE (field)) == POINTER_TYPE - && TREE_TYPE (TREE_TYPE (field)) != outer)) - && (!TYPE_NAME (TREE_TYPE (field)) - || (TREE_CODE (field) == TYPE_DECL - && DECL_NAME (field) != DECL_NAME (t) - && TYPE_NAME (TREE_TYPE (field)) != TYPE_NAME (outer)))) - { - switch (TREE_CODE (TREE_TYPE (field))) - { - case POINTER_TYPE: - decl = TREE_TYPE (TREE_TYPE (field)); - - if (TREE_CODE (decl) == FUNCTION_TYPE) - for (decl = TREE_TYPE (decl); - decl && TREE_CODE (decl) == POINTER_TYPE; - decl = TREE_TYPE (decl)); - - decl = get_underlying_decl (decl); - - if (decl - && DECL_P (decl) - && decl_sloc (decl, true) > decl_sloc (t, true) - && DECL_SOURCE_FILE (decl) == DECL_SOURCE_FILE (t) - && !TREE_VISITED (decl) - && !DECL_IS_BUILTIN (decl) - && (!RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)) - || TYPE_FIELDS (TREE_TYPE (decl)))) - { - /* Generate forward declaration. */ - - pp_string (buffer, "type "); - dump_generic_ada_node - (buffer, decl, 0, cpp_check, spc, false, true); - pp_semicolon (buffer); - newline_and_indent (buffer, spc); - - /* Ensure we do not generate duplicate forward - declarations for this type. */ - TREE_VISITED (decl) = 1; - } - break; - - case ARRAY_TYPE: - /* Special case char arrays. */ - if (is_char_array (field)) - pp_string (buffer, "sub"); - - pp_string (buffer, "type "); - dump_ada_double_name (buffer, parent, field, "_array is "); - dump_ada_array_type (buffer, field, spc); - pp_semicolon (buffer); - newline_and_indent (buffer, spc); - break; - - case UNION_TYPE: - TREE_VISITED (t) = 1; - dump_nested_types (buffer, field, t, cpp_check, spc); - - pp_string (buffer, "type "); - - if (TYPE_NAME (TREE_TYPE (field))) - { - dump_generic_ada_node - (buffer, TYPE_NAME (TREE_TYPE (field)), 0, cpp_check, - spc, false, true); - pp_string (buffer, " (discr : unsigned := 0) is "); - print_ada_struct_decl - (buffer, TREE_TYPE (field), t, cpp_check, spc, false); - - pp_string (buffer, "pragma Convention (C_Pass_By_Copy, "); - dump_generic_ada_node - (buffer, TREE_TYPE (field), 0, cpp_check, - spc, false, true); - pp_string (buffer, ");"); - newline_and_indent (buffer, spc); - - pp_string (buffer, "pragma Unchecked_Union ("); - dump_generic_ada_node - (buffer, TREE_TYPE (field), 0, cpp_check, - spc, false, true); - pp_string (buffer, ");"); - } - else - { - dump_ada_double_name - (buffer, parent, field, - "_union (discr : unsigned := 0) is "); - print_ada_struct_decl - (buffer, TREE_TYPE (field), t, cpp_check, spc, false); - pp_string (buffer, "pragma Convention (C_Pass_By_Copy, "); - dump_ada_double_name (buffer, parent, field, "_union);"); - newline_and_indent (buffer, spc); - - pp_string (buffer, "pragma Unchecked_Union ("); - dump_ada_double_name (buffer, parent, field, "_union);"); - } - - newline_and_indent (buffer, spc); - break; - - case RECORD_TYPE: - if (TYPE_NAME (TREE_TYPE (t)) && !TREE_VISITED (t)) - { - pp_string (buffer, "type "); - dump_generic_ada_node - (buffer, t, parent, 0, spc, false, true); - pp_semicolon (buffer); - newline_and_indent (buffer, spc); - } - - TREE_VISITED (t) = 1; - dump_nested_types (buffer, field, t, cpp_check, spc); - pp_string (buffer, "type "); - - if (TYPE_NAME (TREE_TYPE (field))) - { - dump_generic_ada_node - (buffer, TREE_TYPE (field), 0, cpp_check, - spc, false, true); - pp_string (buffer, " is "); - print_ada_struct_decl - (buffer, TREE_TYPE (field), t, cpp_check, spc, false); - pp_string (buffer, "pragma Convention (C_Pass_By_Copy, "); - dump_generic_ada_node - (buffer, TREE_TYPE (field), 0, cpp_check, - spc, false, true); - pp_string (buffer, ");"); - } - else - { - dump_ada_double_name - (buffer, parent, field, "_struct is "); - print_ada_struct_decl - (buffer, TREE_TYPE (field), t, cpp_check, spc, false); - pp_string (buffer, "pragma Convention (C_Pass_By_Copy, "); - dump_ada_double_name (buffer, parent, field, "_struct);"); - } - - newline_and_indent (buffer, spc); - break; - - default: - break; - } - } - field = TREE_CHAIN (field); - } -} - -/* Dump in BUFFER destructor spec corresponding to T. */ - -static void -print_destructor (pretty_printer *buffer, tree t) -{ - const char *s = IDENTIFIER_POINTER (DECL_NAME (t)); - - if (*s == '_') - for (s += 2; *s != ' '; s++) - pp_character (buffer, *s); - else - { - pp_string (buffer, "Delete_"); - pp_ada_tree_identifier (buffer, DECL_NAME (t), t, false); - } -} - -/* Return the name of type T. */ - -static const char * -type_name (tree t) -{ - tree n = TYPE_NAME (t); - - if (TREE_CODE (n) == IDENTIFIER_NODE) - return IDENTIFIER_POINTER (n); - else - return IDENTIFIER_POINTER (DECL_NAME (n)); -} - -/* Print in BUFFER the declaration of a variable T of type TYPE in Ada syntax. - CPP_CHECK is used to perform C++ queries on nodes. SPC is the indentation - level. Return 1 if a declaration was printed, 0 otherwise. */ - -static int -print_ada_declaration (pretty_printer *buffer, tree t, tree type, - int (*cpp_check)(tree, cpp_operation), int spc) -{ - int is_var = 0, need_indent = 0; - int is_class = false; - tree name = TYPE_NAME (TREE_TYPE (t)); - tree decl_name = DECL_NAME (t); - bool dump_internal = get_dump_file_info (TDI_ada)->flags & TDF_RAW; - tree orig = NULL_TREE; - - if (cpp_check && cpp_check (t, IS_TEMPLATE)) - return dump_ada_template (buffer, t, cpp_check, spc); - - if (TREE_CODE (t) == CONST_DECL && TREE_CODE (TREE_TYPE (t)) == ENUMERAL_TYPE) - /* Skip enumeral values: will be handled as part of the type itself. */ - return 0; - - if (TREE_CODE (t) == TYPE_DECL) - { - orig = DECL_ORIGINAL_TYPE (t); - - if (orig && TYPE_STUB_DECL (orig)) - { - tree typ = TREE_TYPE (TYPE_STUB_DECL (orig)); - - if (TYPE_NAME (typ)) - { - /* If types have same representation, and same name (ignoring - casing), then ignore the second type. */ - if (type_name (typ) == type_name (TREE_TYPE (t)) - || !strcasecmp (type_name (typ), type_name (TREE_TYPE (t)))) - return 0; - - INDENT (spc); - - if (RECORD_OR_UNION_TYPE_P (typ) && !TYPE_FIELDS (typ)) - { - pp_string (buffer, "-- skipped empty struct "); - dump_generic_ada_node (buffer, t, type, 0, spc, false, true); - } - else - { - pp_string (buffer, "subtype "); - dump_generic_ada_node (buffer, t, type, 0, spc, false, true); - pp_string (buffer, " is "); - dump_generic_ada_node - (buffer, typ, type, 0, spc, false, true); - pp_semicolon (buffer); - } - return 1; - } - } - - /* Skip unnamed or anonymous structs/unions/enum types. */ - if (!orig && !decl_name && !name) - { - tree tmp; - location_t sloc; - - if (cpp_check || TREE_CODE (TREE_TYPE (t)) == ENUMERAL_TYPE) - return 0; - - if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))) - { - /* Search next items until finding a named type decl. */ - sloc = decl_sloc_common (t, true, true); - - for (tmp = TREE_CHAIN (t); tmp; tmp = TREE_CHAIN (tmp)) - { - if (TREE_CODE (tmp) == TYPE_DECL - && (DECL_NAME (tmp) || TYPE_NAME (TREE_TYPE (tmp)))) - { - /* If same sloc, it means we can ignore the anonymous - struct. */ - if (decl_sloc_common (tmp, true, true) == sloc) - return 0; - else - break; - } - } - if (tmp == NULL) - return 0; - } - } - - if (!orig - && TREE_CODE (TREE_TYPE (t)) == ENUMERAL_TYPE - && decl_name - && (*IDENTIFIER_POINTER (decl_name) == '.' - || *IDENTIFIER_POINTER (decl_name) == '$')) - /* Skip anonymous enum types (duplicates of real types). */ - return 0; - - INDENT (spc); - - switch (TREE_CODE (TREE_TYPE (t))) - { - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - /* Skip empty structs (typically forward references to real - structs). */ - if (!TYPE_FIELDS (TREE_TYPE (t))) - { - pp_string (buffer, "-- skipped empty struct "); - dump_generic_ada_node (buffer, t, type, 0, spc, false, true); - return 1; - } - - if (decl_name - && (*IDENTIFIER_POINTER (decl_name) == '.' - || *IDENTIFIER_POINTER (decl_name) == '$')) - { - pp_string (buffer, "-- skipped anonymous struct "); - dump_generic_ada_node (buffer, t, type, 0, spc, false, true); - return 1; - } - - if (orig && TYPE_NAME (orig) && orig != TREE_TYPE (t)) - pp_string (buffer, "subtype "); - else - { - dump_nested_types (buffer, t, t, cpp_check, spc); - - if (TYPE_METHODS (TREE_TYPE (t)) - || has_static_fields (TREE_TYPE (t))) - { - is_class = true; - pp_string (buffer, "package Class_"); - dump_generic_ada_node - (buffer, t, type, 0, spc, false, true); - pp_string (buffer, " is"); - spc += INDENT_INCR; - newline_and_indent (buffer, spc); - } - - pp_string (buffer, "type "); - } - break; - - case ARRAY_TYPE: - case POINTER_TYPE: - case REFERENCE_TYPE: - if ((orig && TYPE_NAME (orig) && orig != TREE_TYPE (t)) - || is_char_array (t)) - pp_string (buffer, "subtype "); - else - pp_string (buffer, "type "); - break; - - case FUNCTION_TYPE: - pp_string (buffer, "-- skipped function type "); - dump_generic_ada_node (buffer, t, type, 0, spc, false, true); - return 1; - break; - - default: - pp_string (buffer, "subtype "); - } - } - else - { - if (!dump_internal - && TREE_CODE (t) == VAR_DECL - && decl_name - && *IDENTIFIER_POINTER (decl_name) == '_') - return 0; - - need_indent = 1; - } - - /* Print the type and name. */ - if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) - { - if (need_indent) - INDENT (spc); - - /* Print variable's name. */ - dump_generic_ada_node (buffer, t, type, cpp_check, spc, false, true); - - if (TREE_CODE (t) == TYPE_DECL) - { - pp_string (buffer, " is "); - - if (orig && TYPE_NAME (orig) && orig != TREE_TYPE (t)) - dump_generic_ada_node - (buffer, TYPE_NAME (orig), type, - cpp_check, spc, false, true); - else - dump_ada_array_type (buffer, t, spc); - } - else - { - tree tmp = TYPE_NAME (TREE_TYPE (t)); - - if (spc == INDENT_INCR || TREE_STATIC (t)) - is_var = 1; - - pp_string (buffer, " : "); - - if (tmp) - { - if (TREE_CODE (TREE_TYPE (tmp)) != POINTER_TYPE - && TREE_CODE (tmp) != INTEGER_TYPE) - pp_string (buffer, "aliased "); - - dump_generic_ada_node (buffer, tmp, type, 0, spc, false, true); - } - else - { - pp_string (buffer, "aliased "); - - if (!type) - dump_ada_array_type (buffer, t, spc); - else - dump_ada_double_name (buffer, type, t, "_array"); - } - } - } - else if (TREE_CODE (t) == FUNCTION_DECL) - { - bool is_function = true, is_method, is_abstract_class = false; - tree decl_name = DECL_NAME (t); - int prev_in_function = in_function; - bool is_abstract = false; - bool is_constructor = false; - bool is_destructor = false; - bool is_copy_constructor = false; - - if (!decl_name) - return 0; - - if (cpp_check) - { - is_abstract = cpp_check (t, IS_ABSTRACT); - is_constructor = cpp_check (t, IS_CONSTRUCTOR); - is_destructor = cpp_check (t, IS_DESTRUCTOR); - is_copy_constructor = cpp_check (t, IS_COPY_CONSTRUCTOR); - } - - /* Skip __comp_dtor destructor which is redundant with the '~class()' - destructor. */ - if (is_destructor - && !strncmp (IDENTIFIER_POINTER (decl_name), "__comp", 6)) - return 0; - - /* Skip copy constructors: some are internal only, and those that are - not cannot be called easily from Ada anyway. */ - if (is_copy_constructor) - return 0; - - /* If this function has an entry in the dispatch table, we cannot - omit it. */ - if (!dump_internal && !DECL_VINDEX (t) - && *IDENTIFIER_POINTER (decl_name) == '_') - { - if (IDENTIFIER_POINTER (decl_name)[1] == '_') - return 0; - - INDENT (spc); - pp_string (buffer, "-- skipped func "); - pp_string (buffer, IDENTIFIER_POINTER (decl_name)); - return 1; - } - - if (need_indent) - INDENT (spc); - - if (is_constructor) - pp_string (buffer, "function New_"); - else if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (t)))) - { - is_function = false; - pp_string (buffer, "procedure "); - } - else - pp_string (buffer, "function "); - - in_function = is_function; - is_method = TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE; - - if (is_destructor) - print_destructor (buffer, t); - else - dump_ada_decl_name (buffer, t, false); - - dump_ada_function_declaration - (buffer, t, is_method, is_constructor, is_destructor, spc); - in_function = prev_in_function; - - if (is_function) - { - pp_string (buffer, " return "); - - if (is_constructor) - { - dump_ada_decl_name (buffer, t, false); - } - else - { - dump_generic_ada_node - (buffer, TREE_TYPE (TREE_TYPE (t)), type, cpp_check, - spc, false, true); - } - } - - if (is_constructor && cpp_check && type - && AGGREGATE_TYPE_P (type) - && TYPE_METHODS (type)) - { - tree tmp = TYPE_METHODS (type); - - for (; tmp; tmp = TREE_CHAIN (tmp)) - if (cpp_check (tmp, IS_ABSTRACT)) - { - is_abstract_class = 1; - break; - } - } - - if (is_abstract || is_abstract_class) - pp_string (buffer, " is abstract"); - - pp_semicolon (buffer); - pp_string (buffer, " -- "); - dump_sloc (buffer, t); - - if (is_abstract) - return 1; - - newline_and_indent (buffer, spc); - - if (is_constructor) - { - pp_string (buffer, "pragma CPP_Constructor (New_"); - dump_ada_decl_name (buffer, t, false); - pp_string (buffer, ", \""); - pp_asm_name (buffer, t); - pp_string (buffer, "\");"); - } - else if (is_destructor) - { - pp_string (buffer, "pragma Import (CPP, "); - print_destructor (buffer, t); - pp_string (buffer, ", \""); - pp_asm_name (buffer, t); - pp_string (buffer, "\");"); - } - else - { - dump_ada_import (buffer, t); - } - - return 1; - } - else if (TREE_CODE (t) == TYPE_DECL && !DECL_ORIGINAL_TYPE (t)) - { - int is_interface = 0; - int is_abstract_record = 0; - - if (need_indent) - INDENT (spc); - - /* Anonymous structs/unions */ - dump_generic_ada_node - (buffer, TREE_TYPE (t), t, cpp_check, spc, false, true); - - if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE - || TREE_CODE (TREE_TYPE (t)) == QUAL_UNION_TYPE) - { - pp_string (buffer, " (discr : unsigned := 0)"); - } - - pp_string (buffer, " is "); - - /* Check whether we have an Ada interface compatible class. */ - if (cpp_check && AGGREGATE_TYPE_P (TREE_TYPE (t)) - && TYPE_METHODS (TREE_TYPE (t))) - { - int num_fields = 0; - tree tmp = TYPE_FIELDS (TREE_TYPE (t)); - - /* Check that there are no fields other than the virtual table. */ - for (; tmp; tmp = TREE_CHAIN (tmp)) - { - if (TREE_CODE (tmp) == TYPE_DECL) - continue; - num_fields++; - } - - if (num_fields == 1) - is_interface = 1; - - /* Also check that there are only virtual methods. */ - for (tmp = TYPE_METHODS (TREE_TYPE (t)); tmp; tmp = TREE_CHAIN (tmp)) - { - if (cpp_check (tmp, IS_ABSTRACT)) - is_abstract_record = 1; - else - is_interface = 0; - } - } - - if (is_interface) - { - pp_string (buffer, "limited interface; -- "); - dump_sloc (buffer, t); - newline_and_indent (buffer, spc); - pp_string (buffer, "pragma Import (CPP, "); - dump_generic_ada_node - (buffer, TYPE_NAME (TREE_TYPE (t)), type, cpp_check, - spc, false, true); - pp_character (buffer, ')'); - - print_ada_methods (buffer, TREE_TYPE (t), cpp_check, spc); - } - else - { - if (is_abstract_record) - pp_string (buffer, "abstract "); - dump_generic_ada_node (buffer, t, t, cpp_check, spc, false, false); - } - } - else - { - if (need_indent) - INDENT (spc); - - if (TREE_CODE (t) == FIELD_DECL && DECL_NAME (t)) - check_name (buffer, t); - - /* Print variable/type's name. */ - dump_generic_ada_node (buffer, t, t, cpp_check, spc, false, true); - - if (TREE_CODE (t) == TYPE_DECL) - { - tree orig = DECL_ORIGINAL_TYPE (t); - int is_subtype = orig && TYPE_NAME (orig) && orig != TREE_TYPE (t); - - if (!is_subtype - && (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE - || TREE_CODE (TREE_TYPE (t)) == QUAL_UNION_TYPE)) - pp_string (buffer, " (discr : unsigned := 0)"); - - pp_string (buffer, " is "); - - dump_generic_ada_node - (buffer, orig, t, cpp_check, spc, false, is_subtype); - } - else - { - if (spc == INDENT_INCR || TREE_STATIC (t)) - is_var = 1; - - pp_string (buffer, " : "); - - /* Print type declaration. */ - - if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE - && !TYPE_NAME (TREE_TYPE (t))) - { - dump_ada_double_name (buffer, type, t, "_union"); - } - else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))) - { - if (TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE) - pp_string (buffer, "aliased "); - - dump_generic_ada_node - (buffer, TREE_TYPE (t), t, cpp_check, spc, false, true); - } - else - { - if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE - && (TYPE_NAME (TREE_TYPE (t)) - || TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE)) - pp_string (buffer, "aliased "); - - dump_generic_ada_node - (buffer, TREE_TYPE (t), TREE_TYPE (t), cpp_check, - spc, false, true); - } - } - } - - if (is_class) - { - spc -= 3; - newline_and_indent (buffer, spc); - pp_string (buffer, "end;"); - newline_and_indent (buffer, spc); - pp_string (buffer, "use Class_"); - dump_generic_ada_node (buffer, t, type, 0, spc, false, true); - pp_semicolon (buffer); - pp_newline (buffer); - - /* All needed indentation/newline performed already, so return 0. */ - return 0; - } - else - { - pp_string (buffer, "; -- "); - dump_sloc (buffer, t); - } - - if (is_var) - { - newline_and_indent (buffer, spc); - dump_ada_import (buffer, t); - } - - return 1; -} - -/* Prints in BUFFER a structure NODE of type TYPE: name, fields, and methods - with Ada syntax. CPP_CHECK is used to perform C++ queries on nodes. SPC - is the indentation level. If DISPLAY_CONVENTION is true, also print the - pragma Convention for NODE. */ - -static void -print_ada_struct_decl (pretty_printer *buffer, tree node, tree type, - int (*cpp_check)(tree, cpp_operation), int spc, - bool display_convention) -{ - tree tmp; - int is_union = - TREE_CODE (node) == UNION_TYPE || TREE_CODE (node) == QUAL_UNION_TYPE; - char buf [16]; - int field_num = 0; - int field_spc = spc + INDENT_INCR; - int need_semicolon; - - bitfield_used = false; - - if (!TYPE_FIELDS (node)) - pp_string (buffer, "null record;"); - else - { - pp_string (buffer, "record"); - - /* Print the contents of the structure. */ - - if (is_union) - { - newline_and_indent (buffer, spc + INDENT_INCR); - pp_string (buffer, "case discr is"); - field_spc = spc + INDENT_INCR * 3; - } - - pp_newline (buffer); - - /* Print the non-static fields of the structure. */ - for (tmp = TYPE_FIELDS (node); tmp; tmp = TREE_CHAIN (tmp)) - { - /* Add parent field if needed. */ - if (!DECL_NAME (tmp)) - { - if (!is_tagged_type (TREE_TYPE (tmp))) - { - if (!TYPE_NAME (TREE_TYPE (tmp))) - print_ada_declaration - (buffer, tmp, type, cpp_check, field_spc); - else - { - INDENT (field_spc); - - if (field_num == 0) - pp_string (buffer, "parent : "); - else - { - sprintf (buf, "field_%d : ", field_num + 1); - pp_string (buffer, buf); - } - dump_ada_decl_name - (buffer, TYPE_NAME (TREE_TYPE (tmp)), false); - pp_semicolon (buffer); - } - pp_newline (buffer); - field_num++; - } - } - /* Avoid printing the structure recursively. */ - else if ((TREE_TYPE (tmp) != node - || (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE - && TREE_TYPE (TREE_TYPE (tmp)) != node)) - && TREE_CODE (tmp) != TYPE_DECL - && !TREE_STATIC (tmp)) - { - /* Skip internal virtual table field. */ - if (strncmp (IDENTIFIER_POINTER (DECL_NAME (tmp)), "_vptr", 5)) - { - if (is_union) - { - if (TREE_CHAIN (tmp) - && TREE_TYPE (TREE_CHAIN (tmp)) != node - && TREE_CODE (TREE_CHAIN (tmp)) != TYPE_DECL) - sprintf (buf, "when %d =>", field_num); - else - sprintf (buf, "when others =>"); - - INDENT (spc + INDENT_INCR * 2); - pp_string (buffer, buf); - pp_newline (buffer); - } - - if (print_ada_declaration (buffer, - tmp, type, cpp_check, field_spc)) - { - pp_newline (buffer); - field_num++; - } - } - } - } - - if (is_union) - { - INDENT (spc + INDENT_INCR); - pp_string (buffer, "end case;"); - pp_newline (buffer); - } - - if (field_num == 0) - { - INDENT (spc + INDENT_INCR); - pp_string (buffer, "null;"); - pp_newline (buffer); - } - - INDENT (spc); - pp_string (buffer, "end record;"); - } - - newline_and_indent (buffer, spc); - - if (!display_convention) - return; - - if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))) - { - if (TYPE_METHODS (TREE_TYPE (type))) - pp_string (buffer, "pragma Import (CPP, "); - else - pp_string (buffer, "pragma Convention (C_Pass_By_Copy, "); - } - else - pp_string (buffer, "pragma Convention (C, "); - - package_prefix = false; - dump_generic_ada_node - (buffer, TREE_TYPE (type), type, cpp_check, spc, false, true); - package_prefix = true; - pp_character (buffer, ')'); - - if (is_union) - { - pp_semicolon (buffer); - newline_and_indent (buffer, spc); - pp_string (buffer, "pragma Unchecked_Union ("); - - dump_generic_ada_node - (buffer, TREE_TYPE (type), type, cpp_check, spc, false, true); - pp_character (buffer, ')'); - } - - if (bitfield_used) - { - pp_semicolon (buffer); - newline_and_indent (buffer, spc); - pp_string (buffer, "pragma Pack ("); - dump_generic_ada_node - (buffer, TREE_TYPE (type), type, cpp_check, spc, false, true); - pp_character (buffer, ')'); - bitfield_used = false; - } - - print_ada_methods (buffer, node, cpp_check, spc); - - /* Print the static fields of the structure, if any. */ - need_semicolon = TYPE_METHODS (node) == NULL_TREE; - for (tmp = TYPE_FIELDS (node); tmp; tmp = TREE_CHAIN (tmp)) - { - if (DECL_NAME (tmp) && TREE_STATIC (tmp)) - { - if (need_semicolon) - { - need_semicolon = false; - pp_semicolon (buffer); - } - pp_newline (buffer); - pp_newline (buffer); - print_ada_declaration (buffer, tmp, type, cpp_check, spc); - } - } -} - -/* Dump all the declarations in SOURCE_FILE to an Ada spec. - COLLECT_ALL_REFS is a front-end callback used to collect all relevant - nodes for SOURCE_FILE. CPP_CHECK is used to perform C++ queries on - nodes. */ - -static void -dump_ads (const char *source_file, - void (*collect_all_refs)(const char *), - int (*cpp_check)(tree, cpp_operation)) -{ - char *ads_name; - char *pkg_name; - char *s; - FILE *f; - - pkg_name = get_ada_package (source_file); - - /* Construct the the .ads filename and package name. */ - ads_name = xstrdup (pkg_name); - - for (s = ads_name; *s; s++) - *s = TOLOWER (*s); - - ads_name = reconcat (ads_name, ads_name, ".ads", NULL); - - /* Write out the .ads file. */ - f = fopen (ads_name, "w"); - if (f) - { - pretty_printer pp; - - pp_construct (&pp, NULL, 0); - pp_needs_newline (&pp) = true; - pp.buffer->stream = f; - - /* Dump all relevant macros. */ - dump_ada_macros (&pp, source_file); - - /* Reset the table of withs for this file. */ - reset_ada_withs (); - - (*collect_all_refs) (source_file); - - /* Dump all references. */ - dump_ada_nodes (&pp, source_file, cpp_check); - - /* Dump withs. */ - dump_ada_withs (f); - - fprintf (f, "\npackage %s is\n\n", pkg_name); - pp_write_text_to_stream (&pp); - /* ??? need to free pp */ - fprintf (f, "end %s;\n", pkg_name); - fclose (f); - } - - free (ads_name); - free (pkg_name); -} - -static const char **source_refs = NULL; -static int source_refs_used = 0; -static int source_refs_allocd = 0; - -/* Add an entry for FILENAME to the table SOURCE_REFS. */ - -void -collect_source_ref (const char *filename) -{ - int i; - - if (!filename) - return; - - if (source_refs_allocd == 0) - { - source_refs_allocd = 1024; - source_refs = XNEWVEC (const char *, source_refs_allocd); - } - - for (i = 0; i < source_refs_used; i++) - if (filename == source_refs [i]) - return; - - if (source_refs_used == source_refs_allocd) - { - source_refs_allocd *= 2; - source_refs = XRESIZEVEC (const char *, source_refs, source_refs_allocd); - } - - source_refs [source_refs_used++] = filename; -} - -/* Main entry point: dump all Ada specs corresponding to SOURCE_REFS - using callbacks COLLECT_ALL_REFS and CPP_CHECK. - COLLECT_ALL_REFS is a front-end callback used to collect all relevant - nodes for a given source file. - CPP_CHECK is used to perform C++ queries on nodes, or NULL for the C - front-end. */ - -void -dump_ada_specs (void (*collect_all_refs)(const char *), - int (*cpp_check)(tree, cpp_operation)) -{ - int i; - - /* Iterate over the list of files to dump specs for */ - for (i = 0; i < source_refs_used; i++) - dump_ads (source_refs [i], collect_all_refs, cpp_check); - - /* Free files table. */ - free (source_refs); -} diff --git a/gcc/c-ada-spec.h b/gcc/c-ada-spec.h deleted file mode 100644 index 8aed158..0000000 --- a/gcc/c-ada-spec.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Interface for -fdump-ada-spec capability. - Copyright (C) 2010, 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 -. */ - -#ifndef C_ADA_SPEC_H -#define C_ADA_SPEC_H - -#include "pretty-print.h" - -/* In c-ada-spec.c */ - -typedef enum { - IS_ABSTRACT, - IS_CONSTRUCTOR, - IS_DESTRUCTOR, - IS_COPY_CONSTRUCTOR, - IS_TEMPLATE -} cpp_operation; - -extern location_t decl_sloc (const_tree, bool); -extern void collect_ada_nodes (tree, const char *); -extern void collect_source_ref (const char *); -extern void dump_ada_specs (void (*)(const char *), - int (*)(tree, cpp_operation)); - -#endif /* ! C_ADA_SPEC_H */ diff --git a/gcc/c-common.c b/gcc/c-common.c deleted file mode 100644 index 1c51118..0000000 --- a/gcc/c-common.c +++ /dev/null @@ -1,9466 +0,0 @@ -/* Subroutines shared by all languages that are variants of C. - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - 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 -. */ - -/* FIXME: Still need to include rtl.h here (via expr.h) in a front-end file. - Pretend this is a back-end file. */ -#undef IN_GCC_FRONTEND - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "intl.h" -#include "tree.h" -#include "flags.h" -#include "output.h" -#include "c-pragma.h" -#include "ggc.h" -#include "c-common.h" -#include "tm_p.h" -#include "obstack.h" -#include "cpplib.h" -#include "target.h" -#include "langhooks.h" -#include "tree-inline.h" -#include "toplev.h" -#include "diagnostic.h" -#include "tree-iterator.h" -#include "hashtab.h" -#include "tree-mudflap.h" -#include "opts.h" -#include "cgraph.h" -#include "target-def.h" -#include "libfuncs.h" - -#include "expr.h" /* For vector_mode_valid_p */ - -cpp_reader *parse_in; /* Declared in c-pragma.h. */ - -/* The following symbols are subsumed in the c_global_trees array, and - listed here individually for documentation purposes. - - INTEGER_TYPE and REAL_TYPE nodes for the standard data types. - - tree short_integer_type_node; - tree long_integer_type_node; - tree long_long_integer_type_node; - tree int128_integer_type_node; - - tree short_unsigned_type_node; - tree long_unsigned_type_node; - tree long_long_unsigned_type_node; - tree int128_unsigned_type_node; - - tree truthvalue_type_node; - tree truthvalue_false_node; - tree truthvalue_true_node; - - tree ptrdiff_type_node; - - tree unsigned_char_type_node; - tree signed_char_type_node; - tree wchar_type_node; - - tree char16_type_node; - tree char32_type_node; - - tree float_type_node; - tree double_type_node; - tree long_double_type_node; - - tree complex_integer_type_node; - tree complex_float_type_node; - tree complex_double_type_node; - tree complex_long_double_type_node; - - tree dfloat32_type_node; - tree dfloat64_type_node; - tree_dfloat128_type_node; - - tree intQI_type_node; - tree intHI_type_node; - tree intSI_type_node; - tree intDI_type_node; - tree intTI_type_node; - - tree unsigned_intQI_type_node; - tree unsigned_intHI_type_node; - tree unsigned_intSI_type_node; - tree unsigned_intDI_type_node; - tree unsigned_intTI_type_node; - - tree widest_integer_literal_type_node; - tree widest_unsigned_literal_type_node; - - Nodes for types `void *' and `const void *'. - - tree ptr_type_node, const_ptr_type_node; - - Nodes for types `char *' and `const char *'. - - tree string_type_node, const_string_type_node; - - Type `char[SOMENUMBER]'. - Used when an array of char is needed and the size is irrelevant. - - tree char_array_type_node; - - Type `int[SOMENUMBER]' or something like it. - Used when an array of int needed and the size is irrelevant. - - tree int_array_type_node; - - Type `wchar_t[SOMENUMBER]' or something like it. - Used when a wide string literal is created. - - tree wchar_array_type_node; - - Type `char16_t[SOMENUMBER]' or something like it. - Used when a UTF-16 string literal is created. - - tree char16_array_type_node; - - Type `char32_t[SOMENUMBER]' or something like it. - Used when a UTF-32 string literal is created. - - tree char32_array_type_node; - - Type `int ()' -- used for implicit declaration of functions. - - tree default_function_type; - - A VOID_TYPE node, packaged in a TREE_LIST. - - tree void_list_node; - - The lazily created VAR_DECLs for __FUNCTION__, __PRETTY_FUNCTION__, - and __func__. (C doesn't generate __FUNCTION__ and__PRETTY_FUNCTION__ - VAR_DECLS, but C++ does.) - - tree function_name_decl_node; - tree pretty_function_name_decl_node; - tree c99_function_name_decl_node; - - Stack of nested function name VAR_DECLs. - - tree saved_function_name_decls; - -*/ - -tree c_global_trees[CTI_MAX]; - -/* Switches common to the C front ends. */ - -/* Nonzero if preprocessing only. */ - -int flag_preprocess_only; - -/* Nonzero means don't output line number information. */ - -char flag_no_line_commands; - -/* Nonzero causes -E output not to be done, but directives such as - #define that have side effects are still obeyed. */ - -char flag_no_output; - -/* Nonzero means dump macros in some fashion. */ - -char flag_dump_macros; - -/* Nonzero means pass #include lines through to the output. */ - -char flag_dump_includes; - -/* Nonzero means process PCH files while preprocessing. */ - -bool flag_pch_preprocess; - -/* The file name to which we should write a precompiled header, or - NULL if no header will be written in this compile. */ - -const char *pch_file; - -/* Nonzero if an ISO standard was selected. It rejects macros in the - user's namespace. */ -int flag_iso; - -/* Nonzero if -undef was given. It suppresses target built-in macros - and assertions. */ -int flag_undef; - -/* Nonzero means don't recognize the non-ANSI builtin functions. */ - -int flag_no_builtin; - -/* Nonzero means don't recognize the non-ANSI builtin functions. - -ansi sets this. */ - -int flag_no_nonansi_builtin; - -/* Nonzero means give `double' the same size as `float'. */ - -int flag_short_double; - -/* Nonzero means give `wchar_t' the same size as `short'. */ - -int flag_short_wchar; - -/* Nonzero means allow implicit conversions between vectors with - differing numbers of subparts and/or differing element types. */ -int flag_lax_vector_conversions; - -/* Nonzero means allow Microsoft extensions without warnings or errors. */ -int flag_ms_extensions; - -/* Nonzero means don't recognize the keyword `asm'. */ - -int flag_no_asm; - -/* Nonzero means to treat bitfields as signed unless they say `unsigned'. */ - -int flag_signed_bitfields = 1; - -/* Warn about #pragma directives that are not recognized. */ - -int warn_unknown_pragmas; /* Tri state variable. */ - -/* Warn about format/argument anomalies in calls to formatted I/O functions - (*printf, *scanf, strftime, strfmon, etc.). */ - -int warn_format; - -/* Warn about using __null (as NULL in C++) as sentinel. For code compiled - with GCC this doesn't matter as __null is guaranteed to have the right - size. */ - -int warn_strict_null_sentinel; - -/* Zero means that faster, ...NonNil variants of objc_msgSend... - calls will be used in ObjC; passing nil receivers to such calls - will most likely result in crashes. */ -int flag_nil_receivers = 1; - -/* Nonzero means that code generation will be altered to support - "zero-link" execution. This currently affects ObjC only, but may - affect other languages in the future. */ -int flag_zero_link = 0; - -/* Nonzero means emit an '__OBJC, __image_info' for the current translation - unit. It will inform the ObjC runtime that class definition(s) herein - contained are to replace one(s) previously loaded. */ -int flag_replace_objc_classes = 0; - -/* C/ObjC language option variables. */ - - -/* Nonzero means allow type mismatches in conditional expressions; - just make their values `void'. */ - -int flag_cond_mismatch; - -/* Nonzero means enable C89 Amendment 1 features. */ - -int flag_isoc94; - -/* Nonzero means use the ISO C99 (or C1X) dialect of C. */ - -int flag_isoc99; - -/* Nonzero means use the ISO C1X dialect of C. */ - -int flag_isoc1x; - -/* Nonzero means that we have builtin functions, and main is an int. */ - -int flag_hosted = 1; - - -/* ObjC language option variables. */ - - -/* Open and close the file for outputting class declarations, if - requested (ObjC). */ - -int flag_gen_declaration; - -/* Tells the compiler that this is a special run. Do not perform any - compiling, instead we are to test some platform dependent features - and output a C header file with appropriate definitions. */ - -int print_struct_values; - -/* Tells the compiler what is the constant string class for ObjC. */ - -const char *constant_string_class_name; - - -/* C++ language option variables. */ - - -/* Nonzero means don't recognize any extension keywords. */ - -int flag_no_gnu_keywords; - -/* Nonzero means do emit exported implementations of functions even if - they can be inlined. */ - -int flag_implement_inlines = 1; - -/* Nonzero means that implicit instantiations will be emitted if needed. */ - -int flag_implicit_templates = 1; - -/* Nonzero means that implicit instantiations of inline templates will be - emitted if needed, even if instantiations of non-inline templates - aren't. */ - -int flag_implicit_inline_templates = 1; - -/* Nonzero means generate separate instantiation control files and - juggle them at link time. */ - -int flag_use_repository; - -/* Nonzero if we want to issue diagnostics that the standard says are not - required. */ - -int flag_optional_diags = 1; - -/* Nonzero means we should attempt to elide constructors when possible. */ - -int flag_elide_constructors = 1; - -/* Nonzero means that member functions defined in class scope are - inline by default. */ - -int flag_default_inline = 1; - -/* Controls whether compiler generates 'type descriptor' that give - run-time type information. */ - -int flag_rtti = 1; - -/* Nonzero if we want to conserve space in the .o files. We do this - by putting uninitialized data and runtime initialized data into - .common instead of .data at the expense of not flagging multiple - definitions. */ - -int flag_conserve_space; - -/* Nonzero if we want to obey access control semantics. */ - -int flag_access_control = 1; - -/* Nonzero if we want to check the return value of new and avoid calling - constructors if it is a null pointer. */ - -int flag_check_new; - -/* The C++ dialect being used. C++98 is the default. */ - -enum cxx_dialect cxx_dialect = cxx98; - -/* Nonzero if we want the new ISO rules for pushing a new scope for `for' - initialization variables. - 0: Old rules, set by -fno-for-scope. - 2: New ISO rules, set by -ffor-scope. - 1: Try to implement new ISO rules, but with backup compatibility - (and warnings). This is the default, for now. */ - -int flag_new_for_scope = 1; - -/* Nonzero if we want to emit defined symbols with common-like linkage as - weak symbols where possible, in order to conform to C++ semantics. - Otherwise, emit them as local symbols. */ - -int flag_weak = 1; - -/* 0 means we want the preprocessor to not emit line directives for - the current working directory. 1 means we want it to do it. -1 - means we should decide depending on whether debugging information - is being emitted or not. */ - -int flag_working_directory = -1; - -/* Nonzero to use __cxa_atexit, rather than atexit, to register - destructors for local statics and global objects. '2' means it has been - set nonzero as a default, not by a command-line flag. */ - -int flag_use_cxa_atexit = DEFAULT_USE_CXA_ATEXIT; - -/* Nonzero to use __cxa_get_exception_ptr in C++ exception-handling - code. '2' means it has not been set explicitly on the command line. */ - -int flag_use_cxa_get_exception_ptr = 2; - -/* Nonzero means to implement standard semantics for exception - specifications, calling unexpected if an exception is thrown that - doesn't match the specification. Zero means to treat them as - assertions and optimize accordingly, but not check them. */ - -int flag_enforce_eh_specs = 1; - -/* Nonzero means to generate thread-safe code for initializing local - statics. */ - -int flag_threadsafe_statics = 1; - -/* Nonzero if we want to pretty-print template specializations as the - template signature followed by the arguments. */ - -int flag_pretty_templates = 1; - -/* Maximum template instantiation depth. This limit exists to limit the - time it takes to notice infinite template instantiations; the default - value of 1024 is likely to be in the next C++ standard. */ - -int max_tinst_depth = 1024; - - - -/* The elements of `ridpointers' are identifier nodes for the reserved - type names and storage classes. It is indexed by a RID_... value. */ -tree *ridpointers; - -tree (*make_fname_decl) (location_t, tree, int); - -/* Nonzero means don't warn about problems that occur when the code is - executed. */ -int c_inhibit_evaluation_warnings; - -/* Whether lexing has been completed, so subsequent preprocessor - errors should use the compiler's input_location. */ -bool done_lexing = false; - -/* Information about how a function name is generated. */ -struct fname_var_t -{ - tree *const decl; /* pointer to the VAR_DECL. */ - const unsigned rid; /* RID number for the identifier. */ - const int pretty; /* How pretty is it? */ -}; - -/* The three ways of getting then name of the current function. */ - -const struct fname_var_t fname_vars[] = -{ - /* C99 compliant __func__, must be first. */ - {&c99_function_name_decl_node, RID_C99_FUNCTION_NAME, 0}, - /* GCC __FUNCTION__ compliant. */ - {&function_name_decl_node, RID_FUNCTION_NAME, 0}, - /* GCC __PRETTY_FUNCTION__ compliant. */ - {&pretty_function_name_decl_node, RID_PRETTY_FUNCTION_NAME, 1}, - {NULL, 0, 0}, -}; - -static tree c_fully_fold_internal (tree expr, bool, bool *, bool *); -static tree check_case_value (tree); -static bool check_case_bounds (tree, tree, tree *, tree *); - -static tree handle_packed_attribute (tree *, tree, tree, int, bool *); -static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *); -static tree handle_common_attribute (tree *, tree, tree, int, bool *); -static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); -static tree handle_hot_attribute (tree *, tree, tree, int, bool *); -static tree handle_cold_attribute (tree *, tree, tree, int, bool *); -static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); -static tree handle_noclone_attribute (tree *, tree, tree, int, bool *); -static tree handle_always_inline_attribute (tree *, tree, tree, int, - bool *); -static tree handle_gnu_inline_attribute (tree *, tree, tree, int, bool *); -static tree handle_artificial_attribute (tree *, tree, tree, int, bool *); -static tree handle_flatten_attribute (tree *, tree, tree, int, bool *); -static tree handle_error_attribute (tree *, tree, tree, int, bool *); -static tree handle_used_attribute (tree *, tree, tree, int, bool *); -static tree handle_unused_attribute (tree *, tree, tree, int, bool *); -static tree handle_externally_visible_attribute (tree *, tree, tree, int, - bool *); -static tree handle_const_attribute (tree *, tree, tree, int, bool *); -static tree handle_transparent_union_attribute (tree *, tree, tree, - int, bool *); -static tree handle_constructor_attribute (tree *, tree, tree, int, bool *); -static tree handle_destructor_attribute (tree *, tree, tree, int, bool *); -static tree handle_mode_attribute (tree *, tree, tree, int, bool *); -static tree handle_section_attribute (tree *, tree, tree, int, bool *); -static tree handle_aligned_attribute (tree *, tree, tree, int, bool *); -static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ; -static tree handle_alias_attribute (tree *, tree, tree, int, bool *); -static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ; -static tree handle_visibility_attribute (tree *, tree, tree, int, - bool *); -static tree handle_tls_model_attribute (tree *, tree, tree, int, - bool *); -static tree handle_no_instrument_function_attribute (tree *, tree, - tree, int, bool *); -static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); -static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); -static tree handle_no_limit_stack_attribute (tree *, tree, tree, int, - bool *); -static tree handle_pure_attribute (tree *, tree, tree, int, bool *); -static tree handle_novops_attribute (tree *, tree, tree, int, bool *); -static tree handle_deprecated_attribute (tree *, tree, tree, int, - bool *); -static tree handle_vector_size_attribute (tree *, tree, tree, int, - bool *); -static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); -static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); -static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *); -static tree handle_warn_unused_result_attribute (tree *, tree, tree, int, - bool *); -static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); -static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); -static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *); -static tree handle_target_attribute (tree *, tree, tree, int, bool *); -static tree handle_optimize_attribute (tree *, tree, tree, int, bool *); -static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); - -static void check_function_nonnull (tree, int, tree *); -static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); -static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT); -static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *); -static int resort_field_decl_cmp (const void *, const void *); - -/* Reserved words. The third field is a mask: keywords are disabled - if they match the mask. - - Masks for languages: - C --std=c89: D_C99 | D_CXXONLY | D_OBJC | D_CXX_OBJC - C --std=c99: D_CXXONLY | D_OBJC - ObjC is like C except that D_OBJC and D_CXX_OBJC are not set - C++ --std=c98: D_CONLY | D_CXXOX | D_OBJC - C++ --std=c0x: D_CONLY | D_OBJC - ObjC++ is like C++ except that D_OBJC is not set - - If -fno-asm is used, D_ASM is added to the mask. If - -fno-gnu-keywords is used, D_EXT is added. If -fno-asm and C in - C89 mode, D_EXT89 is added for both -fno-asm and -fno-gnu-keywords. - In C with -Wc++-compat, we warn if D_CXXWARN is set. */ - -const struct c_common_resword c_common_reswords[] = -{ - { "_Bool", RID_BOOL, D_CONLY }, - { "_Complex", RID_COMPLEX, 0 }, - { "_Imaginary", RID_IMAGINARY, D_CONLY }, - { "_Decimal32", RID_DFLOAT32, D_CONLY | D_EXT }, - { "_Decimal64", RID_DFLOAT64, D_CONLY | D_EXT }, - { "_Decimal128", RID_DFLOAT128, D_CONLY | D_EXT }, - { "_Fract", RID_FRACT, D_CONLY | D_EXT }, - { "_Accum", RID_ACCUM, D_CONLY | D_EXT }, - { "_Sat", RID_SAT, D_CONLY | D_EXT }, - { "_Static_assert", RID_STATIC_ASSERT, D_CONLY }, - { "__FUNCTION__", RID_FUNCTION_NAME, 0 }, - { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 }, - { "__alignof", RID_ALIGNOF, 0 }, - { "__alignof__", RID_ALIGNOF, 0 }, - { "__asm", RID_ASM, 0 }, - { "__asm__", RID_ASM, 0 }, - { "__attribute", RID_ATTRIBUTE, 0 }, - { "__attribute__", RID_ATTRIBUTE, 0 }, - { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY }, - { "__builtin_offsetof", RID_OFFSETOF, 0 }, - { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY }, - { "__builtin_va_arg", RID_VA_ARG, 0 }, - { "__complex", RID_COMPLEX, 0 }, - { "__complex__", RID_COMPLEX, 0 }, - { "__const", RID_CONST, 0 }, - { "__const__", RID_CONST, 0 }, - { "__decltype", RID_DECLTYPE, D_CXXONLY }, - { "__extension__", RID_EXTENSION, 0 }, - { "__func__", RID_C99_FUNCTION_NAME, 0 }, - { "__has_nothrow_assign", RID_HAS_NOTHROW_ASSIGN, D_CXXONLY }, - { "__has_nothrow_constructor", RID_HAS_NOTHROW_CONSTRUCTOR, D_CXXONLY }, - { "__has_nothrow_copy", RID_HAS_NOTHROW_COPY, D_CXXONLY }, - { "__has_trivial_assign", RID_HAS_TRIVIAL_ASSIGN, D_CXXONLY }, - { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY }, - { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY }, - { "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY }, - { "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY }, - { "__int128", RID_INT128, 0 }, - { "__is_abstract", RID_IS_ABSTRACT, D_CXXONLY }, - { "__is_base_of", RID_IS_BASE_OF, D_CXXONLY }, - { "__is_class", RID_IS_CLASS, D_CXXONLY }, - { "__is_convertible_to", RID_IS_CONVERTIBLE_TO, D_CXXONLY }, - { "__is_empty", RID_IS_EMPTY, D_CXXONLY }, - { "__is_enum", RID_IS_ENUM, D_CXXONLY }, - { "__is_pod", RID_IS_POD, D_CXXONLY }, - { "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY }, - { "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY }, - { "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY }, - { "__is_union", RID_IS_UNION, D_CXXONLY }, - { "__imag", RID_IMAGPART, 0 }, - { "__imag__", RID_IMAGPART, 0 }, - { "__inline", RID_INLINE, 0 }, - { "__inline__", RID_INLINE, 0 }, - { "__label__", RID_LABEL, 0 }, - { "__null", RID_NULL, 0 }, - { "__real", RID_REALPART, 0 }, - { "__real__", RID_REALPART, 0 }, - { "__restrict", RID_RESTRICT, 0 }, - { "__restrict__", RID_RESTRICT, 0 }, - { "__signed", RID_SIGNED, 0 }, - { "__signed__", RID_SIGNED, 0 }, - { "__thread", RID_THREAD, 0 }, - { "__typeof", RID_TYPEOF, 0 }, - { "__typeof__", RID_TYPEOF, 0 }, - { "__volatile", RID_VOLATILE, 0 }, - { "__volatile__", RID_VOLATILE, 0 }, - { "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX0X | D_CXXWARN }, - { "asm", RID_ASM, D_ASM }, - { "auto", RID_AUTO, 0 }, - { "bool", RID_BOOL, D_CXXONLY | D_CXXWARN }, - { "break", RID_BREAK, 0 }, - { "case", RID_CASE, 0 }, - { "catch", RID_CATCH, D_CXX_OBJC | D_CXXWARN }, - { "char", RID_CHAR, 0 }, - { "char16_t", RID_CHAR16, D_CXXONLY | D_CXX0X | D_CXXWARN }, - { "char32_t", RID_CHAR32, D_CXXONLY | D_CXX0X | D_CXXWARN }, - { "class", RID_CLASS, D_CXX_OBJC | D_CXXWARN }, - { "const", RID_CONST, 0 }, - { "constexpr", RID_CONSTEXPR, D_CXXONLY | D_CXX0X | D_CXXWARN }, - { "const_cast", RID_CONSTCAST, D_CXXONLY | D_CXXWARN }, - { "continue", RID_CONTINUE, 0 }, - { "decltype", RID_DECLTYPE, D_CXXONLY | D_CXX0X | D_CXXWARN }, - { "default", RID_DEFAULT, 0 }, - { "delete", RID_DELETE, D_CXXONLY | D_CXXWARN }, - { "do", RID_DO, 0 }, - { "double", RID_DOUBLE, 0 }, - { "dynamic_cast", RID_DYNCAST, D_CXXONLY | D_CXXWARN }, - { "else", RID_ELSE, 0 }, - { "enum", RID_ENUM, 0 }, - { "explicit", RID_EXPLICIT, D_CXXONLY | D_CXXWARN }, - { "export", RID_EXPORT, D_CXXONLY | D_CXXWARN }, - { "extern", RID_EXTERN, 0 }, - { "false", RID_FALSE, D_CXXONLY | D_CXXWARN }, - { "float", RID_FLOAT, 0 }, - { "for", RID_FOR, 0 }, - { "friend", RID_FRIEND, D_CXXONLY | D_CXXWARN }, - { "goto", RID_GOTO, 0 }, - { "if", RID_IF, 0 }, - { "inline", RID_INLINE, D_EXT89 }, - { "int", RID_INT, 0 }, - { "long", RID_LONG, 0 }, - { "mutable", RID_MUTABLE, D_CXXONLY | D_CXXWARN }, - { "namespace", RID_NAMESPACE, D_CXXONLY | D_CXXWARN }, - { "new", RID_NEW, D_CXXONLY | D_CXXWARN }, - { "noexcept", RID_NOEXCEPT, D_CXXONLY | D_CXX0X | D_CXXWARN }, - { "nullptr", RID_NULLPTR, D_CXXONLY | D_CXX0X | D_CXXWARN }, - { "operator", RID_OPERATOR, D_CXXONLY | D_CXXWARN }, - { "private", RID_PRIVATE, D_CXX_OBJC | D_CXXWARN }, - { "protected", RID_PROTECTED, D_CXX_OBJC | D_CXXWARN }, - { "public", RID_PUBLIC, D_CXX_OBJC | D_CXXWARN }, - { "register", RID_REGISTER, 0 }, - { "reinterpret_cast", RID_REINTCAST, D_CXXONLY | D_CXXWARN }, - { "restrict", RID_RESTRICT, D_CONLY | D_C99 }, - { "return", RID_RETURN, 0 }, - { "short", RID_SHORT, 0 }, - { "signed", RID_SIGNED, 0 }, - { "sizeof", RID_SIZEOF, 0 }, - { "static", RID_STATIC, 0 }, - { "static_assert", RID_STATIC_ASSERT, D_CXXONLY | D_CXX0X | D_CXXWARN }, - { "static_cast", RID_STATCAST, D_CXXONLY | D_CXXWARN }, - { "struct", RID_STRUCT, 0 }, - { "switch", RID_SWITCH, 0 }, - { "template", RID_TEMPLATE, D_CXXONLY | D_CXXWARN }, - { "this", RID_THIS, D_CXXONLY | D_CXXWARN }, - { "throw", RID_THROW, D_CXX_OBJC | D_CXXWARN }, - { "true", RID_TRUE, D_CXXONLY | D_CXXWARN }, - { "try", RID_TRY, D_CXX_OBJC | D_CXXWARN }, - { "typedef", RID_TYPEDEF, 0 }, - { "typename", RID_TYPENAME, D_CXXONLY | D_CXXWARN }, - { "typeid", RID_TYPEID, D_CXXONLY | D_CXXWARN }, - { "typeof", RID_TYPEOF, D_ASM | D_EXT }, - { "union", RID_UNION, 0 }, - { "unsigned", RID_UNSIGNED, 0 }, - { "using", RID_USING, D_CXXONLY | D_CXXWARN }, - { "virtual", RID_VIRTUAL, D_CXXONLY | D_CXXWARN }, - { "void", RID_VOID, 0 }, - { "volatile", RID_VOLATILE, 0 }, - { "wchar_t", RID_WCHAR, D_CXXONLY }, - { "while", RID_WHILE, 0 }, - /* These Objective-C keywords are recognized only immediately after - an '@'. */ - { "compatibility_alias", RID_AT_ALIAS, D_OBJC }, - { "defs", RID_AT_DEFS, D_OBJC }, - { "encode", RID_AT_ENCODE, D_OBJC }, - { "end", RID_AT_END, D_OBJC }, - { "implementation", RID_AT_IMPLEMENTATION, D_OBJC }, - { "interface", RID_AT_INTERFACE, D_OBJC }, - { "protocol", RID_AT_PROTOCOL, D_OBJC }, - { "selector", RID_AT_SELECTOR, D_OBJC }, - { "finally", RID_AT_FINALLY, D_OBJC }, - { "synchronized", RID_AT_SYNCHRONIZED, D_OBJC }, - /* These are recognized only in protocol-qualifier context - (see above) */ - { "bycopy", RID_BYCOPY, D_OBJC }, - { "byref", RID_BYREF, D_OBJC }, - { "in", RID_IN, D_OBJC }, - { "inout", RID_INOUT, D_OBJC }, - { "oneway", RID_ONEWAY, D_OBJC }, - { "out", RID_OUT, D_OBJC }, -}; - -const unsigned int num_c_common_reswords = - sizeof c_common_reswords / sizeof (struct c_common_resword); - -/* Table of machine-independent attributes common to all C-like languages. */ -const struct attribute_spec c_common_attribute_table[] = -{ - /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ - { "packed", 0, 0, false, false, false, - handle_packed_attribute }, - { "nocommon", 0, 0, true, false, false, - handle_nocommon_attribute }, - { "common", 0, 0, true, false, false, - handle_common_attribute }, - /* FIXME: logically, noreturn attributes should be listed as - "false, true, true" and apply to function types. But implementing this - would require all the places in the compiler that use TREE_THIS_VOLATILE - on a decl to identify non-returning functions to be located and fixed - to check the function type instead. */ - { "noreturn", 0, 0, true, false, false, - handle_noreturn_attribute }, - { "volatile", 0, 0, true, false, false, - handle_noreturn_attribute }, - { "noinline", 0, 0, true, false, false, - handle_noinline_attribute }, - { "noclone", 0, 0, true, false, false, - handle_noclone_attribute }, - { "always_inline", 0, 0, true, false, false, - handle_always_inline_attribute }, - { "gnu_inline", 0, 0, true, false, false, - handle_gnu_inline_attribute }, - { "artificial", 0, 0, true, false, false, - handle_artificial_attribute }, - { "flatten", 0, 0, true, false, false, - handle_flatten_attribute }, - { "used", 0, 0, true, false, false, - handle_used_attribute }, - { "unused", 0, 0, false, false, false, - handle_unused_attribute }, - { "externally_visible", 0, 0, true, false, false, - handle_externally_visible_attribute }, - /* The same comments as for noreturn attributes apply to const ones. */ - { "const", 0, 0, true, false, false, - handle_const_attribute }, - { "transparent_union", 0, 0, false, false, false, - handle_transparent_union_attribute }, - { "constructor", 0, 1, true, false, false, - handle_constructor_attribute }, - { "destructor", 0, 1, true, false, false, - handle_destructor_attribute }, - { "mode", 1, 1, false, true, false, - handle_mode_attribute }, - { "section", 1, 1, true, false, false, - handle_section_attribute }, - { "aligned", 0, 1, false, false, false, - handle_aligned_attribute }, - { "weak", 0, 0, true, false, false, - handle_weak_attribute }, - { "alias", 1, 1, true, false, false, - handle_alias_attribute }, - { "weakref", 0, 1, true, false, false, - handle_weakref_attribute }, - { "no_instrument_function", 0, 0, true, false, false, - handle_no_instrument_function_attribute }, - { "malloc", 0, 0, true, false, false, - handle_malloc_attribute }, - { "returns_twice", 0, 0, true, false, false, - handle_returns_twice_attribute }, - { "no_stack_limit", 0, 0, true, false, false, - handle_no_limit_stack_attribute }, - { "pure", 0, 0, true, false, false, - handle_pure_attribute }, - /* For internal use (marking of builtins) only. The name contains space - to prevent its usage in source code. */ - { "no vops", 0, 0, true, false, false, - handle_novops_attribute }, - { "deprecated", 0, 1, false, false, false, - handle_deprecated_attribute }, - { "vector_size", 1, 1, false, true, false, - handle_vector_size_attribute }, - { "visibility", 1, 1, false, false, false, - handle_visibility_attribute }, - { "tls_model", 1, 1, true, false, false, - handle_tls_model_attribute }, - { "nonnull", 0, -1, false, true, true, - handle_nonnull_attribute }, - { "nothrow", 0, 0, true, false, false, - handle_nothrow_attribute }, - { "may_alias", 0, 0, false, true, false, NULL }, - { "cleanup", 1, 1, true, false, false, - handle_cleanup_attribute }, - { "warn_unused_result", 0, 0, false, true, true, - handle_warn_unused_result_attribute }, - { "sentinel", 0, 1, false, true, true, - handle_sentinel_attribute }, - /* For internal use (marking of builtins) only. The name contains space - to prevent its usage in source code. */ - { "type generic", 0, 0, false, true, true, - handle_type_generic_attribute }, - { "alloc_size", 1, 2, false, true, true, - handle_alloc_size_attribute }, - { "cold", 0, 0, true, false, false, - handle_cold_attribute }, - { "hot", 0, 0, true, false, false, - handle_hot_attribute }, - { "warning", 1, 1, true, false, false, - handle_error_attribute }, - { "error", 1, 1, true, false, false, - handle_error_attribute }, - { "target", 1, -1, true, false, false, - handle_target_attribute }, - { "optimize", 1, -1, true, false, false, - handle_optimize_attribute }, - /* For internal use (marking of builtins and runtime functions) only. - The name contains space to prevent its usage in source code. */ - { "fn spec", 1, 1, false, true, true, - handle_fnspec_attribute }, - { NULL, 0, 0, false, false, false, NULL } -}; - -/* Give the specifications for the format attributes, used by C and all - descendants. */ - -const struct attribute_spec c_common_format_attribute_table[] = -{ - /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ - { "format", 3, 3, false, true, true, - handle_format_attribute }, - { "format_arg", 1, 1, false, true, true, - handle_format_arg_attribute }, - { NULL, 0, 0, false, false, false, NULL } -}; - -/* Return identifier for address space AS. */ - -const char * -c_addr_space_name (addr_space_t as) -{ - int rid = RID_FIRST_ADDR_SPACE + as; - gcc_assert (ridpointers [rid]); - return IDENTIFIER_POINTER (ridpointers [rid]); -} - -/* Push current bindings for the function name VAR_DECLS. */ - -void -start_fname_decls (void) -{ - unsigned ix; - tree saved = NULL_TREE; - - for (ix = 0; fname_vars[ix].decl; ix++) - { - tree decl = *fname_vars[ix].decl; - - if (decl) - { - saved = tree_cons (decl, build_int_cst (NULL_TREE, ix), saved); - *fname_vars[ix].decl = NULL_TREE; - } - } - if (saved || saved_function_name_decls) - /* Normally they'll have been NULL, so only push if we've got a - stack, or they are non-NULL. */ - saved_function_name_decls = tree_cons (saved, NULL_TREE, - saved_function_name_decls); -} - -/* Finish up the current bindings, adding them into the current function's - statement tree. This must be done _before_ finish_stmt_tree is called. - If there is no current function, we must be at file scope and no statements - are involved. Pop the previous bindings. */ - -void -finish_fname_decls (void) -{ - unsigned ix; - tree stmts = NULL_TREE; - tree stack = saved_function_name_decls; - - for (; stack && TREE_VALUE (stack); stack = TREE_CHAIN (stack)) - append_to_statement_list (TREE_VALUE (stack), &stmts); - - if (stmts) - { - tree *bodyp = &DECL_SAVED_TREE (current_function_decl); - - if (TREE_CODE (*bodyp) == BIND_EXPR) - bodyp = &BIND_EXPR_BODY (*bodyp); - - append_to_statement_list_force (*bodyp, &stmts); - *bodyp = stmts; - } - - for (ix = 0; fname_vars[ix].decl; ix++) - *fname_vars[ix].decl = NULL_TREE; - - if (stack) - { - /* We had saved values, restore them. */ - tree saved; - - for (saved = TREE_PURPOSE (stack); saved; saved = TREE_CHAIN (saved)) - { - tree decl = TREE_PURPOSE (saved); - unsigned ix = TREE_INT_CST_LOW (TREE_VALUE (saved)); - - *fname_vars[ix].decl = decl; - } - stack = TREE_CHAIN (stack); - } - saved_function_name_decls = stack; -} - -/* Return the text name of the current function, suitably prettified - by PRETTY_P. Return string must be freed by caller. */ - -const char * -fname_as_string (int pretty_p) -{ - const char *name = "top level"; - char *namep; - int vrb = 2, len; - cpp_string cstr = { 0, 0 }, strname; - - if (!pretty_p) - { - name = ""; - vrb = 0; - } - - if (current_function_decl) - name = lang_hooks.decl_printable_name (current_function_decl, vrb); - - len = strlen (name) + 3; /* Two for '"'s. One for NULL. */ - - namep = XNEWVEC (char, len); - snprintf (namep, len, "\"%s\"", name); - strname.text = (unsigned char *) namep; - strname.len = len - 1; - - if (cpp_interpret_string (parse_in, &strname, 1, &cstr, CPP_STRING)) - { - XDELETEVEC (namep); - return (const char *) cstr.text; - } - - return namep; -} - -/* Return the VAR_DECL for a const char array naming the current - function. If the VAR_DECL has not yet been created, create it - now. RID indicates how it should be formatted and IDENTIFIER_NODE - ID is its name (unfortunately C and C++ hold the RID values of - keywords in different places, so we can't derive RID from ID in - this language independent code. LOC is the location of the - function. */ - -tree -fname_decl (location_t loc, unsigned int rid, tree id) -{ - unsigned ix; - tree decl = NULL_TREE; - - for (ix = 0; fname_vars[ix].decl; ix++) - if (fname_vars[ix].rid == rid) - break; - - decl = *fname_vars[ix].decl; - if (!decl) - { - /* If a tree is built here, it would normally have the lineno of - the current statement. Later this tree will be moved to the - beginning of the function and this line number will be wrong. - To avoid this problem set the lineno to 0 here; that prevents - it from appearing in the RTL. */ - tree stmts; - location_t saved_location = input_location; - input_location = UNKNOWN_LOCATION; - - stmts = push_stmt_list (); - decl = (*make_fname_decl) (loc, id, fname_vars[ix].pretty); - stmts = pop_stmt_list (stmts); - if (!IS_EMPTY_STMT (stmts)) - saved_function_name_decls - = tree_cons (decl, stmts, saved_function_name_decls); - *fname_vars[ix].decl = decl; - input_location = saved_location; - } - if (!ix && !current_function_decl) - pedwarn (loc, 0, "%qD is not defined outside of function scope", decl); - - return decl; -} - -/* Given a STRING_CST, give it a suitable array-of-chars data type. */ - -tree -fix_string_type (tree value) -{ - int length = TREE_STRING_LENGTH (value); - int nchars; - tree e_type, i_type, a_type; - - /* Compute the number of elements, for the array type. */ - if (TREE_TYPE (value) == char_array_type_node || !TREE_TYPE (value)) - { - nchars = length; - e_type = char_type_node; - } - else if (TREE_TYPE (value) == char16_array_type_node) - { - nchars = length / (TYPE_PRECISION (char16_type_node) / BITS_PER_UNIT); - e_type = char16_type_node; - } - else if (TREE_TYPE (value) == char32_array_type_node) - { - nchars = length / (TYPE_PRECISION (char32_type_node) / BITS_PER_UNIT); - e_type = char32_type_node; - } - else - { - nchars = length / (TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT); - e_type = wchar_type_node; - } - - /* C89 2.2.4.1, C99 5.2.4.1 (Translation limits). The analogous - limit in C++98 Annex B is very large (65536) and is not normative, - so we do not diagnose it (warn_overlength_strings is forced off - in c_common_post_options). */ - if (warn_overlength_strings) - { - const int nchars_max = flag_isoc99 ? 4095 : 509; - const int relevant_std = flag_isoc99 ? 99 : 90; - if (nchars - 1 > nchars_max) - /* Translators: The %d after 'ISO C' will be 90 or 99. Do not - separate the %d from the 'C'. 'ISO' should not be - translated, but it may be moved after 'C%d' in languages - where modifiers follow nouns. */ - pedwarn (input_location, OPT_Woverlength_strings, - "string length %qd is greater than the length %qd " - "ISO C%d compilers are required to support", - nchars - 1, nchars_max, relevant_std); - } - - /* Create the array type for the string constant. The ISO C++ - standard says that a string literal has type `const char[N]' or - `const wchar_t[N]'. We use the same logic when invoked as a C - front-end with -Wwrite-strings. - ??? We should change the type of an expression depending on the - state of a warning flag. We should just be warning -- see how - this is handled in the C++ front-end for the deprecated implicit - conversion from string literals to `char*' or `wchar_t*'. - - The C++ front end relies on TYPE_MAIN_VARIANT of a cv-qualified - array type being the unqualified version of that type. - Therefore, if we are constructing an array of const char, we must - construct the matching unqualified array type first. The C front - end does not require this, but it does no harm, so we do it - unconditionally. */ - i_type = build_index_type (build_int_cst (NULL_TREE, nchars - 1)); - a_type = build_array_type (e_type, i_type); - if (c_dialect_cxx() || warn_write_strings) - a_type = c_build_qualified_type (a_type, TYPE_QUAL_CONST); - - TREE_TYPE (value) = a_type; - TREE_CONSTANT (value) = 1; - TREE_READONLY (value) = 1; - TREE_STATIC (value) = 1; - return value; -} - -/* 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. */ - -tree -c_fully_fold (tree expr, bool in_init, bool *maybe_const) -{ - tree ret; - tree eptype = NULL_TREE; - bool dummy = true; - bool maybe_const_itself = true; - location_t loc = EXPR_LOCATION (expr); - - /* This function is not relevant to C++ because C++ folds while - parsing, and may need changes to be correct for C++ when C++ - stops folding while parsing. */ - if (c_dialect_cxx ()) - gcc_unreachable (); - - 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); - 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). */ - -static tree -c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, - bool *maybe_const_itself) -{ - 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 = TREE_NO_WARNING (expr); - int unused_p; - - /* This function is not relevant to C++ because C++ folds while - parsing, and may need changes to be correct for C++ when C++ - stops folding while parsing. */ - if (c_dialect_cxx ()) - gcc_unreachable (); - - /* Constants, declarations, statements, errors, SAVE_EXPRs 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 - || code == SAVE_EXPR) - return 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; - 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); - 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); - } - 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); - STRIP_TYPE_NOPS (op0); - op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, - maybe_const_itself); - STRIP_TYPE_NOPS (op1); - op1 = decl_constant_value_for_optimization (op1); - 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); - } - ret = fold (ret); - goto out; - - case COMPOUND_EXPR: - case MODIFY_EXPR: - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - case PLUS_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case POINTER_PLUS_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: - /* 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); - STRIP_TYPE_NOPS (op0); - if (code != MODIFY_EXPR - && code != PREDECREMENT_EXPR - && code != PREINCREMENT_EXPR - && code != POSTDECREMENT_EXPR - && code != POSTINCREMENT_EXPR) - op0 = decl_constant_value_for_optimization (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); - STRIP_TYPE_NOPS (op1); - op1 = decl_constant_value_for_optimization (op1); - 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) - && !TREE_OVERFLOW_P (op1)) - overflow_warning (EXPR_LOCATION (expr), ret); - goto out; - - case INDIRECT_REF: - case FIX_TRUNC_EXPR: - case FLOAT_EXPR: - CASE_CONVERT: - case NON_LVALUE_EXPR: - case NEGATE_EXPR: - case BIT_NOT_EXPR: - case TRUTH_NOT_EXPR: - case ADDR_EXPR: - case CONJ_EXPR: - case REALPART_EXPR: - case IMAGPART_EXPR: - /* Unary operations. */ - orig_op0 = op0 = TREE_OPERAND (expr, 0); - op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, - maybe_const_itself); - STRIP_TYPE_NOPS (op0); - if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR) - op0 = decl_constant_value_for_optimization (op0); - 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 - && TREE_CODE (ret) == INDIRECT_REF) - { - 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); - 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); - STRIP_TYPE_NOPS (op0); - - unused_p = (op0 == (code == TRUTH_ANDIF_EXPR - ? truthvalue_false_node - : truthvalue_true_node)); - c_inhibit_evaluation_warnings += unused_p; - op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self); - STRIP_TYPE_NOPS (op1); - c_inhibit_evaluation_warnings -= unused_p; - - 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); - - STRIP_TYPE_NOPS (op0); - c_inhibit_evaluation_warnings += (op0 == truthvalue_false_node); - op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self); - STRIP_TYPE_NOPS (op1); - c_inhibit_evaluation_warnings -= (op0 == truthvalue_false_node); - - c_inhibit_evaluation_warnings += (op0 == truthvalue_true_node); - op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self); - STRIP_TYPE_NOPS (op2); - c_inhibit_evaluation_warnings -= (op0 == truthvalue_true_node); - - 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 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 (); - - 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 |= TREE_NO_WARNING (ret); - STRIP_TYPE_NOPS (ret); - if (nowarning && !TREE_NO_WARNING (ret)) - { - if (!CAN_HAVE_LOCATION_P (ret)) - ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret); - TREE_NO_WARNING (ret) = 1; - } - if (ret != expr) - protected_set_expr_location (ret, loc); - return ret; -} - -/* If not optimizing, EXP is not a VAR_DECL, or EXP has array type, - return EXP. Otherwise, return either EXP or its known constant - value (if it has one), but return EXP if EXP has mode BLKmode. ??? - Is the BLKmode test appropriate? */ - -tree -decl_constant_value_for_optimization (tree exp) -{ - tree ret; - - /* This function is only used by C, for c_fully_fold and other - optimization, and may not be correct for C++. */ - if (c_dialect_cxx ()) - gcc_unreachable (); - - if (!optimize - || TREE_CODE (exp) != VAR_DECL - || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE - || DECL_MODE (exp) == BLKmode) - return exp; - - ret = decl_constant_value (exp); - /* 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 != exp && TREE_STATIC (exp)) - ret = unshare_expr (ret); - return ret; -} - -/* Print a warning if a constant expression had overflow in folding. - Invoke this function on every expression that the language - requires to be a constant expression. - Note the ANSI C standard says it is erroneous for a - constant expression to overflow. */ - -void -constant_expression_warning (tree value) -{ - if (warn_overflow && pedantic - && (TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST - || TREE_CODE (value) == FIXED_CST - || TREE_CODE (value) == VECTOR_CST - || TREE_CODE (value) == COMPLEX_CST) - && TREE_OVERFLOW (value)) - pedwarn (input_location, OPT_Woverflow, "overflow in constant expression"); -} - -/* The same as above but print an unconditional error. */ -void -constant_expression_error (tree value) -{ - if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST - || TREE_CODE (value) == FIXED_CST - || TREE_CODE (value) == VECTOR_CST - || TREE_CODE (value) == COMPLEX_CST) - && TREE_OVERFLOW (value)) - error ("overflow in constant expression"); -} - -/* Print a warning if an expression had overflow in folding and its - operands hadn't. - - Invoke this function on every expression that - (1) appears in the source code, and - (2) is a constant expression that overflowed, and - (3) is not already checked by convert_and_check; - however, do not invoke this function on operands of explicit casts - or when the expression is the result of an operator and any operand - already overflowed. */ - -void -overflow_warning (location_t loc, tree value) -{ - if (c_inhibit_evaluation_warnings != 0) - return; - - switch (TREE_CODE (value)) - { - case INTEGER_CST: - warning_at (loc, OPT_Woverflow, "integer overflow in expression"); - break; - - case REAL_CST: - warning_at (loc, OPT_Woverflow, - "floating point overflow in expression"); - break; - - case FIXED_CST: - warning_at (loc, OPT_Woverflow, "fixed-point overflow in expression"); - break; - - case VECTOR_CST: - warning_at (loc, OPT_Woverflow, "vector overflow in expression"); - break; - - case COMPLEX_CST: - if (TREE_CODE (TREE_REALPART (value)) == INTEGER_CST) - warning_at (loc, OPT_Woverflow, - "complex integer overflow in expression"); - else if (TREE_CODE (TREE_REALPART (value)) == REAL_CST) - warning_at (loc, OPT_Woverflow, - "complex floating point overflow in expression"); - break; - - default: - break; - } -} - -/* Warn about uses of logical || / && operator in a context where it - is likely that the bitwise equivalent was intended by the - programmer. We have seen an expression in which CODE is a binary - operator used to combine expressions OP_LEFT and OP_RIGHT, which before folding - had CODE_LEFT and CODE_RIGHT, into an expression of type TYPE. */ -void -warn_logical_operator (location_t location, enum tree_code code, tree type, - enum tree_code code_left, tree op_left, - enum tree_code ARG_UNUSED (code_right), tree op_right) -{ - int or_op = (code == TRUTH_ORIF_EXPR || code == TRUTH_OR_EXPR); - int in0_p, in1_p, in_p; - tree low0, low1, low, high0, high1, high, lhs, rhs, tem; - bool strict_overflow_p = false; - - if (code != TRUTH_ANDIF_EXPR - && code != TRUTH_AND_EXPR - && code != TRUTH_ORIF_EXPR - && code != TRUTH_OR_EXPR) - return; - - /* Warn if &&/|| are being used in a context where it is - likely that the bitwise equivalent was intended by the - programmer. That is, an expression such as op && MASK - where op should not be any boolean expression, nor a - constant, and mask seems to be a non-boolean integer constant. */ - if (!truth_value_p (code_left) - && INTEGRAL_TYPE_P (TREE_TYPE (op_left)) - && !CONSTANT_CLASS_P (op_left) - && !TREE_NO_WARNING (op_left) - && TREE_CODE (op_right) == INTEGER_CST - && !integer_zerop (op_right) - && !integer_onep (op_right)) - { - if (or_op) - warning_at (location, OPT_Wlogical_op, "logical %" - " applied to non-boolean constant"); - else - warning_at (location, OPT_Wlogical_op, "logical %" - " applied to non-boolean constant"); - TREE_NO_WARNING (op_left) = true; - return; - } - - /* We do not warn for constants because they are typical of macro - expansions that test for features. */ - if (CONSTANT_CLASS_P (op_left) || CONSTANT_CLASS_P (op_right)) - return; - - /* This warning only makes sense with logical operands. */ - if (!(truth_value_p (TREE_CODE (op_left)) - || INTEGRAL_TYPE_P (TREE_TYPE (op_left))) - || !(truth_value_p (TREE_CODE (op_right)) - || INTEGRAL_TYPE_P (TREE_TYPE (op_right)))) - return; - - lhs = make_range (op_left, &in0_p, &low0, &high0, &strict_overflow_p); - rhs = make_range (op_right, &in1_p, &low1, &high1, &strict_overflow_p); - - if (lhs && TREE_CODE (lhs) == C_MAYBE_CONST_EXPR) - lhs = C_MAYBE_CONST_EXPR_EXPR (lhs); - - if (rhs && TREE_CODE (rhs) == C_MAYBE_CONST_EXPR) - rhs = C_MAYBE_CONST_EXPR_EXPR (rhs); - - /* If this is an OR operation, invert both sides; we will invert - again at the end. */ - if (or_op) - in0_p = !in0_p, in1_p = !in1_p; - - /* If both expressions are the same, if we can merge the ranges, and we - can build the range test, return it or it inverted. */ - if (lhs && rhs && operand_equal_p (lhs, rhs, 0) - && merge_ranges (&in_p, &low, &high, in0_p, low0, high0, - in1_p, low1, high1) - && 0 != (tem = build_range_check (UNKNOWN_LOCATION, - type, lhs, in_p, low, high))) - { - if (TREE_CODE (tem) != INTEGER_CST) - return; - - if (or_op) - warning_at (location, OPT_Wlogical_op, - "logical % " - "of collectively exhaustive tests is always true"); - else - warning_at (location, OPT_Wlogical_op, - "logical % " - "of mutually exclusive tests is always false"); - } -} - - -/* Print a warning about casts that might indicate violation - of strict aliasing rules if -Wstrict-aliasing is used and - strict aliasing mode is in effect. OTYPE is the original - TREE_TYPE of EXPR, and TYPE the type we're casting to. */ - -bool -strict_aliasing_warning (tree otype, tree type, tree expr) -{ - /* Strip pointer conversion chains and get to the correct original type. */ - STRIP_NOPS (expr); - otype = TREE_TYPE (expr); - - if (!(flag_strict_aliasing - && POINTER_TYPE_P (type) - && POINTER_TYPE_P (otype) - && !VOID_TYPE_P (TREE_TYPE (type))) - /* If the type we are casting to is a ref-all pointer - dereferencing it is always valid. */ - || TYPE_REF_CAN_ALIAS_ALL (type)) - return false; - - if ((warn_strict_aliasing > 1) && TREE_CODE (expr) == ADDR_EXPR - && (DECL_P (TREE_OPERAND (expr, 0)) - || handled_component_p (TREE_OPERAND (expr, 0)))) - { - /* Casting the address of an object to non void pointer. Warn - if the cast breaks type based aliasing. */ - if (!COMPLETE_TYPE_P (TREE_TYPE (type)) && warn_strict_aliasing == 2) - { - warning (OPT_Wstrict_aliasing, "type-punning to incomplete type " - "might break strict-aliasing rules"); - return true; - } - else - { - /* warn_strict_aliasing >= 3. This includes the default (3). - Only warn if the cast is dereferenced immediately. */ - alias_set_type set1 = - get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0))); - alias_set_type set2 = get_alias_set (TREE_TYPE (type)); - - if (set1 != set2 && set2 != 0 - && (set1 == 0 || !alias_sets_conflict_p (set1, set2))) - { - warning (OPT_Wstrict_aliasing, "dereferencing type-punned " - "pointer will break strict-aliasing rules"); - return true; - } - else if (warn_strict_aliasing == 2 - && !alias_sets_must_conflict_p (set1, set2)) - { - warning (OPT_Wstrict_aliasing, "dereferencing type-punned " - "pointer might break strict-aliasing rules"); - return true; - } - } - } - else - if ((warn_strict_aliasing == 1) && !VOID_TYPE_P (TREE_TYPE (otype))) - { - /* At this level, warn for any conversions, even if an address is - not taken in the same statement. This will likely produce many - false positives, but could be useful to pinpoint problems that - are not revealed at higher levels. */ - alias_set_type set1 = get_alias_set (TREE_TYPE (otype)); - alias_set_type set2 = get_alias_set (TREE_TYPE (type)); - if (!COMPLETE_TYPE_P (type) - || !alias_sets_must_conflict_p (set1, set2)) - { - warning (OPT_Wstrict_aliasing, "dereferencing type-punned " - "pointer might break strict-aliasing rules"); - return true; - } - } - - return false; -} - -/* Warn for unlikely, improbable, or stupid DECL declarations - of `main'. */ - -void -check_main_parameter_types (tree decl) -{ - tree args; - int argct = 0; - - for (args = TYPE_ARG_TYPES (TREE_TYPE (decl)); args; - args = TREE_CHAIN (args)) - { - tree type = args ? TREE_VALUE (args) : 0; - - if (type == void_type_node || type == error_mark_node ) - break; - - ++argct; - switch (argct) - { - case 1: - if (TYPE_MAIN_VARIANT (type) != integer_type_node) - pedwarn (input_location, OPT_Wmain, "first argument of %q+D should be %", - decl); - break; - - case 2: - if (TREE_CODE (type) != POINTER_TYPE - || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE - || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) - != char_type_node)) - pedwarn (input_location, OPT_Wmain, "second argument of %q+D should be %", - decl); - break; - - case 3: - if (TREE_CODE (type) != POINTER_TYPE - || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE - || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) - != char_type_node)) - pedwarn (input_location, OPT_Wmain, "third argument of %q+D should probably be " - "%", decl); - break; - } - } - - /* It is intentional that this message does not mention the third - argument because it's only mentioned in an appendix of the - standard. */ - if (argct > 0 && (argct < 2 || argct > 3)) - pedwarn (input_location, OPT_Wmain, "%q+D takes only zero or two arguments", decl); -} - -/* True if pointers to distinct types T1 and T2 can be converted to - each other without an explicit cast. Only returns true for opaque - vector types. */ -bool -vector_targets_convertible_p (const_tree t1, const_tree t2) -{ - if (TREE_CODE (t1) == VECTOR_TYPE && TREE_CODE (t2) == VECTOR_TYPE - && (TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2)) - && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))) - return true; - - return false; -} - -/* True if vector types T1 and T2 can be converted to each other - without an explicit cast. If EMIT_LAX_NOTE is true, and T1 and T2 - can only be converted with -flax-vector-conversions yet that is not - in effect, emit a note telling the user about that option if such - a note has not previously been emitted. */ -bool -vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note) -{ - static bool emitted_lax_note = false; - bool convertible_lax; - - if ((TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2)) - && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))) - return true; - - convertible_lax = - (tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)) - && (TREE_CODE (TREE_TYPE (t1)) != REAL_TYPE || - TYPE_PRECISION (t1) == TYPE_PRECISION (t2)) - && (INTEGRAL_TYPE_P (TREE_TYPE (t1)) - == INTEGRAL_TYPE_P (TREE_TYPE (t2)))); - - if (!convertible_lax || flag_lax_vector_conversions) - return convertible_lax; - - if (TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2) - && lang_hooks.types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))) - return true; - - if (emit_lax_note && !emitted_lax_note) - { - emitted_lax_note = true; - inform (input_location, "use -flax-vector-conversions to permit " - "conversions between vectors with differing " - "element types or numbers of subparts"); - } - - return false; -} - -/* This is a helper function of build_binary_op. - - For certain operations if both args were extended from the same - smaller type, do the arithmetic in that type and then extend. - - BITWISE 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. -*/ -tree shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise) -{ - int unsigned0, unsigned1; - tree arg0, arg1; - int uns; - tree type; - - /* Cast OP0 and OP1 to RESULT_TYPE. Doing so prevents - excessive narrowing when we call get_narrower below. For - example, suppose that OP0 is of unsigned int extended - from signed char and that RESULT_TYPE is long long int. - If we explicitly cast OP0 to RESULT_TYPE, OP0 would look - like - - (long long int) (unsigned int) signed_char - - which get_narrower would narrow down to - - (unsigned int) signed char - - If we do not cast OP0 first, get_narrower would return - signed_char, which is inconsistent with the case of the - explicit cast. */ - op0 = convert (result_type, op0); - op1 = convert (result_type, op1); - - arg0 = get_narrower (op0, &unsigned0); - arg1 = get_narrower (op1, &unsigned1); - - /* UNS is 1 if the operation to be done is an unsigned one. */ - uns = TYPE_UNSIGNED (result_type); - - /* Handle the case that OP0 (or OP1) does not *contain* a conversion - but it *requires* conversion to FINAL_TYPE. */ - - if ((TYPE_PRECISION (TREE_TYPE (op0)) - == TYPE_PRECISION (TREE_TYPE (arg0))) - && TREE_TYPE (op0) != result_type) - unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0)); - if ((TYPE_PRECISION (TREE_TYPE (op1)) - == TYPE_PRECISION (TREE_TYPE (arg1))) - && TREE_TYPE (op1) != result_type) - unsigned1 = TYPE_UNSIGNED (TREE_TYPE (op1)); - - /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */ - - /* For bitwise operations, signedness of nominal type - does not matter. Consider only how operands were extended. */ - if (bitwise) - uns = unsigned0; - - /* Note that in all three cases below we refrain from optimizing - an unsigned operation on sign-extended args. - That would not be valid. */ - - /* Both args variable: if both extended in same way - from same width, do it in that width. - Do it unsigned if args were zero-extended. */ - if ((TYPE_PRECISION (TREE_TYPE (arg0)) - < TYPE_PRECISION (result_type)) - && (TYPE_PRECISION (TREE_TYPE (arg1)) - == TYPE_PRECISION (TREE_TYPE (arg0))) - && unsigned0 == unsigned1 - && (unsigned0 || !uns)) - return c_common_signed_or_unsigned_type - (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1))); - - else if (TREE_CODE (arg0) == INTEGER_CST - && (unsigned1 || !uns) - && (TYPE_PRECISION (TREE_TYPE (arg1)) - < TYPE_PRECISION (result_type)) - && (type - = c_common_signed_or_unsigned_type (unsigned1, - TREE_TYPE (arg1))) - && !POINTER_TYPE_P (type) - && int_fits_type_p (arg0, type)) - return type; - - else if (TREE_CODE (arg1) == INTEGER_CST - && (unsigned0 || !uns) - && (TYPE_PRECISION (TREE_TYPE (arg0)) - < TYPE_PRECISION (result_type)) - && (type - = c_common_signed_or_unsigned_type (unsigned0, - TREE_TYPE (arg0))) - && !POINTER_TYPE_P (type) - && int_fits_type_p (arg1, type)) - return type; - - return result_type; -} - -/* Warns if the conversion of EXPR to TYPE may alter a value. - This is a helper function for warnings_for_convert_and_check. */ - -static void -conversion_warning (tree type, tree expr) -{ - bool give_warning = false; - - int i; - const int expr_num_operands = TREE_OPERAND_LENGTH (expr); - tree expr_type = TREE_TYPE (expr); - - if (!warn_conversion && !warn_sign_conversion) - return; - - /* If any operand is artificial, then this expression was generated - by the compiler and we do not warn. */ - for (i = 0; i < expr_num_operands; i++) - { - tree op = TREE_OPERAND (expr, i); - if (op && DECL_P (op) && DECL_ARTIFICIAL (op)) - return; - } - - switch (TREE_CODE (expr)) - { - case EQ_EXPR: - case NE_EXPR: - case LE_EXPR: - case GE_EXPR: - case LT_EXPR: - case GT_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - case TRUTH_NOT_EXPR: - /* Conversion from boolean to a signed:1 bit-field (which only - can hold the values 0 and -1) doesn't lose information - but - it does change the value. */ - if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type)) - warning (OPT_Wconversion, - "conversion to %qT from boolean expression", type); - return; - - case REAL_CST: - case INTEGER_CST: - - /* Warn for real constant that is not an exact integer converted - to integer type. */ - if (TREE_CODE (expr_type) == REAL_TYPE - && TREE_CODE (type) == INTEGER_TYPE) - { - if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type))) - give_warning = true; - } - /* Warn for an integer constant that does not fit into integer type. */ - else if (TREE_CODE (expr_type) == INTEGER_TYPE - && TREE_CODE (type) == INTEGER_TYPE - && !int_fits_type_p (expr, type)) - { - if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type) - && tree_int_cst_sgn (expr) < 0) - warning (OPT_Wsign_conversion, - "negative integer implicitly converted to unsigned type"); - else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type)) - warning (OPT_Wsign_conversion, "conversion of unsigned constant " - "value to negative integer"); - else - give_warning = true; - } - else if (TREE_CODE (type) == REAL_TYPE) - { - /* Warn for an integer constant that does not fit into real type. */ - if (TREE_CODE (expr_type) == INTEGER_TYPE) - { - REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr); - if (!exact_real_truncate (TYPE_MODE (type), &a)) - give_warning = true; - } - /* Warn for a real constant that does not fit into a smaller - real type. */ - else if (TREE_CODE (expr_type) == REAL_TYPE - && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) - { - REAL_VALUE_TYPE a = TREE_REAL_CST (expr); - if (!exact_real_truncate (TYPE_MODE (type), &a)) - give_warning = true; - } - } - - if (give_warning) - warning (OPT_Wconversion, - "conversion to %qT alters %qT constant value", - type, expr_type); - - return; - - case COND_EXPR: - { - /* In case of COND_EXPR, if both operands are constants or - COND_EXPR, then we do not care about the type of COND_EXPR, - only about the conversion of each operand. */ - tree op1 = TREE_OPERAND (expr, 1); - tree op2 = TREE_OPERAND (expr, 2); - - if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST - || TREE_CODE (op1) == COND_EXPR) - && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST - || TREE_CODE (op2) == COND_EXPR)) - { - conversion_warning (type, op1); - conversion_warning (type, op2); - return; - } - /* Fall through. */ - } - - default: /* 'expr' is not a constant. */ - - /* Warn for real types converted to integer types. */ - if (TREE_CODE (expr_type) == REAL_TYPE - && TREE_CODE (type) == INTEGER_TYPE) - give_warning = true; - - else if (TREE_CODE (expr_type) == INTEGER_TYPE - && TREE_CODE (type) == INTEGER_TYPE) - { - /* Don't warn about unsigned char y = 0xff, x = (int) y; */ - expr = get_unwidened (expr, 0); - expr_type = TREE_TYPE (expr); - - /* Don't warn for short y; short x = ((int)y & 0xff); */ - if (TREE_CODE (expr) == BIT_AND_EXPR - || TREE_CODE (expr) == BIT_IOR_EXPR - || TREE_CODE (expr) == BIT_XOR_EXPR) - { - /* If both args were extended from a shortest type, - use that type if that is safe. */ - expr_type = shorten_binary_op (expr_type, - TREE_OPERAND (expr, 0), - TREE_OPERAND (expr, 1), - /* bitwise */1); - - if (TREE_CODE (expr) == BIT_AND_EXPR) - { - tree op0 = TREE_OPERAND (expr, 0); - tree op1 = TREE_OPERAND (expr, 1); - bool unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0)); - bool unsigned1 = TYPE_UNSIGNED (TREE_TYPE (op1)); - - /* If one of the operands is a non-negative constant - that fits in the target type, then the type of the - other operand does not matter. */ - if ((TREE_CODE (op0) == INTEGER_CST - && int_fits_type_p (op0, c_common_signed_type (type)) - && int_fits_type_p (op0, c_common_unsigned_type (type))) - || (TREE_CODE (op1) == INTEGER_CST - && int_fits_type_p (op1, c_common_signed_type (type)) - && int_fits_type_p (op1, - c_common_unsigned_type (type)))) - return; - /* If constant is unsigned and fits in the target - type, then the result will also fit. */ - else if ((TREE_CODE (op0) == INTEGER_CST - && unsigned0 - && int_fits_type_p (op0, type)) - || (TREE_CODE (op1) == INTEGER_CST - && unsigned1 - && int_fits_type_p (op1, type))) - return; - } - } - /* Warn for integer types converted to smaller integer types. */ - if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) - give_warning = true; - - /* When they are the same width but different signedness, - then the value may change. */ - else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type) - && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type)) - /* Even when converted to a bigger type, if the type is - unsigned but expr is signed, then negative values - will be changed. */ - || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type))) - warning (OPT_Wsign_conversion, "conversion to %qT from %qT " - "may change the sign of the result", - type, expr_type); - } - - /* Warn for integer types converted to real types if and only if - all the range of values of the integer type cannot be - represented by the real type. */ - else if (TREE_CODE (expr_type) == INTEGER_TYPE - && TREE_CODE (type) == REAL_TYPE) - { - tree type_low_bound, type_high_bound; - REAL_VALUE_TYPE real_low_bound, real_high_bound; - - /* Don't warn about char y = 0xff; float x = (int) y; */ - expr = get_unwidened (expr, 0); - expr_type = TREE_TYPE (expr); - - type_low_bound = TYPE_MIN_VALUE (expr_type); - type_high_bound = TYPE_MAX_VALUE (expr_type); - real_low_bound = real_value_from_int_cst (0, type_low_bound); - real_high_bound = real_value_from_int_cst (0, type_high_bound); - - if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound) - || !exact_real_truncate (TYPE_MODE (type), &real_high_bound)) - give_warning = true; - } - - /* Warn for real types converted to smaller real types. */ - else if (TREE_CODE (expr_type) == REAL_TYPE - && TREE_CODE (type) == REAL_TYPE - && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) - give_warning = true; - - - if (give_warning) - warning (OPT_Wconversion, - "conversion to %qT from %qT may alter its value", - type, expr_type); - } -} - -/* Produce warnings after a conversion. RESULT is the result of - converting EXPR to TYPE. This is a helper function for - convert_and_check and cp_convert_and_check. */ - -void -warnings_for_convert_and_check (tree type, tree expr, tree result) -{ - if (TREE_CODE (expr) == INTEGER_CST - && (TREE_CODE (type) == INTEGER_TYPE - || TREE_CODE (type) == ENUMERAL_TYPE) - && !int_fits_type_p (expr, type)) - { - /* Do not diagnose overflow in a constant expression merely - because a conversion overflowed. */ - if (TREE_OVERFLOW (result)) - TREE_OVERFLOW (result) = TREE_OVERFLOW (expr); - - if (TYPE_UNSIGNED (type)) - { - /* This detects cases like converting -129 or 256 to - unsigned char. */ - if (!int_fits_type_p (expr, c_common_signed_type (type))) - warning (OPT_Woverflow, - "large integer implicitly truncated to unsigned type"); - else - conversion_warning (type, expr); - } - else if (!int_fits_type_p (expr, c_common_unsigned_type (type))) - warning (OPT_Woverflow, - "overflow in implicit constant conversion"); - /* No warning for converting 0x80000000 to int. */ - else if (pedantic - && (TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE - || TYPE_PRECISION (TREE_TYPE (expr)) - != TYPE_PRECISION (type))) - warning (OPT_Woverflow, - "overflow in implicit constant conversion"); - - else - conversion_warning (type, expr); - } - else if ((TREE_CODE (result) == INTEGER_CST - || TREE_CODE (result) == FIXED_CST) && TREE_OVERFLOW (result)) - warning (OPT_Woverflow, - "overflow in implicit constant conversion"); - else - conversion_warning (type, expr); -} - - -/* Convert EXPR to TYPE, warning about conversion problems with constants. - Invoke this function on every expression that is converted implicitly, - i.e. because of language rules and not because of an explicit cast. */ - -tree -convert_and_check (tree type, tree expr) -{ - tree result; - tree expr_for_warning; - - /* Convert from a value with possible excess precision rather than - via the semantic type, but do not warn about values not fitting - exactly in the semantic type. */ - if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) - { - tree orig_type = TREE_TYPE (expr); - expr = TREE_OPERAND (expr, 0); - expr_for_warning = convert (orig_type, expr); - if (orig_type == type) - return expr_for_warning; - } - else - expr_for_warning = expr; - - if (TREE_TYPE (expr) == type) - return expr; - - result = convert (type, expr); - - if (c_inhibit_evaluation_warnings == 0 - && !TREE_OVERFLOW_P (expr) - && result != error_mark_node) - warnings_for_convert_and_check (type, expr_for_warning, result); - - return result; -} - -/* A node in a list that describes references to variables (EXPR), which are - either read accesses if WRITER is zero, or write accesses, in which case - WRITER is the parent of EXPR. */ -struct tlist -{ - struct tlist *next; - tree expr, writer; -}; - -/* Used to implement a cache the results of a call to verify_tree. We only - use this for SAVE_EXPRs. */ -struct tlist_cache -{ - struct tlist_cache *next; - struct tlist *cache_before_sp; - struct tlist *cache_after_sp; - tree expr; -}; - -/* Obstack to use when allocating tlist structures, and corresponding - firstobj. */ -static struct obstack tlist_obstack; -static char *tlist_firstobj = 0; - -/* Keep track of the identifiers we've warned about, so we can avoid duplicate - warnings. */ -static struct tlist *warned_ids; -/* SAVE_EXPRs need special treatment. We process them only once and then - cache the results. */ -static struct tlist_cache *save_expr_cache; - -static void add_tlist (struct tlist **, struct tlist *, tree, int); -static void merge_tlist (struct tlist **, struct tlist *, int); -static void verify_tree (tree, struct tlist **, struct tlist **, tree); -static int warning_candidate_p (tree); -static bool candidate_equal_p (const_tree, const_tree); -static void warn_for_collisions (struct tlist *); -static void warn_for_collisions_1 (tree, tree, struct tlist *, int); -static struct tlist *new_tlist (struct tlist *, tree, tree); - -/* Create a new struct tlist and fill in its fields. */ -static struct tlist * -new_tlist (struct tlist *next, tree t, tree writer) -{ - struct tlist *l; - l = XOBNEW (&tlist_obstack, struct tlist); - l->next = next; - l->expr = t; - l->writer = writer; - return l; -} - -/* Add duplicates of the nodes found in ADD to the list *TO. If EXCLUDE_WRITER - is nonnull, we ignore any node we find which has a writer equal to it. */ - -static void -add_tlist (struct tlist **to, struct tlist *add, tree exclude_writer, int copy) -{ - while (add) - { - struct tlist *next = add->next; - if (!copy) - add->next = *to; - if (!exclude_writer || !candidate_equal_p (add->writer, exclude_writer)) - *to = copy ? new_tlist (*to, add->expr, add->writer) : add; - add = next; - } -} - -/* Merge the nodes of ADD into TO. This merging process is done so that for - each variable that already exists in TO, no new node is added; however if - there is a write access recorded in ADD, and an occurrence on TO is only - a read access, then the occurrence in TO will be modified to record the - write. */ - -static void -merge_tlist (struct tlist **to, struct tlist *add, int copy) -{ - struct tlist **end = to; - - while (*end) - end = &(*end)->next; - - while (add) - { - int found = 0; - struct tlist *tmp2; - struct tlist *next = add->next; - - for (tmp2 = *to; tmp2; tmp2 = tmp2->next) - if (candidate_equal_p (tmp2->expr, add->expr)) - { - found = 1; - if (!tmp2->writer) - tmp2->writer = add->writer; - } - if (!found) - { - *end = copy ? add : new_tlist (NULL, add->expr, add->writer); - end = &(*end)->next; - *end = 0; - } - add = next; - } -} - -/* WRITTEN is a variable, WRITER is its parent. Warn if any of the variable - references in list LIST conflict with it, excluding reads if ONLY writers - is nonzero. */ - -static void -warn_for_collisions_1 (tree written, tree writer, struct tlist *list, - int only_writes) -{ - struct tlist *tmp; - - /* Avoid duplicate warnings. */ - for (tmp = warned_ids; tmp; tmp = tmp->next) - if (candidate_equal_p (tmp->expr, written)) - return; - - while (list) - { - if (candidate_equal_p (list->expr, written) - && !candidate_equal_p (list->writer, writer) - && (!only_writes || list->writer)) - { - warned_ids = new_tlist (warned_ids, written, NULL_TREE); - warning_at (EXPR_HAS_LOCATION (writer) - ? EXPR_LOCATION (writer) : input_location, - OPT_Wsequence_point, "operation on %qE may be undefined", - list->expr); - } - list = list->next; - } -} - -/* Given a list LIST of references to variables, find whether any of these - can cause conflicts due to missing sequence points. */ - -static void -warn_for_collisions (struct tlist *list) -{ - struct tlist *tmp; - - for (tmp = list; tmp; tmp = tmp->next) - { - if (tmp->writer) - warn_for_collisions_1 (tmp->expr, tmp->writer, list, 0); - } -} - -/* Return nonzero if X is a tree that can be verified by the sequence point - warnings. */ -static int -warning_candidate_p (tree x) -{ - /* !VOID_TYPE_P (TREE_TYPE (x)) is workaround for cp/tree.c - (lvalue_p) crash on TRY/CATCH. */ - return !(DECL_P (x) && DECL_ARTIFICIAL (x)) - && TREE_TYPE (x) && !VOID_TYPE_P (TREE_TYPE (x)) && lvalue_p (x); -} - -/* Return nonzero if X and Y appear to be the same candidate (or NULL) */ -static bool -candidate_equal_p (const_tree x, const_tree y) -{ - return (x == y) || (x && y && operand_equal_p (x, y, 0)); -} - -/* Walk the tree X, and record accesses to variables. If X is written by the - parent tree, WRITER is the parent. - We store accesses in one of the two lists: PBEFORE_SP, and PNO_SP. If this - expression or its only operand forces a sequence point, then everything up - to the sequence point is stored in PBEFORE_SP. Everything else gets stored - in PNO_SP. - Once we return, we will have emitted warnings if any subexpression before - such a sequence point could be undefined. On a higher level, however, the - sequence point may not be relevant, and we'll merge the two lists. - - Example: (b++, a) + b; - The call that processes the COMPOUND_EXPR will store the increment of B - in PBEFORE_SP, and the use of A in PNO_SP. The higher-level call that - processes the PLUS_EXPR will need to merge the two lists so that - eventually, all accesses end up on the same list (and we'll warn about the - unordered subexpressions b++ and b. - - A note on merging. If we modify the former example so that our expression - becomes - (b++, b) + a - care must be taken not simply to add all three expressions into the final - PNO_SP list. The function merge_tlist takes care of that by merging the - before-SP list of the COMPOUND_EXPR into its after-SP list in a special - way, so that no more than one access to B is recorded. */ - -static void -verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp, - tree writer) -{ - struct tlist *tmp_before, *tmp_nosp, *tmp_list2, *tmp_list3; - enum tree_code code; - enum tree_code_class cl; - - /* X may be NULL if it is the operand of an empty statement expression - ({ }). */ - if (x == NULL) - return; - - restart: - code = TREE_CODE (x); - cl = TREE_CODE_CLASS (code); - - if (warning_candidate_p (x)) - *pno_sp = new_tlist (*pno_sp, x, writer); - - switch (code) - { - case CONSTRUCTOR: - return; - - case COMPOUND_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - tmp_before = tmp_nosp = tmp_list3 = 0; - verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE); - warn_for_collisions (tmp_nosp); - merge_tlist (pbefore_sp, tmp_before, 0); - merge_tlist (pbefore_sp, tmp_nosp, 0); - verify_tree (TREE_OPERAND (x, 1), &tmp_list3, pno_sp, NULL_TREE); - merge_tlist (pbefore_sp, tmp_list3, 0); - return; - - case COND_EXPR: - tmp_before = tmp_list2 = 0; - verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_list2, NULL_TREE); - warn_for_collisions (tmp_list2); - merge_tlist (pbefore_sp, tmp_before, 0); - merge_tlist (pbefore_sp, tmp_list2, 1); - - tmp_list3 = tmp_nosp = 0; - verify_tree (TREE_OPERAND (x, 1), &tmp_list3, &tmp_nosp, NULL_TREE); - warn_for_collisions (tmp_nosp); - merge_tlist (pbefore_sp, tmp_list3, 0); - - tmp_list3 = tmp_list2 = 0; - verify_tree (TREE_OPERAND (x, 2), &tmp_list3, &tmp_list2, NULL_TREE); - warn_for_collisions (tmp_list2); - merge_tlist (pbefore_sp, tmp_list3, 0); - /* Rather than add both tmp_nosp and tmp_list2, we have to merge the - two first, to avoid warning for (a ? b++ : b++). */ - merge_tlist (&tmp_nosp, tmp_list2, 0); - add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0); - return; - - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - verify_tree (TREE_OPERAND (x, 0), pno_sp, pno_sp, x); - return; - - case MODIFY_EXPR: - tmp_before = tmp_nosp = tmp_list3 = 0; - verify_tree (TREE_OPERAND (x, 1), &tmp_before, &tmp_nosp, NULL_TREE); - verify_tree (TREE_OPERAND (x, 0), &tmp_list3, &tmp_list3, x); - /* Expressions inside the LHS are not ordered wrt. the sequence points - in the RHS. Example: - *a = (a++, 2) - Despite the fact that the modification of "a" is in the before_sp - list (tmp_before), it conflicts with the use of "a" in the LHS. - We can handle this by adding the contents of tmp_list3 - to those of tmp_before, and redoing the collision warnings for that - list. */ - add_tlist (&tmp_before, tmp_list3, x, 1); - warn_for_collisions (tmp_before); - /* Exclude the LHS itself here; we first have to merge it into the - tmp_nosp list. This is done to avoid warning for "a = a"; if we - didn't exclude the LHS, we'd get it twice, once as a read and once - as a write. */ - add_tlist (pno_sp, tmp_list3, x, 0); - warn_for_collisions_1 (TREE_OPERAND (x, 0), x, tmp_nosp, 1); - - merge_tlist (pbefore_sp, tmp_before, 0); - if (warning_candidate_p (TREE_OPERAND (x, 0))) - merge_tlist (&tmp_nosp, new_tlist (NULL, TREE_OPERAND (x, 0), x), 0); - add_tlist (pno_sp, tmp_nosp, NULL_TREE, 1); - return; - - case CALL_EXPR: - /* We need to warn about conflicts among arguments and conflicts between - args and the function address. Side effects of the function address, - however, are not ordered by the sequence point of the call. */ - { - call_expr_arg_iterator iter; - tree arg; - tmp_before = tmp_nosp = 0; - verify_tree (CALL_EXPR_FN (x), &tmp_before, &tmp_nosp, NULL_TREE); - FOR_EACH_CALL_EXPR_ARG (arg, iter, x) - { - tmp_list2 = tmp_list3 = 0; - verify_tree (arg, &tmp_list2, &tmp_list3, NULL_TREE); - merge_tlist (&tmp_list3, tmp_list2, 0); - add_tlist (&tmp_before, tmp_list3, NULL_TREE, 0); - } - add_tlist (&tmp_before, tmp_nosp, NULL_TREE, 0); - warn_for_collisions (tmp_before); - add_tlist (pbefore_sp, tmp_before, NULL_TREE, 0); - return; - } - - case TREE_LIST: - /* Scan all the list, e.g. indices of multi dimensional array. */ - while (x) - { - tmp_before = tmp_nosp = 0; - verify_tree (TREE_VALUE (x), &tmp_before, &tmp_nosp, NULL_TREE); - merge_tlist (&tmp_nosp, tmp_before, 0); - add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0); - x = TREE_CHAIN (x); - } - return; - - case SAVE_EXPR: - { - struct tlist_cache *t; - for (t = save_expr_cache; t; t = t->next) - if (candidate_equal_p (t->expr, x)) - break; - - if (!t) - { - t = XOBNEW (&tlist_obstack, struct tlist_cache); - t->next = save_expr_cache; - t->expr = x; - save_expr_cache = t; - - tmp_before = tmp_nosp = 0; - verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE); - warn_for_collisions (tmp_nosp); - - tmp_list3 = 0; - while (tmp_nosp) - { - struct tlist *t = tmp_nosp; - tmp_nosp = t->next; - merge_tlist (&tmp_list3, t, 0); - } - t->cache_before_sp = tmp_before; - t->cache_after_sp = tmp_list3; - } - merge_tlist (pbefore_sp, t->cache_before_sp, 1); - add_tlist (pno_sp, t->cache_after_sp, NULL_TREE, 1); - return; - } - - case ADDR_EXPR: - x = TREE_OPERAND (x, 0); - if (DECL_P (x)) - return; - writer = 0; - goto restart; - - default: - /* For other expressions, simply recurse on their operands. - Manual tail recursion for unary expressions. - Other non-expressions need not be processed. */ - if (cl == tcc_unary) - { - x = TREE_OPERAND (x, 0); - writer = 0; - goto restart; - } - else if (IS_EXPR_CODE_CLASS (cl)) - { - int lp; - int max = TREE_OPERAND_LENGTH (x); - for (lp = 0; lp < max; lp++) - { - tmp_before = tmp_nosp = 0; - verify_tree (TREE_OPERAND (x, lp), &tmp_before, &tmp_nosp, 0); - merge_tlist (&tmp_nosp, tmp_before, 0); - add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0); - } - } - return; - } -} - -/* Try to warn for undefined behavior in EXPR due to missing sequence - points. */ - -DEBUG_FUNCTION void -verify_sequence_points (tree expr) -{ - struct tlist *before_sp = 0, *after_sp = 0; - - warned_ids = 0; - save_expr_cache = 0; - if (tlist_firstobj == 0) - { - gcc_obstack_init (&tlist_obstack); - tlist_firstobj = (char *) obstack_alloc (&tlist_obstack, 0); - } - - verify_tree (expr, &before_sp, &after_sp, 0); - warn_for_collisions (after_sp); - obstack_free (&tlist_obstack, tlist_firstobj); -} - -/* Validate the expression after `case' and apply default promotions. */ - -static tree -check_case_value (tree value) -{ - if (value == NULL_TREE) - return value; - - /* ??? Can we ever get nops here for a valid case value? We - shouldn't for C. */ - STRIP_TYPE_NOPS (value); - /* In C++, the following is allowed: - - const int i = 3; - switch (...) { case i: ... } - - So, we try to reduce the VALUE to a constant that way. */ - if (c_dialect_cxx ()) - { - value = decl_constant_value (value); - STRIP_TYPE_NOPS (value); - value = fold (value); - } - - if (TREE_CODE (value) == INTEGER_CST) - /* Promote char or short to int. */ - value = perform_integral_promotions (value); - else if (value != error_mark_node) - { - error ("case label does not reduce to an integer constant"); - value = error_mark_node; - } - - constant_expression_warning (value); - - return value; -} - -/* See if the case values LOW and HIGH are in the range of the original - type (i.e. before the default conversion to int) of the switch testing - expression. - TYPE is the promoted type of the testing expression, and ORIG_TYPE is - the type before promoting it. CASE_LOW_P is a pointer to the lower - bound of the case label, and CASE_HIGH_P is the upper bound or NULL - if the case is not a case range. - The caller has to make sure that we are not called with NULL for - CASE_LOW_P (i.e. the default case). - Returns true if the case label is in range of ORIG_TYPE (saturated or - untouched) or false if the label is out of range. */ - -static bool -check_case_bounds (tree type, tree orig_type, - tree *case_low_p, tree *case_high_p) -{ - tree min_value, max_value; - tree case_low = *case_low_p; - tree case_high = case_high_p ? *case_high_p : case_low; - - /* If there was a problem with the original type, do nothing. */ - if (orig_type == error_mark_node) - return true; - - min_value = TYPE_MIN_VALUE (orig_type); - max_value = TYPE_MAX_VALUE (orig_type); - - /* Case label is less than minimum for type. */ - if (tree_int_cst_compare (case_low, min_value) < 0 - && tree_int_cst_compare (case_high, min_value) < 0) - { - warning (0, "case label value is less than minimum value for type"); - return false; - } - - /* Case value is greater than maximum for type. */ - if (tree_int_cst_compare (case_low, max_value) > 0 - && tree_int_cst_compare (case_high, max_value) > 0) - { - warning (0, "case label value exceeds maximum value for type"); - return false; - } - - /* Saturate lower case label value to minimum. */ - if (tree_int_cst_compare (case_high, min_value) >= 0 - && tree_int_cst_compare (case_low, min_value) < 0) - { - warning (0, "lower value in case label range" - " less than minimum value for type"); - case_low = min_value; - } - - /* Saturate upper case label value to maximum. */ - if (tree_int_cst_compare (case_low, max_value) <= 0 - && tree_int_cst_compare (case_high, max_value) > 0) - { - warning (0, "upper value in case label range" - " exceeds maximum value for type"); - case_high = max_value; - } - - if (*case_low_p != case_low) - *case_low_p = convert (type, case_low); - if (case_high_p && *case_high_p != case_high) - *case_high_p = convert (type, case_high); - - return true; -} - -/* Return an integer type with BITS bits of precision, - that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ - -tree -c_common_type_for_size (unsigned int bits, int unsignedp) -{ - if (bits == TYPE_PRECISION (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - - if (bits == TYPE_PRECISION (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - - if (bits == TYPE_PRECISION (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - - if (bits == TYPE_PRECISION (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - - if (bits == TYPE_PRECISION (long_long_integer_type_node)) - return (unsignedp ? long_long_unsigned_type_node - : long_long_integer_type_node); - - if (int128_integer_type_node - && bits == TYPE_PRECISION (int128_integer_type_node)) - return (unsignedp ? int128_unsigned_type_node - : int128_integer_type_node); - - if (bits == TYPE_PRECISION (widest_integer_literal_type_node)) - return (unsignedp ? widest_unsigned_literal_type_node - : widest_integer_literal_type_node); - - if (bits <= TYPE_PRECISION (intQI_type_node)) - return unsignedp ? unsigned_intQI_type_node : intQI_type_node; - - if (bits <= TYPE_PRECISION (intHI_type_node)) - return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - - if (bits <= TYPE_PRECISION (intSI_type_node)) - return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - - if (bits <= TYPE_PRECISION (intDI_type_node)) - return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - - return 0; -} - -/* Return a fixed-point type that has at least IBIT ibits and FBIT fbits - that is unsigned if UNSIGNEDP is nonzero, otherwise signed; - and saturating if SATP is nonzero, otherwise not saturating. */ - -tree -c_common_fixed_point_type_for_size (unsigned int ibit, unsigned int fbit, - int unsignedp, int satp) -{ - enum machine_mode mode; - if (ibit == 0) - mode = unsignedp ? UQQmode : QQmode; - else - mode = unsignedp ? UHAmode : HAmode; - - for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - if (GET_MODE_IBIT (mode) >= ibit && GET_MODE_FBIT (mode) >= fbit) - break; - - if (mode == VOIDmode || !targetm.scalar_mode_supported_p (mode)) - { - sorry ("GCC cannot support operators with integer types and " - "fixed-point types that have too many integral and " - "fractional bits together"); - return 0; - } - - return c_common_type_for_mode (mode, satp); -} - -/* Used for communication between c_common_type_for_mode and - c_register_builtin_type. */ -static GTY(()) tree registered_builtin_types; - -/* Return a data type that has machine mode MODE. - If the mode is an integer, - then UNSIGNEDP selects between signed and unsigned types. - If the mode is a fixed-point mode, - then UNSIGNEDP selects between saturating and nonsaturating types. */ - -tree -c_common_type_for_mode (enum machine_mode mode, int unsignedp) -{ - tree t; - - if (mode == TYPE_MODE (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - - if (mode == TYPE_MODE (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - - if (mode == TYPE_MODE (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - - if (mode == TYPE_MODE (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - - if (mode == TYPE_MODE (long_long_integer_type_node)) - return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node; - - if (int128_integer_type_node - && mode == TYPE_MODE (int128_integer_type_node)) - return unsignedp ? int128_unsigned_type_node : int128_integer_type_node; - - if (mode == TYPE_MODE (widest_integer_literal_type_node)) - return unsignedp ? widest_unsigned_literal_type_node - : widest_integer_literal_type_node; - - if (mode == QImode) - return unsignedp ? unsigned_intQI_type_node : intQI_type_node; - - if (mode == HImode) - return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - - if (mode == SImode) - return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - - if (mode == DImode) - return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - -#if HOST_BITS_PER_WIDE_INT >= 64 - if (mode == TYPE_MODE (intTI_type_node)) - return unsignedp ? unsigned_intTI_type_node : intTI_type_node; -#endif - - if (mode == TYPE_MODE (float_type_node)) - return float_type_node; - - if (mode == TYPE_MODE (double_type_node)) - return double_type_node; - - if (mode == TYPE_MODE (long_double_type_node)) - return long_double_type_node; - - if (mode == TYPE_MODE (void_type_node)) - return void_type_node; - - if (mode == TYPE_MODE (build_pointer_type (char_type_node))) - return (unsignedp - ? make_unsigned_type (GET_MODE_PRECISION (mode)) - : make_signed_type (GET_MODE_PRECISION (mode))); - - if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) - return (unsignedp - ? make_unsigned_type (GET_MODE_PRECISION (mode)) - : make_signed_type (GET_MODE_PRECISION (mode))); - - if (COMPLEX_MODE_P (mode)) - { - enum machine_mode inner_mode; - tree inner_type; - - if (mode == TYPE_MODE (complex_float_type_node)) - return complex_float_type_node; - if (mode == TYPE_MODE (complex_double_type_node)) - return complex_double_type_node; - if (mode == TYPE_MODE (complex_long_double_type_node)) - return complex_long_double_type_node; - - if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp) - return complex_integer_type_node; - - inner_mode = GET_MODE_INNER (mode); - inner_type = c_common_type_for_mode (inner_mode, unsignedp); - if (inner_type != NULL_TREE) - return build_complex_type (inner_type); - } - else if (VECTOR_MODE_P (mode)) - { - enum machine_mode inner_mode = GET_MODE_INNER (mode); - tree inner_type = c_common_type_for_mode (inner_mode, unsignedp); - if (inner_type != NULL_TREE) - return build_vector_type_for_mode (inner_type, mode); - } - - if (mode == TYPE_MODE (dfloat32_type_node)) - return dfloat32_type_node; - if (mode == TYPE_MODE (dfloat64_type_node)) - return dfloat64_type_node; - if (mode == TYPE_MODE (dfloat128_type_node)) - return dfloat128_type_node; - - if (ALL_SCALAR_FIXED_POINT_MODE_P (mode)) - { - if (mode == TYPE_MODE (short_fract_type_node)) - return unsignedp ? sat_short_fract_type_node : short_fract_type_node; - if (mode == TYPE_MODE (fract_type_node)) - return unsignedp ? sat_fract_type_node : fract_type_node; - if (mode == TYPE_MODE (long_fract_type_node)) - return unsignedp ? sat_long_fract_type_node : long_fract_type_node; - if (mode == TYPE_MODE (long_long_fract_type_node)) - return unsignedp ? sat_long_long_fract_type_node - : long_long_fract_type_node; - - if (mode == TYPE_MODE (unsigned_short_fract_type_node)) - return unsignedp ? sat_unsigned_short_fract_type_node - : unsigned_short_fract_type_node; - if (mode == TYPE_MODE (unsigned_fract_type_node)) - return unsignedp ? sat_unsigned_fract_type_node - : unsigned_fract_type_node; - if (mode == TYPE_MODE (unsigned_long_fract_type_node)) - return unsignedp ? sat_unsigned_long_fract_type_node - : unsigned_long_fract_type_node; - if (mode == TYPE_MODE (unsigned_long_long_fract_type_node)) - return unsignedp ? sat_unsigned_long_long_fract_type_node - : unsigned_long_long_fract_type_node; - - if (mode == TYPE_MODE (short_accum_type_node)) - return unsignedp ? sat_short_accum_type_node : short_accum_type_node; - if (mode == TYPE_MODE (accum_type_node)) - return unsignedp ? sat_accum_type_node : accum_type_node; - if (mode == TYPE_MODE (long_accum_type_node)) - return unsignedp ? sat_long_accum_type_node : long_accum_type_node; - if (mode == TYPE_MODE (long_long_accum_type_node)) - return unsignedp ? sat_long_long_accum_type_node - : long_long_accum_type_node; - - if (mode == TYPE_MODE (unsigned_short_accum_type_node)) - return unsignedp ? sat_unsigned_short_accum_type_node - : unsigned_short_accum_type_node; - if (mode == TYPE_MODE (unsigned_accum_type_node)) - return unsignedp ? sat_unsigned_accum_type_node - : unsigned_accum_type_node; - if (mode == TYPE_MODE (unsigned_long_accum_type_node)) - return unsignedp ? sat_unsigned_long_accum_type_node - : unsigned_long_accum_type_node; - if (mode == TYPE_MODE (unsigned_long_long_accum_type_node)) - return unsignedp ? sat_unsigned_long_long_accum_type_node - : unsigned_long_long_accum_type_node; - - if (mode == QQmode) - return unsignedp ? sat_qq_type_node : qq_type_node; - if (mode == HQmode) - return unsignedp ? sat_hq_type_node : hq_type_node; - if (mode == SQmode) - return unsignedp ? sat_sq_type_node : sq_type_node; - if (mode == DQmode) - return unsignedp ? sat_dq_type_node : dq_type_node; - if (mode == TQmode) - return unsignedp ? sat_tq_type_node : tq_type_node; - - if (mode == UQQmode) - return unsignedp ? sat_uqq_type_node : uqq_type_node; - if (mode == UHQmode) - return unsignedp ? sat_uhq_type_node : uhq_type_node; - if (mode == USQmode) - return unsignedp ? sat_usq_type_node : usq_type_node; - if (mode == UDQmode) - return unsignedp ? sat_udq_type_node : udq_type_node; - if (mode == UTQmode) - return unsignedp ? sat_utq_type_node : utq_type_node; - - if (mode == HAmode) - return unsignedp ? sat_ha_type_node : ha_type_node; - if (mode == SAmode) - return unsignedp ? sat_sa_type_node : sa_type_node; - if (mode == DAmode) - return unsignedp ? sat_da_type_node : da_type_node; - if (mode == TAmode) - return unsignedp ? sat_ta_type_node : ta_type_node; - - if (mode == UHAmode) - return unsignedp ? sat_uha_type_node : uha_type_node; - if (mode == USAmode) - return unsignedp ? sat_usa_type_node : usa_type_node; - if (mode == UDAmode) - return unsignedp ? sat_uda_type_node : uda_type_node; - if (mode == UTAmode) - return unsignedp ? sat_uta_type_node : uta_type_node; - } - - for (t = registered_builtin_types; t; t = TREE_CHAIN (t)) - if (TYPE_MODE (TREE_VALUE (t)) == mode) - return TREE_VALUE (t); - - return 0; -} - -tree -c_common_unsigned_type (tree type) -{ - return c_common_signed_or_unsigned_type (1, type); -} - -/* Return a signed type the same as TYPE in other respects. */ - -tree -c_common_signed_type (tree type) -{ - return c_common_signed_or_unsigned_type (0, type); -} - -/* Return a type the same as TYPE except unsigned or - signed according to UNSIGNEDP. */ - -tree -c_common_signed_or_unsigned_type (int unsignedp, tree type) -{ - tree type1; - - /* This block of code emulates the behavior of the old - c_common_unsigned_type. In particular, it returns - long_unsigned_type_node if passed a long, even when a int would - have the same size. This is necessary for warnings to work - correctly in archs where sizeof(int) == sizeof(long) */ - - type1 = TYPE_MAIN_VARIANT (type); - if (type1 == signed_char_type_node || type1 == char_type_node || type1 == unsigned_char_type_node) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - if (type1 == integer_type_node || type1 == unsigned_type_node) - return unsignedp ? unsigned_type_node : integer_type_node; - if (type1 == short_integer_type_node || type1 == short_unsigned_type_node) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (type1 == long_integer_type_node || type1 == long_unsigned_type_node) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - if (type1 == long_long_integer_type_node || type1 == long_long_unsigned_type_node) - return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node; - if (int128_integer_type_node - && (type1 == int128_integer_type_node - || type1 == int128_unsigned_type_node)) - return unsignedp ? int128_unsigned_type_node : int128_integer_type_node; - if (type1 == widest_integer_literal_type_node || type1 == widest_unsigned_literal_type_node) - return unsignedp ? widest_unsigned_literal_type_node : widest_integer_literal_type_node; -#if HOST_BITS_PER_WIDE_INT >= 64 - if (type1 == intTI_type_node || type1 == unsigned_intTI_type_node) - return unsignedp ? unsigned_intTI_type_node : intTI_type_node; -#endif - if (type1 == intDI_type_node || type1 == unsigned_intDI_type_node) - return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - if (type1 == intSI_type_node || type1 == unsigned_intSI_type_node) - return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - if (type1 == intHI_type_node || type1 == unsigned_intHI_type_node) - return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - if (type1 == intQI_type_node || type1 == unsigned_intQI_type_node) - return unsignedp ? unsigned_intQI_type_node : intQI_type_node; - -#define C_COMMON_FIXED_TYPES(NAME) \ - if (type1 == short_ ## NAME ## _type_node \ - || type1 == unsigned_short_ ## NAME ## _type_node) \ - return unsignedp ? unsigned_short_ ## NAME ## _type_node \ - : short_ ## NAME ## _type_node; \ - if (type1 == NAME ## _type_node \ - || type1 == unsigned_ ## NAME ## _type_node) \ - return unsignedp ? unsigned_ ## NAME ## _type_node \ - : NAME ## _type_node; \ - if (type1 == long_ ## NAME ## _type_node \ - || type1 == unsigned_long_ ## NAME ## _type_node) \ - return unsignedp ? unsigned_long_ ## NAME ## _type_node \ - : long_ ## NAME ## _type_node; \ - if (type1 == long_long_ ## NAME ## _type_node \ - || type1 == unsigned_long_long_ ## NAME ## _type_node) \ - return unsignedp ? unsigned_long_long_ ## NAME ## _type_node \ - : long_long_ ## NAME ## _type_node; - -#define C_COMMON_FIXED_MODE_TYPES(NAME) \ - if (type1 == NAME ## _type_node \ - || type1 == u ## NAME ## _type_node) \ - return unsignedp ? u ## NAME ## _type_node \ - : NAME ## _type_node; - -#define C_COMMON_FIXED_TYPES_SAT(NAME) \ - if (type1 == sat_ ## short_ ## NAME ## _type_node \ - || type1 == sat_ ## unsigned_short_ ## NAME ## _type_node) \ - return unsignedp ? sat_ ## unsigned_short_ ## NAME ## _type_node \ - : sat_ ## short_ ## NAME ## _type_node; \ - if (type1 == sat_ ## NAME ## _type_node \ - || type1 == sat_ ## unsigned_ ## NAME ## _type_node) \ - return unsignedp ? sat_ ## unsigned_ ## NAME ## _type_node \ - : sat_ ## NAME ## _type_node; \ - if (type1 == sat_ ## long_ ## NAME ## _type_node \ - || type1 == sat_ ## unsigned_long_ ## NAME ## _type_node) \ - return unsignedp ? sat_ ## unsigned_long_ ## NAME ## _type_node \ - : sat_ ## long_ ## NAME ## _type_node; \ - if (type1 == sat_ ## long_long_ ## NAME ## _type_node \ - || type1 == sat_ ## unsigned_long_long_ ## NAME ## _type_node) \ - return unsignedp ? sat_ ## unsigned_long_long_ ## NAME ## _type_node \ - : sat_ ## long_long_ ## NAME ## _type_node; - -#define C_COMMON_FIXED_MODE_TYPES_SAT(NAME) \ - if (type1 == sat_ ## NAME ## _type_node \ - || type1 == sat_ ## u ## NAME ## _type_node) \ - return unsignedp ? sat_ ## u ## NAME ## _type_node \ - : sat_ ## NAME ## _type_node; - - C_COMMON_FIXED_TYPES (fract); - C_COMMON_FIXED_TYPES_SAT (fract); - C_COMMON_FIXED_TYPES (accum); - C_COMMON_FIXED_TYPES_SAT (accum); - - C_COMMON_FIXED_MODE_TYPES (qq); - C_COMMON_FIXED_MODE_TYPES (hq); - C_COMMON_FIXED_MODE_TYPES (sq); - C_COMMON_FIXED_MODE_TYPES (dq); - C_COMMON_FIXED_MODE_TYPES (tq); - C_COMMON_FIXED_MODE_TYPES_SAT (qq); - C_COMMON_FIXED_MODE_TYPES_SAT (hq); - C_COMMON_FIXED_MODE_TYPES_SAT (sq); - C_COMMON_FIXED_MODE_TYPES_SAT (dq); - C_COMMON_FIXED_MODE_TYPES_SAT (tq); - C_COMMON_FIXED_MODE_TYPES (ha); - C_COMMON_FIXED_MODE_TYPES (sa); - C_COMMON_FIXED_MODE_TYPES (da); - C_COMMON_FIXED_MODE_TYPES (ta); - C_COMMON_FIXED_MODE_TYPES_SAT (ha); - C_COMMON_FIXED_MODE_TYPES_SAT (sa); - C_COMMON_FIXED_MODE_TYPES_SAT (da); - C_COMMON_FIXED_MODE_TYPES_SAT (ta); - - /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not - the precision; they have precision set to match their range, but - may use a wider mode to match an ABI. If we change modes, we may - wind up with bad conversions. For INTEGER_TYPEs in C, must check - the precision as well, so as to yield correct results for - bit-field types. C++ does not have these separate bit-field - types, and producing a signed or unsigned variant of an - ENUMERAL_TYPE may cause other problems as well. */ - - if (!INTEGRAL_TYPE_P (type) - || TYPE_UNSIGNED (type) == unsignedp) - return type; - -#define TYPE_OK(node) \ - (TYPE_MODE (type) == TYPE_MODE (node) \ - && TYPE_PRECISION (type) == TYPE_PRECISION (node)) - if (TYPE_OK (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - if (TYPE_OK (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - if (TYPE_OK (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (TYPE_OK (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - if (TYPE_OK (long_long_integer_type_node)) - return (unsignedp ? long_long_unsigned_type_node - : long_long_integer_type_node); - if (int128_integer_type_node && TYPE_OK (int128_integer_type_node)) - return (unsignedp ? int128_unsigned_type_node - : int128_integer_type_node); - if (TYPE_OK (widest_integer_literal_type_node)) - return (unsignedp ? widest_unsigned_literal_type_node - : widest_integer_literal_type_node); - -#if HOST_BITS_PER_WIDE_INT >= 64 - if (TYPE_OK (intTI_type_node)) - return unsignedp ? unsigned_intTI_type_node : intTI_type_node; -#endif - if (TYPE_OK (intDI_type_node)) - return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - if (TYPE_OK (intSI_type_node)) - return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - if (TYPE_OK (intHI_type_node)) - return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - if (TYPE_OK (intQI_type_node)) - return unsignedp ? unsigned_intQI_type_node : intQI_type_node; -#undef TYPE_OK - - return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp); -} - -/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP. */ - -tree -c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp) -{ - /* Extended integer types of the same width as a standard type have - lesser rank, so those of the same width as int promote to int or - unsigned int and are valid for printf formats expecting int or - unsigned int. To avoid such special cases, avoid creating - extended integer types for bit-fields if a standard integer type - is available. */ - if (width == TYPE_PRECISION (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - if (width == TYPE_PRECISION (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - if (width == TYPE_PRECISION (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (width == TYPE_PRECISION (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - if (width == TYPE_PRECISION (long_long_integer_type_node)) - return (unsignedp ? long_long_unsigned_type_node - : long_long_integer_type_node); - if (int128_integer_type_node - && width == TYPE_PRECISION (int128_integer_type_node)) - return (unsignedp ? int128_unsigned_type_node - : int128_integer_type_node); - return build_nonstandard_integer_type (width, unsignedp); -} - -/* The C version of the register_builtin_type langhook. */ - -void -c_register_builtin_type (tree type, const char* name) -{ - tree decl; - - decl = build_decl (UNKNOWN_LOCATION, - TYPE_DECL, get_identifier (name), type); - DECL_ARTIFICIAL (decl) = 1; - if (!TYPE_NAME (type)) - TYPE_NAME (type) = decl; - pushdecl (decl); - - registered_builtin_types = tree_cons (0, type, registered_builtin_types); -} - -/* Print an error message for invalid operands to arith operation - CODE with TYPE0 for operand 0, and TYPE1 for operand 1. - LOCATION is the location of the message. */ - -void -binary_op_error (location_t location, enum tree_code code, - tree type0, tree type1) -{ - const char *opname; - - switch (code) - { - case PLUS_EXPR: - opname = "+"; break; - case MINUS_EXPR: - opname = "-"; break; - case MULT_EXPR: - opname = "*"; break; - case MAX_EXPR: - opname = "max"; break; - case MIN_EXPR: - opname = "min"; break; - case EQ_EXPR: - opname = "=="; break; - case NE_EXPR: - opname = "!="; break; - case LE_EXPR: - opname = "<="; break; - case GE_EXPR: - opname = ">="; break; - case LT_EXPR: - opname = "<"; break; - case GT_EXPR: - opname = ">"; break; - case LSHIFT_EXPR: - opname = "<<"; break; - case RSHIFT_EXPR: - opname = ">>"; break; - case TRUNC_MOD_EXPR: - case FLOOR_MOD_EXPR: - opname = "%"; break; - case TRUNC_DIV_EXPR: - case FLOOR_DIV_EXPR: - opname = "/"; break; - case BIT_AND_EXPR: - opname = "&"; break; - case BIT_IOR_EXPR: - opname = "|"; break; - case TRUTH_ANDIF_EXPR: - opname = "&&"; break; - case TRUTH_ORIF_EXPR: - opname = "||"; break; - case BIT_XOR_EXPR: - opname = "^"; break; - default: - gcc_unreachable (); - } - error_at (location, - "invalid operands to binary %s (have %qT and %qT)", opname, - type0, type1); -} - -/* Subroutine of build_binary_op, used for comparison operations. - See if the operands have both been converted from subword integer types - and, if so, perhaps change them both back to their original type. - This function is also responsible for converting the two operands - to the proper common type for comparison. - - The arguments of this function are all pointers to local variables - of build_binary_op: OP0_PTR is &OP0, OP1_PTR is &OP1, - RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE. - - If this function returns nonzero, it means that the comparison has - a constant value. What this function returns is an expression for - that value. */ - -tree -shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, - enum tree_code *rescode_ptr) -{ - tree type; - tree op0 = *op0_ptr; - tree op1 = *op1_ptr; - int unsignedp0, unsignedp1; - int real1, real2; - tree primop0, primop1; - enum tree_code code = *rescode_ptr; - - /* Throw away any conversions to wider types - already present in the operands. */ - - primop0 = get_narrower (op0, &unsignedp0); - primop1 = get_narrower (op1, &unsignedp1); - - /* Handle the case that OP0 does not *contain* a conversion - but it *requires* conversion to FINAL_TYPE. */ - - if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr) - unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (op0)); - if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr) - unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (op1)); - - /* If one of the operands must be floated, we cannot optimize. */ - real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE; - real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE; - - /* If first arg is constant, swap the args (changing operation - so value is preserved), for canonicalization. Don't do this if - the second arg is 0. */ - - if (TREE_CONSTANT (primop0) - && !integer_zerop (primop1) && !real_zerop (primop1) - && !fixed_zerop (primop1)) - { - tree tem = primop0; - int temi = unsignedp0; - primop0 = primop1; - primop1 = tem; - tem = op0; - op0 = op1; - op1 = tem; - *op0_ptr = op0; - *op1_ptr = op1; - unsignedp0 = unsignedp1; - unsignedp1 = temi; - temi = real1; - real1 = real2; - real2 = temi; - - switch (code) - { - case LT_EXPR: - code = GT_EXPR; - break; - case GT_EXPR: - code = LT_EXPR; - break; - case LE_EXPR: - code = GE_EXPR; - break; - case GE_EXPR: - code = LE_EXPR; - break; - default: - break; - } - *rescode_ptr = code; - } - - /* If comparing an integer against a constant more bits wide, - maybe we can deduce a value of 1 or 0 independent of the data. - Or else truncate the constant now - rather than extend the variable at run time. - - This is only interesting if the constant is the wider arg. - Also, it is not safe if the constant is unsigned and the - variable arg is signed, since in this case the variable - would be sign-extended and then regarded as unsigned. - Our technique fails in this case because the lowest/highest - possible unsigned results don't follow naturally from the - lowest/highest possible values of the variable operand. - For just EQ_EXPR and NE_EXPR there is another technique that - could be used: see if the constant can be faithfully represented - in the other operand's type, by truncating it and reextending it - and see if that preserves the constant's value. */ - - if (!real1 && !real2 - && TREE_CODE (TREE_TYPE (primop0)) != FIXED_POINT_TYPE - && TREE_CODE (primop1) == INTEGER_CST - && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)) - { - int min_gt, max_gt, min_lt, max_lt; - tree maxval, minval; - /* 1 if comparison is nominally unsigned. */ - int unsignedp = TYPE_UNSIGNED (*restype_ptr); - tree val; - - type = c_common_signed_or_unsigned_type (unsignedp0, - TREE_TYPE (primop0)); - - maxval = TYPE_MAX_VALUE (type); - minval = TYPE_MIN_VALUE (type); - - if (unsignedp && !unsignedp0) - *restype_ptr = c_common_signed_type (*restype_ptr); - - if (TREE_TYPE (primop1) != *restype_ptr) - { - /* Convert primop1 to target type, but do not introduce - additional overflow. We know primop1 is an int_cst. */ - primop1 = force_fit_type_double (*restype_ptr, - TREE_INT_CST_LOW (primop1), - TREE_INT_CST_HIGH (primop1), 0, - TREE_OVERFLOW (primop1)); - } - if (type != *restype_ptr) - { - minval = convert (*restype_ptr, minval); - maxval = convert (*restype_ptr, maxval); - } - - if (unsignedp && unsignedp0) - { - min_gt = INT_CST_LT_UNSIGNED (primop1, minval); - max_gt = INT_CST_LT_UNSIGNED (primop1, maxval); - min_lt = INT_CST_LT_UNSIGNED (minval, primop1); - max_lt = INT_CST_LT_UNSIGNED (maxval, primop1); - } - else - { - min_gt = INT_CST_LT (primop1, minval); - max_gt = INT_CST_LT (primop1, maxval); - min_lt = INT_CST_LT (minval, primop1); - max_lt = INT_CST_LT (maxval, primop1); - } - - val = 0; - /* This used to be a switch, but Genix compiler can't handle that. */ - if (code == NE_EXPR) - { - if (max_lt || min_gt) - val = truthvalue_true_node; - } - else if (code == EQ_EXPR) - { - if (max_lt || min_gt) - val = truthvalue_false_node; - } - else if (code == LT_EXPR) - { - if (max_lt) - val = truthvalue_true_node; - if (!min_lt) - val = truthvalue_false_node; - } - else if (code == GT_EXPR) - { - if (min_gt) - val = truthvalue_true_node; - if (!max_gt) - val = truthvalue_false_node; - } - else if (code == LE_EXPR) - { - if (!max_gt) - val = truthvalue_true_node; - if (min_gt) - val = truthvalue_false_node; - } - else if (code == GE_EXPR) - { - if (!min_lt) - val = truthvalue_true_node; - if (max_lt) - val = truthvalue_false_node; - } - - /* If primop0 was sign-extended and unsigned comparison specd, - we did a signed comparison above using the signed type bounds. - But the comparison we output must be unsigned. - - Also, for inequalities, VAL is no good; but if the signed - comparison had *any* fixed result, it follows that the - unsigned comparison just tests the sign in reverse - (positive values are LE, negative ones GE). - So we can generate an unsigned comparison - against an extreme value of the signed type. */ - - if (unsignedp && !unsignedp0) - { - if (val != 0) - switch (code) - { - case LT_EXPR: - case GE_EXPR: - primop1 = TYPE_MIN_VALUE (type); - val = 0; - break; - - case LE_EXPR: - case GT_EXPR: - primop1 = TYPE_MAX_VALUE (type); - val = 0; - break; - - default: - break; - } - type = c_common_unsigned_type (type); - } - - if (TREE_CODE (primop0) != INTEGER_CST) - { - if (val == truthvalue_false_node) - warning (OPT_Wtype_limits, "comparison is always false due to limited range of data type"); - if (val == truthvalue_true_node) - warning (OPT_Wtype_limits, "comparison is always true due to limited range of data type"); - } - - if (val != 0) - { - /* Don't forget to evaluate PRIMOP0 if it has side effects. */ - if (TREE_SIDE_EFFECTS (primop0)) - return build2 (COMPOUND_EXPR, TREE_TYPE (val), primop0, val); - return val; - } - - /* Value is not predetermined, but do the comparison - in the type of the operand that is not constant. - TYPE is already properly set. */ - } - - /* If either arg is decimal float and the other is float, find the - proper common type to use for comparison. */ - else if (real1 && real2 - && (DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (primop0))) - || DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (primop1))))) - type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)); - - else if (real1 && real2 - && (TYPE_PRECISION (TREE_TYPE (primop0)) - == TYPE_PRECISION (TREE_TYPE (primop1)))) - type = TREE_TYPE (primop0); - - /* If args' natural types are both narrower than nominal type - and both extend in the same manner, compare them - in the type of the wider arg. - Otherwise must actually extend both to the nominal - common type lest different ways of extending - alter the result. - (eg, (short)-1 == (unsigned short)-1 should be 0.) */ - - else if (unsignedp0 == unsignedp1 && real1 == real2 - && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr) - && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)) - { - type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)); - type = c_common_signed_or_unsigned_type (unsignedp0 - || TYPE_UNSIGNED (*restype_ptr), - type); - /* Make sure shorter operand is extended the right way - to match the longer operand. */ - primop0 - = convert (c_common_signed_or_unsigned_type (unsignedp0, - TREE_TYPE (primop0)), - primop0); - primop1 - = convert (c_common_signed_or_unsigned_type (unsignedp1, - TREE_TYPE (primop1)), - primop1); - } - else - { - /* Here we must do the comparison on the nominal type - using the args exactly as we received them. */ - type = *restype_ptr; - primop0 = op0; - primop1 = op1; - - if (!real1 && !real2 && integer_zerop (primop1) - && TYPE_UNSIGNED (*restype_ptr)) - { - tree value = 0; - switch (code) - { - case GE_EXPR: - /* All unsigned values are >= 0, so we warn. However, - if OP0 is a constant that is >= 0, the signedness of - the comparison isn't an issue, so suppress the - warning. */ - if (warn_type_limits && !in_system_header - && !(TREE_CODE (primop0) == INTEGER_CST - && !TREE_OVERFLOW (convert (c_common_signed_type (type), - primop0)))) - warning (OPT_Wtype_limits, - "comparison of unsigned expression >= 0 is always true"); - value = truthvalue_true_node; - break; - - case LT_EXPR: - if (warn_type_limits && !in_system_header - && !(TREE_CODE (primop0) == INTEGER_CST - && !TREE_OVERFLOW (convert (c_common_signed_type (type), - primop0)))) - warning (OPT_Wtype_limits, - "comparison of unsigned expression < 0 is always false"); - value = truthvalue_false_node; - break; - - default: - break; - } - - if (value != 0) - { - /* Don't forget to evaluate PRIMOP0 if it has side effects. */ - if (TREE_SIDE_EFFECTS (primop0)) - return build2 (COMPOUND_EXPR, TREE_TYPE (value), - primop0, value); - return value; - } - } - } - - *op0_ptr = convert (type, primop0); - *op1_ptr = convert (type, primop1); - - *restype_ptr = truthvalue_type_node; - - return 0; -} - -/* Return a tree for the sum or difference (RESULTCODE says which) - of pointer PTROP and integer INTOP. */ - -tree -pointer_int_sum (location_t loc, enum tree_code resultcode, - tree ptrop, tree intop) -{ - tree size_exp, ret; - - /* The result is a pointer of the same type that is being added. */ - tree result_type = TREE_TYPE (ptrop); - - if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) - { - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, - "pointer of type % used in arithmetic"); - size_exp = integer_one_node; - } - else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE) - { - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, - "pointer to a function used in arithmetic"); - size_exp = integer_one_node; - } - else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE) - { - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, - "pointer to member function used in arithmetic"); - size_exp = integer_one_node; - } - else - size_exp = size_in_bytes (TREE_TYPE (result_type)); - - /* We are manipulating pointer values, so we don't need to warn - about relying on undefined signed overflow. We disable the - warning here because we use integer types so fold won't know that - they are really pointers. */ - fold_defer_overflow_warnings (); - - /* If what we are about to multiply by the size of the elements - contains a constant term, apply distributive law - and multiply that constant term separately. - This helps produce common subexpressions. */ - if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR) - && !TREE_CONSTANT (intop) - && TREE_CONSTANT (TREE_OPERAND (intop, 1)) - && TREE_CONSTANT (size_exp) - /* If the constant comes from pointer subtraction, - skip this optimization--it would cause an error. */ - && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE - /* If the constant is unsigned, and smaller than the pointer size, - then we must skip this optimization. This is because it could cause - an overflow error if the constant is negative but INTOP is not. */ - && (!TYPE_UNSIGNED (TREE_TYPE (intop)) - || (TYPE_PRECISION (TREE_TYPE (intop)) - == TYPE_PRECISION (TREE_TYPE (ptrop))))) - { - enum tree_code subcode = resultcode; - tree int_type = TREE_TYPE (intop); - if (TREE_CODE (intop) == MINUS_EXPR) - subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); - /* Convert both subexpression types to the type of intop, - because weird cases involving pointer arithmetic - can result in a sum or difference with different type args. */ - ptrop = build_binary_op (EXPR_LOCATION (TREE_OPERAND (intop, 1)), - subcode, ptrop, - convert (int_type, TREE_OPERAND (intop, 1)), 1); - intop = convert (int_type, TREE_OPERAND (intop, 0)); - } - - /* Convert the integer argument to a type the same size as sizetype - so the multiply won't overflow spuriously. */ - if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype) - || TYPE_UNSIGNED (TREE_TYPE (intop)) != TYPE_UNSIGNED (sizetype)) - intop = convert (c_common_type_for_size (TYPE_PRECISION (sizetype), - TYPE_UNSIGNED (sizetype)), intop); - - /* Replace the integer argument with a suitable product by the object size. - Do this multiplication as signed, then convert to the appropriate type - for the pointer operation and disregard an overflow that occured only - because of the sign-extension change in the latter conversion. */ - { - tree t = build_binary_op (loc, - MULT_EXPR, intop, - convert (TREE_TYPE (intop), size_exp), 1); - intop = convert (sizetype, t); - if (TREE_OVERFLOW_P (intop) && !TREE_OVERFLOW (t)) - intop = build_int_cst_wide (TREE_TYPE (intop), TREE_INT_CST_LOW (intop), - TREE_INT_CST_HIGH (intop)); - } - - /* Create the sum or difference. */ - if (resultcode == MINUS_EXPR) - intop = fold_build1_loc (loc, NEGATE_EXPR, sizetype, intop); - - ret = fold_build2_loc (loc, POINTER_PLUS_EXPR, result_type, ptrop, intop); - - fold_undefer_and_ignore_overflow_warnings (); - - return ret; -} - -/* Wrap a C_MAYBE_CONST_EXPR around an expression that is fully folded - and if NON_CONST is known not to be permitted in an evaluated part - of a constant expression. */ - -tree -c_wrap_maybe_const (tree expr, bool non_const) -{ - bool nowarning = TREE_NO_WARNING (expr); - location_t loc = EXPR_LOCATION (expr); - - /* This should never be called for C++. */ - if (c_dialect_cxx ()) - gcc_unreachable (); - - /* The result of folding may have a NOP_EXPR to set TREE_NO_WARNING. */ - STRIP_TYPE_NOPS (expr); - expr = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL, expr); - C_MAYBE_CONST_EXPR_NON_CONST (expr) = non_const; - if (nowarning) - TREE_NO_WARNING (expr) = 1; - protected_set_expr_location (expr, loc); - - return expr; -} - -/* Wrap a SAVE_EXPR around EXPR, if appropriate. Like save_expr, but - for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR - around the SAVE_EXPR if needed so that c_fully_fold does not need - to look inside SAVE_EXPRs. */ - -tree -c_save_expr (tree expr) -{ - bool maybe_const = true; - if (c_dialect_cxx ()) - return save_expr (expr); - expr = c_fully_fold (expr, false, &maybe_const); - expr = save_expr (expr); - if (!maybe_const) - expr = c_wrap_maybe_const (expr, true); - return expr; -} - -/* Return whether EXPR is a declaration whose address can never be - NULL. */ - -bool -decl_with_nonnull_addr_p (const_tree expr) -{ - return (DECL_P (expr) - && (TREE_CODE (expr) == PARM_DECL - || TREE_CODE (expr) == LABEL_DECL - || !DECL_WEAK (expr))); -} - -/* Prepare expr to be an argument of a TRUTH_NOT_EXPR, - or for an `if' or `while' statement or ?..: exp. It should already - have been validated to be of suitable type; otherwise, a bad - diagnostic may result. - - The EXPR is located at LOCATION. - - This preparation consists of taking the ordinary - representation of an expression expr and producing a valid tree - boolean expression describing whether expr is nonzero. We could - simply always do build_binary_op (NE_EXPR, expr, truthvalue_false_node, 1), - but we optimize comparisons, &&, ||, and !. - - The resulting type should always be `truthvalue_type_node'. */ - -tree -c_common_truthvalue_conversion (location_t location, tree expr) -{ - switch (TREE_CODE (expr)) - { - case EQ_EXPR: case NE_EXPR: case UNEQ_EXPR: case LTGT_EXPR: - case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: - case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR: - case ORDERED_EXPR: case UNORDERED_EXPR: - if (TREE_TYPE (expr) == truthvalue_type_node) - return expr; - expr = build2 (TREE_CODE (expr), truthvalue_type_node, - TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1)); - goto ret; - - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - if (TREE_TYPE (expr) == truthvalue_type_node) - return expr; - expr = build2 (TREE_CODE (expr), truthvalue_type_node, - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 0)), - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 1))); - goto ret; - - case TRUTH_NOT_EXPR: - if (TREE_TYPE (expr) == truthvalue_type_node) - return expr; - expr = build1 (TREE_CODE (expr), truthvalue_type_node, - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 0))); - goto ret; - - case ERROR_MARK: - return expr; - - case INTEGER_CST: - return integer_zerop (expr) ? truthvalue_false_node - : truthvalue_true_node; - - case REAL_CST: - return real_compare (NE_EXPR, &TREE_REAL_CST (expr), &dconst0) - ? truthvalue_true_node - : truthvalue_false_node; - - case FIXED_CST: - return fixed_compare (NE_EXPR, &TREE_FIXED_CST (expr), - &FCONST0 (TYPE_MODE (TREE_TYPE (expr)))) - ? truthvalue_true_node - : truthvalue_false_node; - - case FUNCTION_DECL: - expr = build_unary_op (location, ADDR_EXPR, expr, 0); - /* Fall through. */ - - case ADDR_EXPR: - { - tree inner = TREE_OPERAND (expr, 0); - if (decl_with_nonnull_addr_p (inner)) - { - /* Common Ada/Pascal programmer's mistake. */ - warning_at (location, - OPT_Waddress, - "the address of %qD will always evaluate as %", - inner); - return truthvalue_true_node; - } - - /* If we still have a decl, it is possible for its address to - be NULL, so we cannot optimize. */ - if (DECL_P (inner)) - { - gcc_assert (DECL_WEAK (inner)); - break; - } - - if (TREE_SIDE_EFFECTS (inner)) - { - expr = build2 (COMPOUND_EXPR, truthvalue_type_node, - inner, truthvalue_true_node); - goto ret; - } - else - return truthvalue_true_node; - } - - case COMPLEX_EXPR: - expr = build_binary_op (EXPR_LOCATION (expr), - (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)) - ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 0)), - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 1)), - 0); - goto ret; - - case NEGATE_EXPR: - case ABS_EXPR: - case FLOAT_EXPR: - case EXCESS_PRECISION_EXPR: - /* These don't change whether an object is nonzero or zero. */ - return c_common_truthvalue_conversion (location, TREE_OPERAND (expr, 0)); - - case LROTATE_EXPR: - case RROTATE_EXPR: - /* These don't change whether an object is zero or nonzero, but - we can't ignore them if their second arg has side-effects. */ - if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))) - { - expr = build2 (COMPOUND_EXPR, truthvalue_type_node, - TREE_OPERAND (expr, 1), - c_common_truthvalue_conversion - (location, TREE_OPERAND (expr, 0))); - goto ret; - } - else - return c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 0)); - - case COND_EXPR: - /* Distribute the conversion into the arms of a COND_EXPR. */ - if (c_dialect_cxx ()) - { - expr = fold_build3_loc (location, COND_EXPR, truthvalue_type_node, - TREE_OPERAND (expr, 0), - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, - 1)), - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, - 2))); - goto ret; - } - else - { - /* Folding will happen later for C. */ - expr = build3 (COND_EXPR, truthvalue_type_node, - TREE_OPERAND (expr, 0), - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 1)), - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 2))); - goto ret; - } - - CASE_CONVERT: - /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE, - since that affects how `default_conversion' will behave. */ - if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE - || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE) - break; - /* If this is widening the argument, we can ignore it. */ - if (TYPE_PRECISION (TREE_TYPE (expr)) - >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) - return c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 0)); - break; - - case MODIFY_EXPR: - if (!TREE_NO_WARNING (expr) - && warn_parentheses) - { - warning (OPT_Wparentheses, - "suggest parentheses around assignment used as truth value"); - TREE_NO_WARNING (expr) = 1; - } - break; - - default: - break; - } - - if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) - { - tree t = c_save_expr (expr); - expr = (build_binary_op - (EXPR_LOCATION (expr), - (TREE_SIDE_EFFECTS (expr) - ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), - c_common_truthvalue_conversion - (location, - build_unary_op (location, REALPART_EXPR, t, 0)), - c_common_truthvalue_conversion - (location, - build_unary_op (location, IMAGPART_EXPR, t, 0)), - 0)); - goto ret; - } - - if (TREE_CODE (TREE_TYPE (expr)) == FIXED_POINT_TYPE) - { - tree fixed_zero_node = build_fixed (TREE_TYPE (expr), - FCONST0 (TYPE_MODE - (TREE_TYPE (expr)))); - return build_binary_op (location, NE_EXPR, expr, fixed_zero_node, 1); - } - else - return build_binary_op (location, NE_EXPR, expr, integer_zero_node, 1); - - ret: - protected_set_expr_location (expr, location); - return expr; -} - -static void def_builtin_1 (enum built_in_function fncode, - const char *name, - enum built_in_class fnclass, - tree fntype, tree libtype, - bool both_p, bool fallback_p, bool nonansi_p, - tree fnattrs, bool implicit_p); - - -/* Apply the TYPE_QUALS to the new DECL. */ - -void -c_apply_type_quals_to_decl (int type_quals, tree decl) -{ - tree type = TREE_TYPE (decl); - - if (type == error_mark_node) - return; - - if (((type_quals & TYPE_QUAL_CONST) - || (type && TREE_CODE (type) == REFERENCE_TYPE)) - /* An object declared 'const' is only readonly after it is - initialized. We don't have any way of expressing this currently, - so we need to be conservative and unset TREE_READONLY for types - with constructors. Otherwise aliasing code will ignore stores in - an inline constructor. */ - && !(type && TYPE_NEEDS_CONSTRUCTING (type))) - TREE_READONLY (decl) = 1; - if (type_quals & TYPE_QUAL_VOLATILE) - { - TREE_SIDE_EFFECTS (decl) = 1; - TREE_THIS_VOLATILE (decl) = 1; - } - if (type_quals & TYPE_QUAL_RESTRICT) - { - while (type && TREE_CODE (type) == ARRAY_TYPE) - /* Allow 'restrict' on arrays of pointers. - FIXME currently we just ignore it. */ - type = TREE_TYPE (type); - if (!type - || !POINTER_TYPE_P (type) - || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type))) - error ("invalid use of %"); - } -} - -/* Hash function for the problem of multiple type definitions in - different files. This must hash all types that will compare - equal via comptypes to the same value. In practice it hashes - on some of the simple stuff and leaves the details to comptypes. */ - -static hashval_t -c_type_hash (const void *p) -{ - int i = 0; - int shift, size; - const_tree const t = (const_tree) p; - tree t2; - switch (TREE_CODE (t)) - { - /* For pointers, hash on pointee type plus some swizzling. */ - case POINTER_TYPE: - return c_type_hash (TREE_TYPE (t)) ^ 0x3003003; - /* Hash on number of elements and total size. */ - case ENUMERAL_TYPE: - shift = 3; - t2 = TYPE_VALUES (t); - break; - case RECORD_TYPE: - shift = 0; - t2 = TYPE_FIELDS (t); - break; - case QUAL_UNION_TYPE: - shift = 1; - t2 = TYPE_FIELDS (t); - break; - case UNION_TYPE: - shift = 2; - t2 = TYPE_FIELDS (t); - break; - default: - gcc_unreachable (); - } - for (; t2; t2 = TREE_CHAIN (t2)) - i++; - /* We might have a VLA here. */ - if (TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST) - size = 0; - else - size = TREE_INT_CST_LOW (TYPE_SIZE (t)); - return ((size << 24) | (i << shift)); -} - -static GTY((param_is (union tree_node))) htab_t type_hash_table; - -/* Return the typed-based alias set for T, which may be an expression - or a type. Return -1 if we don't do anything special. */ - -alias_set_type -c_common_get_alias_set (tree t) -{ - tree u; - PTR *slot; - - /* For VLAs, use the alias set of the element type rather than the - default of alias set 0 for types compared structurally. */ - if (TYPE_P (t) && TYPE_STRUCTURAL_EQUALITY_P (t)) - { - if (TREE_CODE (t) == ARRAY_TYPE) - return get_alias_set (TREE_TYPE (t)); - return -1; - } - - /* Permit type-punning when accessing a union, provided the access - is directly through the union. For example, this code does not - permit taking the address of a union member and then storing - through it. Even the type-punning allowed here is a GCC - extension, albeit a common and useful one; the C standard says - that such accesses have implementation-defined behavior. */ - for (u = t; - TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF; - u = TREE_OPERAND (u, 0)) - if (TREE_CODE (u) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE) - return 0; - - /* That's all the expressions we handle specially. */ - if (!TYPE_P (t)) - return -1; - - /* The C standard guarantees that any object may be accessed via an - lvalue that has character type. */ - if (t == char_type_node - || t == signed_char_type_node - || t == unsigned_char_type_node) - return 0; - - /* The C standard specifically allows aliasing between signed and - unsigned variants of the same type. We treat the signed - variant as canonical. */ - if (TREE_CODE (t) == INTEGER_TYPE && TYPE_UNSIGNED (t)) - { - tree t1 = c_common_signed_type (t); - - /* t1 == t can happen for boolean nodes which are always unsigned. */ - if (t1 != t) - return get_alias_set (t1); - } - else if (POINTER_TYPE_P (t)) - { - tree t1; - - /* Unfortunately, there is no canonical form of a pointer type. - In particular, if we have `typedef int I', then `int *', and - `I *' are different types. So, we have to pick a canonical - representative. We do this below. - - Technically, this approach is actually more conservative that - it needs to be. In particular, `const int *' and `int *' - should be in different alias sets, according to the C and C++ - standard, since their types are not the same, and so, - technically, an `int **' and `const int **' cannot point at - the same thing. - - But, the standard is wrong. In particular, this code is - legal C++: - - int *ip; - int **ipp = &ip; - const int* const* cipp = ipp; - - And, it doesn't make sense for that to be legal unless you - can dereference IPP and CIPP. So, we ignore cv-qualifiers on - the pointed-to types. This issue has been reported to the - C++ committee. */ - t1 = build_type_no_quals (t); - if (t1 != t) - return get_alias_set (t1); - } - - /* Handle the case of multiple type nodes referring to "the same" type, - which occurs with IMA. These share an alias set. FIXME: Currently only - C90 is handled. (In C99 type compatibility is not transitive, which - complicates things mightily. The alias set splay trees can theoretically - represent this, but insertion is tricky when you consider all the - different orders things might arrive in.) */ - - if (c_language != clk_c || flag_isoc99) - return -1; - - /* Save time if there's only one input file. */ - if (num_in_fnames == 1) - return -1; - - /* Pointers need special handling if they point to any type that - needs special handling (below). */ - if (TREE_CODE (t) == POINTER_TYPE) - { - tree t2; - /* Find bottom type under any nested POINTERs. */ - for (t2 = TREE_TYPE (t); - TREE_CODE (t2) == POINTER_TYPE; - t2 = TREE_TYPE (t2)) - ; - if (TREE_CODE (t2) != RECORD_TYPE - && TREE_CODE (t2) != ENUMERAL_TYPE - && TREE_CODE (t2) != QUAL_UNION_TYPE - && TREE_CODE (t2) != UNION_TYPE) - return -1; - if (TYPE_SIZE (t2) == 0) - return -1; - } - /* These are the only cases that need special handling. */ - if (TREE_CODE (t) != RECORD_TYPE - && TREE_CODE (t) != ENUMERAL_TYPE - && TREE_CODE (t) != QUAL_UNION_TYPE - && TREE_CODE (t) != UNION_TYPE - && TREE_CODE (t) != POINTER_TYPE) - return -1; - /* Undefined? */ - if (TYPE_SIZE (t) == 0) - return -1; - - /* Look up t in hash table. Only one of the compatible types within each - alias set is recorded in the table. */ - if (!type_hash_table) - type_hash_table = htab_create_ggc (1021, c_type_hash, - (htab_eq) lang_hooks.types_compatible_p, - NULL); - slot = htab_find_slot (type_hash_table, t, INSERT); - if (*slot != NULL) - { - TYPE_ALIAS_SET (t) = TYPE_ALIAS_SET ((tree)*slot); - return TYPE_ALIAS_SET ((tree)*slot); - } - else - /* Our caller will assign and record (in t) a new alias set; all we need - to do is remember t in the hash table. */ - *slot = t; - - return -1; -} - -/* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where - the second parameter indicates which OPERATOR is being applied. - The COMPLAIN flag controls whether we should diagnose possibly - ill-formed constructs or not. LOC is the location of the SIZEOF or - TYPEOF operator. */ - -tree -c_sizeof_or_alignof_type (location_t loc, - tree type, bool is_sizeof, int complain) -{ - const char *op_name; - tree value = NULL; - enum tree_code type_code = TREE_CODE (type); - - op_name = is_sizeof ? "sizeof" : "__alignof__"; - - if (type_code == FUNCTION_TYPE) - { - if (is_sizeof) - { - if (complain && (pedantic || warn_pointer_arith)) - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, - "invalid application of % to a function type"); - else if (!complain) - return error_mark_node; - value = size_one_node; - } - else - value = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT); - } - else if (type_code == VOID_TYPE || type_code == ERROR_MARK) - { - if (type_code == VOID_TYPE - && complain && (pedantic || warn_pointer_arith)) - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, - "invalid application of %qs to a void type", op_name); - else if (!complain) - return error_mark_node; - value = size_one_node; - } - else if (!COMPLETE_TYPE_P (type)) - { - if (complain) - error_at (loc, "invalid application of %qs to incomplete type %qT ", - op_name, type); - return error_mark_node; - } - else - { - if (is_sizeof) - /* Convert in case a char is more than one unit. */ - value = size_binop_loc (loc, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type), - size_int (TYPE_PRECISION (char_type_node) - / BITS_PER_UNIT)); - else - value = size_int (TYPE_ALIGN_UNIT (type)); - } - - /* VALUE will have an integer type with TYPE_IS_SIZETYPE set. - TYPE_IS_SIZETYPE means that certain things (like overflow) will - never happen. However, this node should really have type - `size_t', which is just a typedef for an ordinary integer type. */ - value = fold_convert_loc (loc, size_type_node, value); - gcc_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value))); - - return value; -} - -/* Implement the __alignof keyword: Return the minimum required - alignment of EXPR, measured in bytes. For VAR_DECLs, - FUNCTION_DECLs and FIELD_DECLs return DECL_ALIGN (which can be set - from an "aligned" __attribute__ specification). LOC is the - location of the ALIGNOF operator. */ - -tree -c_alignof_expr (location_t loc, tree expr) -{ - tree t; - - if (VAR_OR_FUNCTION_DECL_P (expr)) - t = size_int (DECL_ALIGN_UNIT (expr)); - - else if (TREE_CODE (expr) == COMPONENT_REF - && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1))) - { - error_at (loc, "%<__alignof%> applied to a bit-field"); - t = size_one_node; - } - else if (TREE_CODE (expr) == COMPONENT_REF - && TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL) - t = size_int (DECL_ALIGN_UNIT (TREE_OPERAND (expr, 1))); - - else if (TREE_CODE (expr) == INDIRECT_REF) - { - tree t = TREE_OPERAND (expr, 0); - tree best = t; - int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); - - while (CONVERT_EXPR_P (t) - && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE) - { - int thisalign; - - t = TREE_OPERAND (t, 0); - thisalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); - if (thisalign > bestalign) - best = t, bestalign = thisalign; - } - return c_alignof (loc, TREE_TYPE (TREE_TYPE (best))); - } - else - return c_alignof (loc, TREE_TYPE (expr)); - - return fold_convert_loc (loc, size_type_node, t); -} - -/* Handle C and C++ default attributes. */ - -enum built_in_attribute -{ -#define DEF_ATTR_NULL_TREE(ENUM) ENUM, -#define DEF_ATTR_INT(ENUM, VALUE) ENUM, -#define DEF_ATTR_IDENT(ENUM, STRING) ENUM, -#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM, -#include "builtin-attrs.def" -#undef DEF_ATTR_NULL_TREE -#undef DEF_ATTR_INT -#undef DEF_ATTR_IDENT -#undef DEF_ATTR_TREE_LIST - ATTR_LAST -}; - -static GTY(()) tree built_in_attributes[(int) ATTR_LAST]; - -static void c_init_attributes (void); - -enum c_builtin_type -{ -#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME, -#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME, -#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME, -#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME, -#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, -#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, -#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, -#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, -#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, -#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, -#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, -#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, -#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, -#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, -#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \ - NAME, -#define DEF_POINTER_TYPE(NAME, TYPE) NAME, -#include "builtin-types.def" -#undef DEF_PRIMITIVE_TYPE -#undef DEF_FUNCTION_TYPE_0 -#undef DEF_FUNCTION_TYPE_1 -#undef DEF_FUNCTION_TYPE_2 -#undef DEF_FUNCTION_TYPE_3 -#undef DEF_FUNCTION_TYPE_4 -#undef DEF_FUNCTION_TYPE_5 -#undef DEF_FUNCTION_TYPE_6 -#undef DEF_FUNCTION_TYPE_7 -#undef DEF_FUNCTION_TYPE_VAR_0 -#undef DEF_FUNCTION_TYPE_VAR_1 -#undef DEF_FUNCTION_TYPE_VAR_2 -#undef DEF_FUNCTION_TYPE_VAR_3 -#undef DEF_FUNCTION_TYPE_VAR_4 -#undef DEF_FUNCTION_TYPE_VAR_5 -#undef DEF_POINTER_TYPE - BT_LAST -}; - -typedef enum c_builtin_type builtin_type; - -/* A temporary array for c_common_nodes_and_builtins. Used in - communication with def_fn_type. */ -static tree builtin_types[(int) BT_LAST + 1]; - -/* A helper function for c_common_nodes_and_builtins. Build function type - for DEF with return type RET and N arguments. If VAR is true, then the - function should be variadic after those N arguments. - - Takes special care not to ICE if any of the types involved are - error_mark_node, which indicates that said type is not in fact available - (see builtin_type_for_size). In which case the function type as a whole - should be error_mark_node. */ - -static void -def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...) -{ - tree args = NULL, t; - va_list list; - int i; - - va_start (list, n); - for (i = 0; i < n; ++i) - { - builtin_type a = (builtin_type) va_arg (list, int); - t = builtin_types[a]; - if (t == error_mark_node) - goto egress; - args = tree_cons (NULL_TREE, t, args); - } - va_end (list); - - args = nreverse (args); - if (!var) - args = chainon (args, void_list_node); - - t = builtin_types[ret]; - if (t == error_mark_node) - goto egress; - t = build_function_type (t, args); - - egress: - builtin_types[def] = t; -} - -/* Build builtin functions common to both C and C++ language - frontends. */ - -static void -c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node) -{ -#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \ - builtin_types[ENUM] = VALUE; -#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ - def_fn_type (ENUM, RETURN, 0, 0); -#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \ - def_fn_type (ENUM, RETURN, 0, 1, ARG1); -#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \ - def_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2); -#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ - def_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3); -#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ - def_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4); -#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ - def_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5); -#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ - ARG6) \ - def_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6); -#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ - ARG6, ARG7) \ - def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); -#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ - def_fn_type (ENUM, RETURN, 1, 0); -#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ - def_fn_type (ENUM, RETURN, 1, 1, ARG1); -#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ - def_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2); -#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ - def_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3); -#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ - def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4); -#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ - def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5); -#define DEF_POINTER_TYPE(ENUM, TYPE) \ - builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]); - -#include "builtin-types.def" - -#undef DEF_PRIMITIVE_TYPE -#undef DEF_FUNCTION_TYPE_1 -#undef DEF_FUNCTION_TYPE_2 -#undef DEF_FUNCTION_TYPE_3 -#undef DEF_FUNCTION_TYPE_4 -#undef DEF_FUNCTION_TYPE_5 -#undef DEF_FUNCTION_TYPE_6 -#undef DEF_FUNCTION_TYPE_VAR_0 -#undef DEF_FUNCTION_TYPE_VAR_1 -#undef DEF_FUNCTION_TYPE_VAR_2 -#undef DEF_FUNCTION_TYPE_VAR_3 -#undef DEF_FUNCTION_TYPE_VAR_4 -#undef DEF_FUNCTION_TYPE_VAR_5 -#undef DEF_POINTER_TYPE - builtin_types[(int) BT_LAST] = NULL_TREE; - - c_init_attributes (); - -#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \ - NONANSI_P, ATTRS, IMPLICIT, COND) \ - if (NAME && COND) \ - def_builtin_1 (ENUM, NAME, CLASS, \ - builtin_types[(int) TYPE], \ - builtin_types[(int) LIBTYPE], \ - BOTH_P, FALLBACK_P, NONANSI_P, \ - built_in_attributes[(int) ATTRS], IMPLICIT); -#include "builtins.def" -#undef DEF_BUILTIN - - targetm.init_builtins (); - - build_common_builtin_nodes (); - - if (flag_mudflap) - mudflap_init (); -} - -/* Like get_identifier, but avoid warnings about null arguments when - the argument may be NULL for targets where GCC lacks stdint.h type - information. */ - -static inline tree -c_get_ident (const char *id) -{ - return get_identifier (id); -} - -/* Build tree nodes and builtin functions common to both C and C++ language - frontends. */ - -void -c_common_nodes_and_builtins (void) -{ - int char16_type_size; - int char32_type_size; - int wchar_type_size; - tree array_domain_type; - tree va_list_ref_type_node; - tree va_list_arg_type_node; - - /* Define `int' and `char' first so that dbx will output them first. */ - record_builtin_type (RID_INT, NULL, integer_type_node); - record_builtin_type (RID_CHAR, "char", char_type_node); - - /* `signed' is the same as `int'. FIXME: the declarations of "signed", - "unsigned long", "long long unsigned" and "unsigned short" were in C++ - but not C. Are the conditionals here needed? */ - if (c_dialect_cxx ()) - record_builtin_type (RID_SIGNED, NULL, integer_type_node); - record_builtin_type (RID_LONG, "long int", long_integer_type_node); - record_builtin_type (RID_UNSIGNED, "unsigned int", unsigned_type_node); - record_builtin_type (RID_MAX, "long unsigned int", - long_unsigned_type_node); - if (int128_integer_type_node != NULL_TREE) - { - record_builtin_type (RID_INT128, "__int128", - int128_integer_type_node); - record_builtin_type (RID_MAX, "__int128 unsigned", - int128_unsigned_type_node); - } - if (c_dialect_cxx ()) - record_builtin_type (RID_MAX, "unsigned long", long_unsigned_type_node); - record_builtin_type (RID_MAX, "long long int", - long_long_integer_type_node); - record_builtin_type (RID_MAX, "long long unsigned int", - long_long_unsigned_type_node); - if (c_dialect_cxx ()) - record_builtin_type (RID_MAX, "long long unsigned", - long_long_unsigned_type_node); - record_builtin_type (RID_SHORT, "short int", short_integer_type_node); - record_builtin_type (RID_MAX, "short unsigned int", - short_unsigned_type_node); - if (c_dialect_cxx ()) - record_builtin_type (RID_MAX, "unsigned short", - short_unsigned_type_node); - - /* Define both `signed char' and `unsigned char'. */ - record_builtin_type (RID_MAX, "signed char", signed_char_type_node); - record_builtin_type (RID_MAX, "unsigned char", unsigned_char_type_node); - - /* These are types that c_common_type_for_size and - c_common_type_for_mode use. */ - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, NULL_TREE, - intQI_type_node)); - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, NULL_TREE, - intHI_type_node)); - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, NULL_TREE, - intSI_type_node)); - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, NULL_TREE, - intDI_type_node)); -#if HOST_BITS_PER_WIDE_INT >= 64 - if (targetm.scalar_mode_supported_p (TImode)) - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, - get_identifier ("__int128_t"), - intTI_type_node)); -#endif - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, NULL_TREE, - unsigned_intQI_type_node)); - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, NULL_TREE, - unsigned_intHI_type_node)); - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, NULL_TREE, - unsigned_intSI_type_node)); - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, NULL_TREE, - unsigned_intDI_type_node)); -#if HOST_BITS_PER_WIDE_INT >= 64 - if (targetm.scalar_mode_supported_p (TImode)) - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, - get_identifier ("__uint128_t"), - unsigned_intTI_type_node)); -#endif - - /* Create the widest literal types. */ - widest_integer_literal_type_node - = make_signed_type (HOST_BITS_PER_WIDE_INT * 2); - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, NULL_TREE, - widest_integer_literal_type_node)); - - widest_unsigned_literal_type_node - = make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2); - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, NULL_TREE, - widest_unsigned_literal_type_node)); - - /* `unsigned long' is the standard type for sizeof. - Note that stddef.h uses `unsigned long', - and this must agree, even if long and int are the same size. */ - size_type_node = - TREE_TYPE (identifier_global_value (get_identifier (SIZE_TYPE))); - signed_size_type_node = c_common_signed_type (size_type_node); - set_sizetype (size_type_node); - - pid_type_node = - TREE_TYPE (identifier_global_value (get_identifier (PID_TYPE))); - - build_common_tree_nodes_2 (flag_short_double); - - record_builtin_type (RID_FLOAT, NULL, float_type_node); - record_builtin_type (RID_DOUBLE, NULL, double_type_node); - record_builtin_type (RID_MAX, "long double", long_double_type_node); - - /* Only supported decimal floating point extension if the target - actually supports underlying modes. */ - if (targetm.scalar_mode_supported_p (SDmode) - && targetm.scalar_mode_supported_p (DDmode) - && targetm.scalar_mode_supported_p (TDmode)) - { - record_builtin_type (RID_DFLOAT32, NULL, dfloat32_type_node); - record_builtin_type (RID_DFLOAT64, NULL, dfloat64_type_node); - record_builtin_type (RID_DFLOAT128, NULL, dfloat128_type_node); - } - - if (targetm.fixed_point_supported_p ()) - { - record_builtin_type (RID_MAX, "short _Fract", short_fract_type_node); - record_builtin_type (RID_FRACT, NULL, fract_type_node); - record_builtin_type (RID_MAX, "long _Fract", long_fract_type_node); - record_builtin_type (RID_MAX, "long long _Fract", - long_long_fract_type_node); - record_builtin_type (RID_MAX, "unsigned short _Fract", - unsigned_short_fract_type_node); - record_builtin_type (RID_MAX, "unsigned _Fract", - unsigned_fract_type_node); - record_builtin_type (RID_MAX, "unsigned long _Fract", - unsigned_long_fract_type_node); - record_builtin_type (RID_MAX, "unsigned long long _Fract", - unsigned_long_long_fract_type_node); - record_builtin_type (RID_MAX, "_Sat short _Fract", - sat_short_fract_type_node); - record_builtin_type (RID_MAX, "_Sat _Fract", sat_fract_type_node); - record_builtin_type (RID_MAX, "_Sat long _Fract", - sat_long_fract_type_node); - record_builtin_type (RID_MAX, "_Sat long long _Fract", - sat_long_long_fract_type_node); - record_builtin_type (RID_MAX, "_Sat unsigned short _Fract", - sat_unsigned_short_fract_type_node); - record_builtin_type (RID_MAX, "_Sat unsigned _Fract", - sat_unsigned_fract_type_node); - record_builtin_type (RID_MAX, "_Sat unsigned long _Fract", - sat_unsigned_long_fract_type_node); - record_builtin_type (RID_MAX, "_Sat unsigned long long _Fract", - sat_unsigned_long_long_fract_type_node); - record_builtin_type (RID_MAX, "short _Accum", short_accum_type_node); - record_builtin_type (RID_ACCUM, NULL, accum_type_node); - record_builtin_type (RID_MAX, "long _Accum", long_accum_type_node); - record_builtin_type (RID_MAX, "long long _Accum", - long_long_accum_type_node); - record_builtin_type (RID_MAX, "unsigned short _Accum", - unsigned_short_accum_type_node); - record_builtin_type (RID_MAX, "unsigned _Accum", - unsigned_accum_type_node); - record_builtin_type (RID_MAX, "unsigned long _Accum", - unsigned_long_accum_type_node); - record_builtin_type (RID_MAX, "unsigned long long _Accum", - unsigned_long_long_accum_type_node); - record_builtin_type (RID_MAX, "_Sat short _Accum", - sat_short_accum_type_node); - record_builtin_type (RID_MAX, "_Sat _Accum", sat_accum_type_node); - record_builtin_type (RID_MAX, "_Sat long _Accum", - sat_long_accum_type_node); - record_builtin_type (RID_MAX, "_Sat long long _Accum", - sat_long_long_accum_type_node); - record_builtin_type (RID_MAX, "_Sat unsigned short _Accum", - sat_unsigned_short_accum_type_node); - record_builtin_type (RID_MAX, "_Sat unsigned _Accum", - sat_unsigned_accum_type_node); - record_builtin_type (RID_MAX, "_Sat unsigned long _Accum", - sat_unsigned_long_accum_type_node); - record_builtin_type (RID_MAX, "_Sat unsigned long long _Accum", - sat_unsigned_long_long_accum_type_node); - - } - - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, - get_identifier ("complex int"), - complex_integer_type_node)); - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, - get_identifier ("complex float"), - complex_float_type_node)); - lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, - get_identifier ("complex double"), - complex_double_type_node)); - lang_hooks.decls.pushdecl - (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, get_identifier ("complex long double"), - complex_long_double_type_node)); - - if (c_dialect_cxx ()) - /* For C++, make fileptr_type_node a distinct void * type until - FILE type is defined. */ - fileptr_type_node = build_variant_type_copy (ptr_type_node); - - record_builtin_type (RID_VOID, NULL, void_type_node); - - /* Set the TYPE_NAME for any variants that were built before - record_builtin_type gave names to the built-in types. */ - { - tree void_name = TYPE_NAME (void_type_node); - TYPE_NAME (void_type_node) = NULL_TREE; - TYPE_NAME (build_qualified_type (void_type_node, TYPE_QUAL_CONST)) - = void_name; - TYPE_NAME (void_type_node) = void_name; - } - - /* This node must not be shared. */ - void_zero_node = make_node (INTEGER_CST); - TREE_TYPE (void_zero_node) = void_type_node; - - void_list_node = build_void_list_node (); - - /* Make a type to be the domain of a few array types - whose domains don't really matter. - 200 is small enough that it always fits in size_t - and large enough that it can hold most function names for the - initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */ - array_domain_type = build_index_type (size_int (200)); - - /* Make a type for arrays of characters. - With luck nothing will ever really depend on the length of this - array type. */ - char_array_type_node - = build_array_type (char_type_node, array_domain_type); - - /* Likewise for arrays of ints. */ - int_array_type_node - = build_array_type (integer_type_node, array_domain_type); - - string_type_node = build_pointer_type (char_type_node); - const_string_type_node - = build_pointer_type (build_qualified_type - (char_type_node, TYPE_QUAL_CONST)); - - /* This is special for C++ so functions can be overloaded. */ - wchar_type_node = get_identifier (MODIFIED_WCHAR_TYPE); - wchar_type_node = TREE_TYPE (identifier_global_value (wchar_type_node)); - wchar_type_size = TYPE_PRECISION (wchar_type_node); - underlying_wchar_type_node = wchar_type_node; - if (c_dialect_cxx ()) - { - if (TYPE_UNSIGNED (wchar_type_node)) - wchar_type_node = make_unsigned_type (wchar_type_size); - else - wchar_type_node = make_signed_type (wchar_type_size); - record_builtin_type (RID_WCHAR, "wchar_t", wchar_type_node); - } - - /* This is for wide string constants. */ - wchar_array_type_node - = build_array_type (wchar_type_node, array_domain_type); - - /* Define 'char16_t'. */ - char16_type_node = get_identifier (CHAR16_TYPE); - char16_type_node = TREE_TYPE (identifier_global_value (char16_type_node)); - char16_type_size = TYPE_PRECISION (char16_type_node); - if (c_dialect_cxx ()) - { - char16_type_node = make_unsigned_type (char16_type_size); - - if (cxx_dialect == cxx0x) - record_builtin_type (RID_CHAR16, "char16_t", char16_type_node); - } - - /* This is for UTF-16 string constants. */ - char16_array_type_node - = build_array_type (char16_type_node, array_domain_type); - - /* Define 'char32_t'. */ - char32_type_node = get_identifier (CHAR32_TYPE); - char32_type_node = TREE_TYPE (identifier_global_value (char32_type_node)); - char32_type_size = TYPE_PRECISION (char32_type_node); - if (c_dialect_cxx ()) - { - char32_type_node = make_unsigned_type (char32_type_size); - - if (cxx_dialect == cxx0x) - record_builtin_type (RID_CHAR32, "char32_t", char32_type_node); - } - - /* This is for UTF-32 string constants. */ - char32_array_type_node - = build_array_type (char32_type_node, array_domain_type); - - wint_type_node = - TREE_TYPE (identifier_global_value (get_identifier (WINT_TYPE))); - - intmax_type_node = - TREE_TYPE (identifier_global_value (get_identifier (INTMAX_TYPE))); - uintmax_type_node = - TREE_TYPE (identifier_global_value (get_identifier (UINTMAX_TYPE))); - - if (SIG_ATOMIC_TYPE) - sig_atomic_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (SIG_ATOMIC_TYPE))); - if (INT8_TYPE) - int8_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT8_TYPE))); - if (INT16_TYPE) - int16_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT16_TYPE))); - if (INT32_TYPE) - int32_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT32_TYPE))); - if (INT64_TYPE) - int64_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT64_TYPE))); - if (UINT8_TYPE) - uint8_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT8_TYPE))); - if (UINT16_TYPE) - uint16_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT16_TYPE))); - if (UINT32_TYPE) - c_uint32_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT32_TYPE))); - if (UINT64_TYPE) - c_uint64_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT64_TYPE))); - if (INT_LEAST8_TYPE) - int_least8_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST8_TYPE))); - if (INT_LEAST16_TYPE) - int_least16_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST16_TYPE))); - if (INT_LEAST32_TYPE) - int_least32_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST32_TYPE))); - if (INT_LEAST64_TYPE) - int_least64_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST64_TYPE))); - if (UINT_LEAST8_TYPE) - uint_least8_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST8_TYPE))); - if (UINT_LEAST16_TYPE) - uint_least16_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST16_TYPE))); - if (UINT_LEAST32_TYPE) - uint_least32_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST32_TYPE))); - if (UINT_LEAST64_TYPE) - uint_least64_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST64_TYPE))); - if (INT_FAST8_TYPE) - int_fast8_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST8_TYPE))); - if (INT_FAST16_TYPE) - int_fast16_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST16_TYPE))); - if (INT_FAST32_TYPE) - int_fast32_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST32_TYPE))); - if (INT_FAST64_TYPE) - int_fast64_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST64_TYPE))); - if (UINT_FAST8_TYPE) - uint_fast8_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST8_TYPE))); - if (UINT_FAST16_TYPE) - uint_fast16_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST16_TYPE))); - if (UINT_FAST32_TYPE) - uint_fast32_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST32_TYPE))); - if (UINT_FAST64_TYPE) - uint_fast64_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST64_TYPE))); - if (INTPTR_TYPE) - intptr_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (INTPTR_TYPE))); - if (UINTPTR_TYPE) - uintptr_type_node = - TREE_TYPE (identifier_global_value (c_get_ident (UINTPTR_TYPE))); - - default_function_type = build_function_type (integer_type_node, NULL_TREE); - ptrdiff_type_node - = TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE))); - unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node); - - lang_hooks.decls.pushdecl - (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, get_identifier ("__builtin_va_list"), - va_list_type_node)); - if (targetm.enum_va_list) - { - int l; - const char *pname; - tree ptype; - - for (l = 0; targetm.enum_va_list (l, &pname, &ptype); ++l) - { - lang_hooks.decls.pushdecl - (build_decl (UNKNOWN_LOCATION, - TYPE_DECL, get_identifier (pname), - ptype)); - - } - } - - if (TREE_CODE (va_list_type_node) == ARRAY_TYPE) - { - va_list_arg_type_node = va_list_ref_type_node = - build_pointer_type (TREE_TYPE (va_list_type_node)); - } - else - { - va_list_arg_type_node = va_list_type_node; - va_list_ref_type_node = build_reference_type (va_list_type_node); - } - - if (!flag_preprocess_only) - c_define_builtins (va_list_ref_type_node, va_list_arg_type_node); - - main_identifier_node = get_identifier ("main"); - - /* Create the built-in __null node. It is important that this is - not shared. */ - null_node = make_node (INTEGER_CST); - TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0); - - /* Since builtin_types isn't gc'ed, don't export these nodes. */ - memset (builtin_types, 0, sizeof (builtin_types)); -} - -/* The number of named compound-literals generated thus far. */ -static GTY(()) int compound_literal_number; - -/* Set DECL_NAME for DECL, a VAR_DECL for a compound-literal. */ - -void -set_compound_literal_name (tree decl) -{ - char *name; - ASM_FORMAT_PRIVATE_NAME (name, "__compound_literal", - compound_literal_number); - compound_literal_number++; - DECL_NAME (decl) = get_identifier (name); -} - -tree -build_va_arg (location_t loc, tree expr, tree type) -{ - expr = build1 (VA_ARG_EXPR, type, expr); - SET_EXPR_LOCATION (expr, loc); - return expr; -} - - -/* Linked list of disabled built-in functions. */ - -typedef struct disabled_builtin -{ - const char *name; - struct disabled_builtin *next; -} disabled_builtin; -static disabled_builtin *disabled_builtins = NULL; - -static bool builtin_function_disabled_p (const char *); - -/* Disable a built-in function specified by -fno-builtin-NAME. If NAME - begins with "__builtin_", give an error. */ - -void -disable_builtin_function (const char *name) -{ - if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0) - error ("cannot disable built-in function %qs", name); - else - { - disabled_builtin *new_disabled_builtin = XNEW (disabled_builtin); - new_disabled_builtin->name = name; - new_disabled_builtin->next = disabled_builtins; - disabled_builtins = new_disabled_builtin; - } -} - - -/* Return true if the built-in function NAME has been disabled, false - otherwise. */ - -static bool -builtin_function_disabled_p (const char *name) -{ - disabled_builtin *p; - for (p = disabled_builtins; p != NULL; p = p->next) - { - if (strcmp (name, p->name) == 0) - return true; - } - return false; -} - - -/* Worker for DEF_BUILTIN. - Possibly define a builtin function with one or two names. - Does not declare a non-__builtin_ function if flag_no_builtin, or if - nonansi_p and flag_no_nonansi_builtin. */ - -static void -def_builtin_1 (enum built_in_function fncode, - const char *name, - enum built_in_class fnclass, - tree fntype, tree libtype, - bool both_p, bool fallback_p, bool nonansi_p, - tree fnattrs, bool implicit_p) -{ - tree decl; - const char *libname; - - if (fntype == error_mark_node) - return; - - gcc_assert ((!both_p && !fallback_p) - || !strncmp (name, "__builtin_", - strlen ("__builtin_"))); - - libname = name + strlen ("__builtin_"); - decl = add_builtin_function (name, fntype, fncode, fnclass, - (fallback_p ? libname : NULL), - fnattrs); - if (both_p - && !flag_no_builtin && !builtin_function_disabled_p (libname) - && !(nonansi_p && flag_no_nonansi_builtin)) - add_builtin_function (libname, libtype, fncode, fnclass, - NULL, fnattrs); - - built_in_decls[(int) fncode] = decl; - if (implicit_p) - implicit_built_in_decls[(int) fncode] = decl; -} - -/* Nonzero if the type T promotes to int. This is (nearly) the - integral promotions defined in ISO C99 6.3.1.1/2. */ - -bool -c_promoting_integer_type_p (const_tree t) -{ - switch (TREE_CODE (t)) - { - case INTEGER_TYPE: - return (TYPE_MAIN_VARIANT (t) == char_type_node - || TYPE_MAIN_VARIANT (t) == signed_char_type_node - || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node - || TYPE_MAIN_VARIANT (t) == short_integer_type_node - || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node - || TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node)); - - case ENUMERAL_TYPE: - /* ??? Technically all enumerations not larger than an int - promote to an int. But this is used along code paths - that only want to notice a size change. */ - return TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node); - - case BOOLEAN_TYPE: - return 1; - - default: - return 0; - } -} - -/* Return 1 if PARMS specifies a fixed number of parameters - and none of their types is affected by default promotions. */ - -int -self_promoting_args_p (const_tree parms) -{ - const_tree t; - for (t = parms; t; t = TREE_CHAIN (t)) - { - tree type = TREE_VALUE (t); - - if (type == error_mark_node) - continue; - - if (TREE_CHAIN (t) == 0 && type != void_type_node) - return 0; - - if (type == 0) - return 0; - - if (TYPE_MAIN_VARIANT (type) == float_type_node) - return 0; - - if (c_promoting_integer_type_p (type)) - return 0; - } - return 1; -} - -/* Recursively remove any '*' or '&' operator from TYPE. */ -tree -strip_pointer_operator (tree t) -{ - while (POINTER_TYPE_P (t)) - t = TREE_TYPE (t); - return t; -} - -/* Recursively remove pointer or array type from TYPE. */ -tree -strip_pointer_or_array_types (tree t) -{ - while (TREE_CODE (t) == ARRAY_TYPE || POINTER_TYPE_P (t)) - t = TREE_TYPE (t); - return t; -} - -/* Used to compare case labels. K1 and K2 are actually tree nodes - representing case labels, or NULL_TREE for a `default' label. - Returns -1 if K1 is ordered before K2, -1 if K1 is ordered after - K2, and 0 if K1 and K2 are equal. */ - -int -case_compare (splay_tree_key k1, splay_tree_key k2) -{ - /* Consider a NULL key (such as arises with a `default' label) to be - smaller than anything else. */ - if (!k1) - return k2 ? -1 : 0; - else if (!k2) - return k1 ? 1 : 0; - - return tree_int_cst_compare ((tree) k1, (tree) k2); -} - -/* Process a case label, located at LOC, for the range LOW_VALUE - ... HIGH_VALUE. If LOW_VALUE and HIGH_VALUE are both NULL_TREE - then this case label is actually a `default' label. If only - HIGH_VALUE is NULL_TREE, then case label was declared using the - usual C/C++ syntax, rather than the GNU case range extension. - CASES is a tree containing all the case ranges processed so far; - COND is the condition for the switch-statement itself. Returns the - CASE_LABEL_EXPR created, or ERROR_MARK_NODE if no CASE_LABEL_EXPR - is created. */ - -tree -c_add_case_label (location_t loc, splay_tree cases, tree cond, tree orig_type, - tree low_value, tree high_value) -{ - tree type; - tree label; - tree case_label; - splay_tree_node node; - - /* Create the LABEL_DECL itself. */ - label = create_artificial_label (loc); - - /* If there was an error processing the switch condition, bail now - before we get more confused. */ - if (!cond || cond == error_mark_node) - goto error_out; - - if ((low_value && TREE_TYPE (low_value) - && POINTER_TYPE_P (TREE_TYPE (low_value))) - || (high_value && TREE_TYPE (high_value) - && POINTER_TYPE_P (TREE_TYPE (high_value)))) - { - error_at (loc, "pointers are not permitted as case values"); - goto error_out; - } - - /* Case ranges are a GNU extension. */ - if (high_value) - pedwarn (loc, OPT_pedantic, - "range expressions in switch statements are non-standard"); - - type = TREE_TYPE (cond); - if (low_value) - { - low_value = check_case_value (low_value); - low_value = convert_and_check (type, low_value); - if (low_value == error_mark_node) - goto error_out; - } - if (high_value) - { - high_value = check_case_value (high_value); - high_value = convert_and_check (type, high_value); - if (high_value == error_mark_node) - goto error_out; - } - - if (low_value && high_value) - { - /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't - really a case range, even though it was written that way. - Remove the HIGH_VALUE to simplify later processing. */ - if (tree_int_cst_equal (low_value, high_value)) - high_value = NULL_TREE; - else if (!tree_int_cst_lt (low_value, high_value)) - warning_at (loc, 0, "empty range specified"); - } - - /* See if the case is in range of the type of the original testing - expression. If both low_value and high_value are out of range, - don't insert the case label and return NULL_TREE. */ - if (low_value - && !check_case_bounds (type, orig_type, - &low_value, high_value ? &high_value : NULL)) - return NULL_TREE; - - /* Look up the LOW_VALUE in the table of case labels we already - have. */ - node = splay_tree_lookup (cases, (splay_tree_key) low_value); - /* If there was not an exact match, check for overlapping ranges. - There's no need to do this if there's no LOW_VALUE or HIGH_VALUE; - that's a `default' label and the only overlap is an exact match. */ - if (!node && (low_value || high_value)) - { - splay_tree_node low_bound; - splay_tree_node high_bound; - - /* Even though there wasn't an exact match, there might be an - overlap between this case range and another case range. - Since we've (inductively) not allowed any overlapping case - ranges, we simply need to find the greatest low case label - that is smaller that LOW_VALUE, and the smallest low case - label that is greater than LOW_VALUE. If there is an overlap - it will occur in one of these two ranges. */ - low_bound = splay_tree_predecessor (cases, - (splay_tree_key) low_value); - high_bound = splay_tree_successor (cases, - (splay_tree_key) low_value); - - /* Check to see if the LOW_BOUND overlaps. It is smaller than - the LOW_VALUE, so there is no need to check unless the - LOW_BOUND is in fact itself a case range. */ - if (low_bound - && CASE_HIGH ((tree) low_bound->value) - && tree_int_cst_compare (CASE_HIGH ((tree) low_bound->value), - low_value) >= 0) - node = low_bound; - /* Check to see if the HIGH_BOUND overlaps. The low end of that - range is bigger than the low end of the current range, so we - are only interested if the current range is a real range, and - not an ordinary case label. */ - else if (high_bound - && high_value - && (tree_int_cst_compare ((tree) high_bound->key, - high_value) - <= 0)) - node = high_bound; - } - /* If there was an overlap, issue an error. */ - if (node) - { - tree duplicate = CASE_LABEL ((tree) node->value); - - if (high_value) - { - error_at (loc, "duplicate (or overlapping) case value"); - error_at (DECL_SOURCE_LOCATION (duplicate), - "this is the first entry overlapping that value"); - } - else if (low_value) - { - error_at (loc, "duplicate case value") ; - error_at (DECL_SOURCE_LOCATION (duplicate), "previously used here"); - } - else - { - error_at (loc, "multiple default labels in one switch"); - error_at (DECL_SOURCE_LOCATION (duplicate), - "this is the first default label"); - } - goto error_out; - } - - /* Add a CASE_LABEL to the statement-tree. */ - case_label = add_stmt (build_case_label (loc, low_value, high_value, label)); - /* Register this case label in the splay tree. */ - splay_tree_insert (cases, - (splay_tree_key) low_value, - (splay_tree_value) case_label); - - return case_label; - - error_out: - /* Add a label so that the back-end doesn't think that the beginning of - the switch is unreachable. Note that we do not add a case label, as - that just leads to duplicates and thence to failure later on. */ - if (!cases->root) - { - tree t = create_artificial_label (loc); - add_stmt (build_stmt (loc, LABEL_EXPR, t)); - } - return error_mark_node; -} - -/* Subroutines of c_do_switch_warnings, called via splay_tree_foreach. - Used to verify that case values match up with enumerator values. */ - -static void -match_case_to_enum_1 (tree key, tree type, tree label) -{ - char buf[2 + 2*HOST_BITS_PER_WIDE_INT/4 + 1]; - - /* ??? Not working too hard to print the double-word value. - Should perhaps be done with %lwd in the diagnostic routines? */ - if (TREE_INT_CST_HIGH (key) == 0) - snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_UNSIGNED, - TREE_INT_CST_LOW (key)); - else if (!TYPE_UNSIGNED (type) - && TREE_INT_CST_HIGH (key) == -1 - && TREE_INT_CST_LOW (key) != 0) - snprintf (buf, sizeof (buf), "-" HOST_WIDE_INT_PRINT_UNSIGNED, - -TREE_INT_CST_LOW (key)); - else - snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_DOUBLE_HEX, - (unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (key), - (unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (key)); - - if (TYPE_NAME (type) == 0) - warning_at (DECL_SOURCE_LOCATION (CASE_LABEL (label)), - warn_switch ? OPT_Wswitch : OPT_Wswitch_enum, - "case value %qs not in enumerated type", - buf); - else - warning_at (DECL_SOURCE_LOCATION (CASE_LABEL (label)), - warn_switch ? OPT_Wswitch : OPT_Wswitch_enum, - "case value %qs not in enumerated type %qT", - buf, type); -} - -/* Subroutine of c_do_switch_warnings, called via splay_tree_foreach. - Used to verify that case values match up with enumerator values. */ - -static int -match_case_to_enum (splay_tree_node node, void *data) -{ - tree label = (tree) node->value; - tree type = (tree) data; - - /* Skip default case. */ - if (!CASE_LOW (label)) - return 0; - - /* If CASE_LOW_SEEN is not set, that means CASE_LOW did not appear - when we did our enum->case scan. Reset our scratch bit after. */ - if (!CASE_LOW_SEEN (label)) - match_case_to_enum_1 (CASE_LOW (label), type, label); - else - CASE_LOW_SEEN (label) = 0; - - /* If CASE_HIGH is non-null, we have a range. If CASE_HIGH_SEEN is - not set, that means that CASE_HIGH did not appear when we did our - enum->case scan. Reset our scratch bit after. */ - if (CASE_HIGH (label)) - { - if (!CASE_HIGH_SEEN (label)) - match_case_to_enum_1 (CASE_HIGH (label), type, label); - else - CASE_HIGH_SEEN (label) = 0; - } - - return 0; -} - -/* Handle -Wswitch*. Called from the front end after parsing the - switch construct. */ -/* ??? Should probably be somewhere generic, since other languages - besides C and C++ would want this. At the moment, however, C/C++ - are the only tree-ssa languages that support enumerations at all, - so the point is moot. */ - -void -c_do_switch_warnings (splay_tree cases, location_t switch_location, - tree type, tree cond) -{ - splay_tree_node default_node; - splay_tree_node node; - tree chain; - - if (!warn_switch && !warn_switch_enum && !warn_switch_default) - return; - - default_node = splay_tree_lookup (cases, (splay_tree_key) NULL); - if (!default_node) - warning_at (switch_location, OPT_Wswitch_default, - "switch missing default case"); - - /* From here on, we only care about about enumerated types. */ - if (!type || TREE_CODE (type) != ENUMERAL_TYPE) - return; - - /* From here on, we only care about -Wswitch and -Wswitch-enum. */ - if (!warn_switch_enum && !warn_switch) - return; - - /* Check the cases. Warn about case values which are not members of - the enumerated type. For -Wswitch-enum, or for -Wswitch when - there is no default case, check that exactly all enumeration - literals are covered by the cases. */ - - /* Clearing COND if it is not an integer constant simplifies - the tests inside the loop below. */ - if (TREE_CODE (cond) != INTEGER_CST) - cond = NULL_TREE; - - /* The time complexity here is O(N*lg(N)) worst case, but for the - common case of monotonically increasing enumerators, it is - O(N), since the nature of the splay tree will keep the next - element adjacent to the root at all times. */ - - for (chain = TYPE_VALUES (type); chain; chain = TREE_CHAIN (chain)) - { - tree value = TREE_VALUE (chain); - if (TREE_CODE (value) == CONST_DECL) - value = DECL_INITIAL (value); - node = splay_tree_lookup (cases, (splay_tree_key) value); - if (node) - { - /* Mark the CASE_LOW part of the case entry as seen. */ - tree label = (tree) node->value; - CASE_LOW_SEEN (label) = 1; - continue; - } - - /* Even though there wasn't an exact match, there might be a - case range which includes the enumerator's value. */ - node = splay_tree_predecessor (cases, (splay_tree_key) value); - if (node && CASE_HIGH ((tree) node->value)) - { - tree label = (tree) node->value; - int cmp = tree_int_cst_compare (CASE_HIGH (label), value); - if (cmp >= 0) - { - /* If we match the upper bound exactly, mark the CASE_HIGH - part of the case entry as seen. */ - if (cmp == 0) - CASE_HIGH_SEEN (label) = 1; - continue; - } - } - - /* We've now determined that this enumerated literal isn't - handled by the case labels of the switch statement. */ - - /* If the switch expression is a constant, we only really care - about whether that constant is handled by the switch. */ - if (cond && tree_int_cst_compare (cond, value)) - continue; - - /* If there is a default_node, the only relevant option is - Wswitch-enum. Otherwise, if both are enabled then we prefer - to warn using -Wswitch because -Wswitch is enabled by -Wall - while -Wswitch-enum is explicit. */ - warning_at (switch_location, - (default_node || !warn_switch - ? OPT_Wswitch_enum - : OPT_Wswitch), - "enumeration value %qE not handled in switch", - TREE_PURPOSE (chain)); - } - - /* Warn if there are case expressions that don't correspond to - enumerators. This can occur since C and C++ don't enforce - type-checking of assignments to enumeration variables. - - The time complexity here is now always O(N) worst case, since - we should have marked both the lower bound and upper bound of - every disjoint case label, with CASE_LOW_SEEN and CASE_HIGH_SEEN - above. This scan also resets those fields. */ - - splay_tree_foreach (cases, match_case_to_enum, type); -} - -/* Finish an expression taking the address of LABEL (an - IDENTIFIER_NODE). Returns an expression for the address. - - LOC is the location for the expression returned. */ - -tree -finish_label_address_expr (tree label, location_t loc) -{ - tree result; - - pedwarn (input_location, OPT_pedantic, "taking the address of a label is non-standard"); - - if (label == error_mark_node) - return error_mark_node; - - label = lookup_label (label); - if (label == NULL_TREE) - result = null_pointer_node; - else - { - TREE_USED (label) = 1; - result = build1 (ADDR_EXPR, ptr_type_node, label); - /* The current function is not necessarily uninlinable. - Computed gotos are incompatible with inlining, but the value - here could be used only in a diagnostic, for example. */ - protected_set_expr_location (result, loc); - } - - return result; -} - - -/* Given a boolean expression ARG, return a tree representing an increment - or decrement (as indicated by CODE) of ARG. The front end must check for - invalid cases (e.g., decrement in C++). */ -tree -boolean_increment (enum tree_code code, tree arg) -{ - tree val; - tree true_res = build_int_cst (TREE_TYPE (arg), 1); - - arg = stabilize_reference (arg); - switch (code) - { - case PREINCREMENT_EXPR: - val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res); - break; - case POSTINCREMENT_EXPR: - val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res); - arg = save_expr (arg); - val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg); - val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val); - break; - case PREDECREMENT_EXPR: - val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, - invert_truthvalue_loc (input_location, arg)); - break; - case POSTDECREMENT_EXPR: - val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, - invert_truthvalue_loc (input_location, arg)); - arg = save_expr (arg); - val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg); - val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val); - break; - default: - gcc_unreachable (); - } - TREE_SIDE_EFFECTS (val) = 1; - return val; -} - -/* Built-in macros for stddef.h and stdint.h, that require macros - defined in this file. */ -void -c_stddef_cpp_builtins(void) -{ - builtin_define_with_value ("__SIZE_TYPE__", SIZE_TYPE, 0); - builtin_define_with_value ("__PTRDIFF_TYPE__", PTRDIFF_TYPE, 0); - builtin_define_with_value ("__WCHAR_TYPE__", MODIFIED_WCHAR_TYPE, 0); - builtin_define_with_value ("__WINT_TYPE__", WINT_TYPE, 0); - builtin_define_with_value ("__INTMAX_TYPE__", INTMAX_TYPE, 0); - builtin_define_with_value ("__UINTMAX_TYPE__", UINTMAX_TYPE, 0); - builtin_define_with_value ("__CHAR16_TYPE__", CHAR16_TYPE, 0); - builtin_define_with_value ("__CHAR32_TYPE__", CHAR32_TYPE, 0); - if (SIG_ATOMIC_TYPE) - builtin_define_with_value ("__SIG_ATOMIC_TYPE__", SIG_ATOMIC_TYPE, 0); - if (INT8_TYPE) - builtin_define_with_value ("__INT8_TYPE__", INT8_TYPE, 0); - if (INT16_TYPE) - builtin_define_with_value ("__INT16_TYPE__", INT16_TYPE, 0); - if (INT32_TYPE) - builtin_define_with_value ("__INT32_TYPE__", INT32_TYPE, 0); - if (INT64_TYPE) - builtin_define_with_value ("__INT64_TYPE__", INT64_TYPE, 0); - if (UINT8_TYPE) - builtin_define_with_value ("__UINT8_TYPE__", UINT8_TYPE, 0); - if (UINT16_TYPE) - builtin_define_with_value ("__UINT16_TYPE__", UINT16_TYPE, 0); - if (UINT32_TYPE) - builtin_define_with_value ("__UINT32_TYPE__", UINT32_TYPE, 0); - if (UINT64_TYPE) - builtin_define_with_value ("__UINT64_TYPE__", UINT64_TYPE, 0); - if (INT_LEAST8_TYPE) - builtin_define_with_value ("__INT_LEAST8_TYPE__", INT_LEAST8_TYPE, 0); - if (INT_LEAST16_TYPE) - builtin_define_with_value ("__INT_LEAST16_TYPE__", INT_LEAST16_TYPE, 0); - if (INT_LEAST32_TYPE) - builtin_define_with_value ("__INT_LEAST32_TYPE__", INT_LEAST32_TYPE, 0); - if (INT_LEAST64_TYPE) - builtin_define_with_value ("__INT_LEAST64_TYPE__", INT_LEAST64_TYPE, 0); - if (UINT_LEAST8_TYPE) - builtin_define_with_value ("__UINT_LEAST8_TYPE__", UINT_LEAST8_TYPE, 0); - if (UINT_LEAST16_TYPE) - builtin_define_with_value ("__UINT_LEAST16_TYPE__", UINT_LEAST16_TYPE, 0); - if (UINT_LEAST32_TYPE) - builtin_define_with_value ("__UINT_LEAST32_TYPE__", UINT_LEAST32_TYPE, 0); - if (UINT_LEAST64_TYPE) - builtin_define_with_value ("__UINT_LEAST64_TYPE__", UINT_LEAST64_TYPE, 0); - if (INT_FAST8_TYPE) - builtin_define_with_value ("__INT_FAST8_TYPE__", INT_FAST8_TYPE, 0); - if (INT_FAST16_TYPE) - builtin_define_with_value ("__INT_FAST16_TYPE__", INT_FAST16_TYPE, 0); - if (INT_FAST32_TYPE) - builtin_define_with_value ("__INT_FAST32_TYPE__", INT_FAST32_TYPE, 0); - if (INT_FAST64_TYPE) - builtin_define_with_value ("__INT_FAST64_TYPE__", INT_FAST64_TYPE, 0); - if (UINT_FAST8_TYPE) - builtin_define_with_value ("__UINT_FAST8_TYPE__", UINT_FAST8_TYPE, 0); - if (UINT_FAST16_TYPE) - builtin_define_with_value ("__UINT_FAST16_TYPE__", UINT_FAST16_TYPE, 0); - if (UINT_FAST32_TYPE) - builtin_define_with_value ("__UINT_FAST32_TYPE__", UINT_FAST32_TYPE, 0); - if (UINT_FAST64_TYPE) - builtin_define_with_value ("__UINT_FAST64_TYPE__", UINT_FAST64_TYPE, 0); - if (INTPTR_TYPE) - builtin_define_with_value ("__INTPTR_TYPE__", INTPTR_TYPE, 0); - if (UINTPTR_TYPE) - builtin_define_with_value ("__UINTPTR_TYPE__", UINTPTR_TYPE, 0); -} - -static void -c_init_attributes (void) -{ - /* Fill in the built_in_attributes array. */ -#define DEF_ATTR_NULL_TREE(ENUM) \ - built_in_attributes[(int) ENUM] = NULL_TREE; -#define DEF_ATTR_INT(ENUM, VALUE) \ - built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE); -#define DEF_ATTR_IDENT(ENUM, STRING) \ - built_in_attributes[(int) ENUM] = get_identifier (STRING); -#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \ - built_in_attributes[(int) ENUM] \ - = tree_cons (built_in_attributes[(int) PURPOSE], \ - built_in_attributes[(int) VALUE], \ - built_in_attributes[(int) CHAIN]); -#include "builtin-attrs.def" -#undef DEF_ATTR_NULL_TREE -#undef DEF_ATTR_INT -#undef DEF_ATTR_IDENT -#undef DEF_ATTR_TREE_LIST -} - -/* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain - identifier as an argument, so the front end shouldn't look it up. */ - -bool -attribute_takes_identifier_p (const_tree attr_id) -{ - if (is_attribute_p ("mode", attr_id) - || is_attribute_p ("format", attr_id) - || is_attribute_p ("cleanup", attr_id)) - return true; - else - return targetm.attribute_takes_identifier_p (attr_id); -} - -/* Attribute handlers common to C front ends. */ - -/* Handle a "packed" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_packed_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int flags, bool *no_add_attrs) -{ - if (TYPE_P (*node)) - { - if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *node = build_variant_type_copy (*node); - TYPE_PACKED (*node) = 1; - } - else if (TREE_CODE (*node) == FIELD_DECL) - { - if (TYPE_ALIGN (TREE_TYPE (*node)) <= BITS_PER_UNIT - /* Still pack bitfields. */ - && ! DECL_INITIAL (*node)) - warning (OPT_Wattributes, - "%qE attribute ignored for field of type %qT", - name, TREE_TYPE (*node)); - else - DECL_PACKED (*node) = 1; - } - /* We can't set DECL_PACKED for a VAR_DECL, because the bit is - used for DECL_REGISTER. It wouldn't mean anything anyway. - We can't set DECL_PACKED on the type of a TYPE_DECL, because - that changes what the typedef is typing. */ - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "nocommon" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_nocommon_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == VAR_DECL) - DECL_COMMON (*node) = 0; - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "common" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_common_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == VAR_DECL) - DECL_COMMON (*node) = 1; - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "noreturn" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - tree type = TREE_TYPE (*node); - - /* See FIXME comment in c_common_attribute_table. */ - if (TREE_CODE (*node) == FUNCTION_DECL) - TREE_THIS_VOLATILE (*node) = 1; - else if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) - TREE_TYPE (*node) - = build_pointer_type - (build_type_variant (TREE_TYPE (type), - TYPE_READONLY (TREE_TYPE (type)), 1)); - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "hot" and attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - { - if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL) - { - warning (OPT_Wattributes, "%qE attribute conflicts with attribute %s", - name, "cold"); - *no_add_attrs = true; - } - /* Most of the rest of the hot processing is done later with - lookup_attribute. */ - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} -/* Handle a "cold" and attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - { - if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL) - { - warning (OPT_Wattributes, "%qE attribute conflicts with attribute %s", - name, "hot"); - *no_add_attrs = true; - } - /* Most of the rest of the cold processing is done later with - lookup_attribute. */ - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "noinline" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_noinline_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - DECL_UNINLINABLE (*node) = 1; - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "noclone" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_noclone_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) != FUNCTION_DECL) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "always_inline" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_always_inline_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - { - /* Set the attribute and mark it for disregarding inline - limits. */ - DECL_DISREGARD_INLINE_LIMITS (*node) = 1; - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "gnu_inline" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_gnu_inline_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (*node)) - { - /* Do nothing else, just set the attribute. We'll get at - it later with lookup_attribute. */ - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle an "artificial" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_artificial_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (*node)) - { - /* Do nothing else, just set the attribute. We'll get at - it later with lookup_attribute. */ - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "flatten" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_flatten_attribute (tree *node, tree name, - tree args ATTRIBUTE_UNUSED, - int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - /* Do nothing else, just set the attribute. We'll get at - it later with lookup_attribute. */ - ; - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "warning" or "error" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_error_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL - || TREE_CODE (TREE_VALUE (args)) == STRING_CST) - /* Do nothing else, just set the attribute. We'll get at - it later with lookup_attribute. */ - ; - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "used" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - tree node = *pnode; - - if (TREE_CODE (node) == FUNCTION_DECL - || (TREE_CODE (node) == VAR_DECL && TREE_STATIC (node))) - { - TREE_USED (node) = 1; - DECL_PRESERVE_P (node) = 1; - if (TREE_CODE (node) == VAR_DECL) - DECL_READ_P (node) = 1; - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "unused" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int flags, bool *no_add_attrs) -{ - if (DECL_P (*node)) - { - tree decl = *node; - - if (TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == LABEL_DECL - || TREE_CODE (decl) == TYPE_DECL) - { - TREE_USED (decl) = 1; - if (TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == PARM_DECL) - DECL_READ_P (decl) = 1; - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - } - else - { - if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *node = build_variant_type_copy (*node); - TREE_USED (*node) = 1; - } - - return NULL_TREE; -} - -/* Handle a "externally_visible" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_externally_visible_attribute (tree *pnode, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - tree node = *pnode; - - if (TREE_CODE (node) == FUNCTION_DECL || TREE_CODE (node) == VAR_DECL) - { - if ((!TREE_STATIC (node) && TREE_CODE (node) != FUNCTION_DECL - && !DECL_EXTERNAL (node)) || !TREE_PUBLIC (node)) - { - warning (OPT_Wattributes, - "%qE attribute have effect only on public objects", name); - *no_add_attrs = true; - } - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "const" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - tree type = TREE_TYPE (*node); - - /* See FIXME comment on noreturn in c_common_attribute_table. */ - if (TREE_CODE (*node) == FUNCTION_DECL) - TREE_READONLY (*node) = 1; - else if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) - TREE_TYPE (*node) - = build_pointer_type - (build_type_variant (TREE_TYPE (type), 1, - TREE_THIS_VOLATILE (TREE_TYPE (type)))); - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "transparent_union" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_transparent_union_attribute (tree *node, tree name, - tree ARG_UNUSED (args), int flags, - bool *no_add_attrs) -{ - tree type; - - *no_add_attrs = true; - - if (TREE_CODE (*node) == TYPE_DECL) - node = &TREE_TYPE (*node); - type = *node; - - if (TREE_CODE (type) == UNION_TYPE) - { - /* When IN_PLACE is set, leave the check for FIELDS and MODE to - the code in finish_struct. */ - if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - { - if (TYPE_FIELDS (type) == NULL_TREE - || TYPE_MODE (type) != DECL_MODE (TYPE_FIELDS (type))) - goto ignored; - - /* A type variant isn't good enough, since we don't a cast - to such a type removed as a no-op. */ - *node = type = build_duplicate_type (type); - } - - TYPE_TRANSPARENT_AGGR (type) = 1; - return NULL_TREE; - } - - ignored: - warning (OPT_Wattributes, "%qE attribute ignored", name); - return NULL_TREE; -} - -/* Subroutine of handle_{con,de}structor_attribute. Evaluate ARGS to - get the requested priority for a constructor or destructor, - possibly issuing diagnostics for invalid or reserved - priorities. */ - -static priority_type -get_priority (tree args, bool is_destructor) -{ - HOST_WIDE_INT pri; - tree arg; - - if (!args) - return DEFAULT_INIT_PRIORITY; - - if (!SUPPORTS_INIT_PRIORITY) - { - if (is_destructor) - error ("destructor priorities are not supported"); - else - error ("constructor priorities are not supported"); - return DEFAULT_INIT_PRIORITY; - } - - arg = TREE_VALUE (args); - if (!host_integerp (arg, /*pos=*/0) - || !INTEGRAL_TYPE_P (TREE_TYPE (arg))) - goto invalid; - - pri = tree_low_cst (TREE_VALUE (args), /*pos=*/0); - if (pri < 0 || pri > MAX_INIT_PRIORITY) - goto invalid; - - if (pri <= MAX_RESERVED_INIT_PRIORITY) - { - if (is_destructor) - warning (0, - "destructor priorities from 0 to %d are reserved " - "for the implementation", - MAX_RESERVED_INIT_PRIORITY); - else - warning (0, - "constructor priorities from 0 to %d are reserved " - "for the implementation", - MAX_RESERVED_INIT_PRIORITY); - } - return pri; - - invalid: - if (is_destructor) - error ("destructor priorities must be integers from 0 to %d inclusive", - MAX_INIT_PRIORITY); - else - error ("constructor priorities must be integers from 0 to %d inclusive", - MAX_INIT_PRIORITY); - return DEFAULT_INIT_PRIORITY; -} - -/* Handle a "constructor" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_constructor_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - tree decl = *node; - tree type = TREE_TYPE (decl); - - if (TREE_CODE (decl) == FUNCTION_DECL - && TREE_CODE (type) == FUNCTION_TYPE - && decl_function_context (decl) == 0) - { - priority_type priority; - DECL_STATIC_CONSTRUCTOR (decl) = 1; - priority = get_priority (args, /*is_destructor=*/false); - SET_DECL_INIT_PRIORITY (decl, priority); - TREE_USED (decl) = 1; - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "destructor" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_destructor_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - tree decl = *node; - tree type = TREE_TYPE (decl); - - if (TREE_CODE (decl) == FUNCTION_DECL - && TREE_CODE (type) == FUNCTION_TYPE - && decl_function_context (decl) == 0) - { - priority_type priority; - DECL_STATIC_DESTRUCTOR (decl) = 1; - priority = get_priority (args, /*is_destructor=*/true); - SET_DECL_FINI_PRIORITY (decl, priority); - TREE_USED (decl) = 1; - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "mode" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_mode_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - tree type = *node; - tree ident = TREE_VALUE (args); - - *no_add_attrs = true; - - if (TREE_CODE (ident) != IDENTIFIER_NODE) - warning (OPT_Wattributes, "%qE attribute ignored", name); - else - { - int j; - const char *p = IDENTIFIER_POINTER (ident); - int len = strlen (p); - enum machine_mode mode = VOIDmode; - tree typefm; - bool valid_mode; - - if (len > 4 && p[0] == '_' && p[1] == '_' - && p[len - 1] == '_' && p[len - 2] == '_') - { - char *newp = (char *) alloca (len - 1); - - strcpy (newp, &p[2]); - newp[len - 4] = '\0'; - p = newp; - } - - /* Change this type to have a type with the specified mode. - First check for the special modes. */ - if (!strcmp (p, "byte")) - mode = byte_mode; - else if (!strcmp (p, "word")) - mode = word_mode; - else if (!strcmp (p, "pointer")) - mode = ptr_mode; - else if (!strcmp (p, "libgcc_cmp_return")) - mode = targetm.libgcc_cmp_return_mode (); - else if (!strcmp (p, "libgcc_shift_count")) - mode = targetm.libgcc_shift_count_mode (); - else if (!strcmp (p, "unwind_word")) - mode = targetm.unwind_word_mode (); - else - for (j = 0; j < NUM_MACHINE_MODES; j++) - if (!strcmp (p, GET_MODE_NAME (j))) - { - mode = (enum machine_mode) j; - break; - } - - if (mode == VOIDmode) - { - error ("unknown machine mode %qE", ident); - return NULL_TREE; - } - - valid_mode = false; - switch (GET_MODE_CLASS (mode)) - { - case MODE_INT: - case MODE_PARTIAL_INT: - case MODE_FLOAT: - case MODE_DECIMAL_FLOAT: - case MODE_FRACT: - case MODE_UFRACT: - case MODE_ACCUM: - case MODE_UACCUM: - valid_mode = targetm.scalar_mode_supported_p (mode); - break; - - case MODE_COMPLEX_INT: - case MODE_COMPLEX_FLOAT: - valid_mode = targetm.scalar_mode_supported_p (GET_MODE_INNER (mode)); - break; - - case MODE_VECTOR_INT: - case MODE_VECTOR_FLOAT: - case MODE_VECTOR_FRACT: - case MODE_VECTOR_UFRACT: - case MODE_VECTOR_ACCUM: - case MODE_VECTOR_UACCUM: - warning (OPT_Wattributes, "specifying vector types with " - "__attribute__ ((mode)) is deprecated"); - warning (OPT_Wattributes, - "use __attribute__ ((vector_size)) instead"); - valid_mode = vector_mode_valid_p (mode); - break; - - default: - break; - } - if (!valid_mode) - { - error ("unable to emulate %qs", p); - return NULL_TREE; - } - - if (POINTER_TYPE_P (type)) - { - addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type)); - tree (*fn)(tree, enum machine_mode, bool); - - if (!targetm.addr_space.valid_pointer_mode (mode, as)) - { - error ("invalid pointer mode %qs", p); - return NULL_TREE; - } - - if (TREE_CODE (type) == POINTER_TYPE) - fn = build_pointer_type_for_mode; - else - fn = build_reference_type_for_mode; - typefm = fn (TREE_TYPE (type), mode, false); - } - else - { - /* For fixed-point modes, we need to test if the signness of type - and the machine mode are consistent. */ - if (ALL_FIXED_POINT_MODE_P (mode) - && TYPE_UNSIGNED (type) != UNSIGNED_FIXED_POINT_MODE_P (mode)) - { - error ("signness of type and machine mode %qs don't match", p); - return NULL_TREE; - } - /* For fixed-point modes, we need to pass saturating info. */ - typefm = lang_hooks.types.type_for_mode (mode, - ALL_FIXED_POINT_MODE_P (mode) ? TYPE_SATURATING (type) - : TYPE_UNSIGNED (type)); - } - - if (typefm == NULL_TREE) - { - error ("no data type for mode %qs", p); - return NULL_TREE; - } - else if (TREE_CODE (type) == ENUMERAL_TYPE) - { - /* For enumeral types, copy the precision from the integer - type returned above. If not an INTEGER_TYPE, we can't use - this mode for this type. */ - if (TREE_CODE (typefm) != INTEGER_TYPE) - { - error ("cannot use mode %qs for enumeral types", p); - return NULL_TREE; - } - - if (flags & ATTR_FLAG_TYPE_IN_PLACE) - { - TYPE_PRECISION (type) = TYPE_PRECISION (typefm); - typefm = type; - } - else - { - /* We cannot build a type variant, as there's code that assumes - that TYPE_MAIN_VARIANT has the same mode. This includes the - debug generators. Instead, create a subrange type. This - results in all of the enumeral values being emitted only once - in the original, and the subtype gets them by reference. */ - if (TYPE_UNSIGNED (type)) - typefm = make_unsigned_type (TYPE_PRECISION (typefm)); - else - typefm = make_signed_type (TYPE_PRECISION (typefm)); - TREE_TYPE (typefm) = type; - } - } - else if (VECTOR_MODE_P (mode) - ? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm)) - : TREE_CODE (type) != TREE_CODE (typefm)) - { - error ("mode %qs applied to inappropriate type", p); - return NULL_TREE; - } - - *node = typefm; - } - - return NULL_TREE; -} - -/* Handle a "section" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - tree decl = *node; - - if (targetm.have_named_sections) - { - user_defined_section_attribute = true; - - if ((TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == VAR_DECL) - && TREE_CODE (TREE_VALUE (args)) == STRING_CST) - { - if (TREE_CODE (decl) == VAR_DECL - && current_function_decl != NULL_TREE - && !TREE_STATIC (decl)) - { - error_at (DECL_SOURCE_LOCATION (decl), - "section attribute cannot be specified for " - "local variables"); - *no_add_attrs = true; - } - - /* The decl may have already been given a section attribute - from a previous declaration. Ensure they match. */ - else if (DECL_SECTION_NAME (decl) != NULL_TREE - && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), - TREE_STRING_POINTER (TREE_VALUE (args))) != 0) - { - error ("section of %q+D conflicts with previous declaration", - *node); - *no_add_attrs = true; - } - else if (TREE_CODE (decl) == VAR_DECL - && !targetm.have_tls && targetm.emutls.tmpl_section - && DECL_THREAD_LOCAL_P (decl)) - { - error ("section of %q+D cannot be overridden", *node); - *no_add_attrs = true; - } - else - DECL_SECTION_NAME (decl) = TREE_VALUE (args); - } - else - { - error ("section attribute not allowed for %q+D", *node); - *no_add_attrs = true; - } - } - else - { - error_at (DECL_SOURCE_LOCATION (*node), - "section attributes are not supported for this target"); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "aligned" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, - int flags, bool *no_add_attrs) -{ - tree decl = NULL_TREE; - tree *type = NULL; - int is_type = 0; - tree align_expr = (args ? TREE_VALUE (args) - : size_int (ATTRIBUTE_ALIGNED_VALUE / BITS_PER_UNIT)); - int i; - - if (DECL_P (*node)) - { - decl = *node; - type = &TREE_TYPE (decl); - is_type = TREE_CODE (*node) == TYPE_DECL; - } - else if (TYPE_P (*node)) - type = node, is_type = 1; - - if (TREE_CODE (align_expr) != INTEGER_CST) - { - error ("requested alignment is not a constant"); - *no_add_attrs = true; - } - else if ((i = tree_log2 (align_expr)) == -1) - { - error ("requested alignment is not a power of 2"); - *no_add_attrs = true; - } - else if (i >= HOST_BITS_PER_INT - BITS_PER_UNIT_LOG) - { - error ("requested alignment is too large"); - *no_add_attrs = true; - } - else if (is_type) - { - if ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - /* OK, modify the type in place. */; - /* If we have a TYPE_DECL, then copy the type, so that we - don't accidentally modify a builtin type. See pushdecl. */ - else if (decl && TREE_TYPE (decl) != error_mark_node - && DECL_ORIGINAL_TYPE (decl) == NULL_TREE) - { - tree tt = TREE_TYPE (decl); - *type = build_variant_type_copy (*type); - DECL_ORIGINAL_TYPE (decl) = tt; - TYPE_NAME (*type) = decl; - TREE_USED (*type) = TREE_USED (decl); - TREE_TYPE (decl) = *type; - } - else - *type = build_variant_type_copy (*type); - - TYPE_ALIGN (*type) = (1U << i) * BITS_PER_UNIT; - TYPE_USER_ALIGN (*type) = 1; - } - else if (! VAR_OR_FUNCTION_DECL_P (decl) - && TREE_CODE (decl) != FIELD_DECL) - { - error ("alignment may not be specified for %q+D", decl); - *no_add_attrs = true; - } - else if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) - { - if (DECL_USER_ALIGN (decl)) - error ("alignment for %q+D was previously specified as %d " - "and may not be decreased", decl, - DECL_ALIGN (decl) / BITS_PER_UNIT); - else - error ("alignment for %q+D must be at least %d", decl, - DECL_ALIGN (decl) / BITS_PER_UNIT); - *no_add_attrs = true; - } - else - { - DECL_ALIGN (decl) = (1U << i) * BITS_PER_UNIT; - DECL_USER_ALIGN (decl) = 1; - } - - return NULL_TREE; -} - -/* Handle a "weak" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_weak_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), - bool * ARG_UNUSED (no_add_attrs)) -{ - if (TREE_CODE (*node) == FUNCTION_DECL - && DECL_DECLARED_INLINE_P (*node)) - { - error ("inline function %q+D cannot be declared weak", *node); - *no_add_attrs = true; - } - else if (TREE_CODE (*node) == FUNCTION_DECL - || TREE_CODE (*node) == VAR_DECL) - declare_weak (*node); - else - warning (OPT_Wattributes, "%qE attribute ignored", name); - - return NULL_TREE; -} - -/* Handle an "alias" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_alias_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - tree decl = *node; - - if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) - || (TREE_CODE (decl) != FUNCTION_DECL - && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) - /* A static variable declaration is always a tentative definition, - but the alias is a non-tentative definition which overrides. */ - || (TREE_CODE (decl) != FUNCTION_DECL - && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl))) - { - error ("%q+D defined both normally and as an alias", decl); - *no_add_attrs = true; - } - - /* Note that the very first time we process a nested declaration, - decl_function_context will not be set. Indeed, *would* never - be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that - we do below. After such frobbery, pushdecl would set the context. - In any case, this is never what we want. */ - else if (decl_function_context (decl) == 0 && current_function_decl == NULL) - { - tree id; - - id = TREE_VALUE (args); - if (TREE_CODE (id) != STRING_CST) - { - error ("alias argument not a string"); - *no_add_attrs = true; - return NULL_TREE; - } - id = get_identifier (TREE_STRING_POINTER (id)); - /* This counts as a use of the object pointed to. */ - TREE_USED (id) = 1; - - if (TREE_CODE (decl) == FUNCTION_DECL) - DECL_INITIAL (decl) = error_mark_node; - else - { - if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))) - DECL_EXTERNAL (decl) = 1; - else - DECL_EXTERNAL (decl) = 0; - TREE_STATIC (decl) = 1; - } - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "weakref" attribute; arguments as in struct - attribute_spec.handler. */ - -static tree -handle_weakref_attribute (tree *node, tree ARG_UNUSED (name), tree args, - int flags, bool *no_add_attrs) -{ - tree attr = NULL_TREE; - - /* We must ignore the attribute when it is associated with - local-scoped decls, since attribute alias is ignored and many - such symbols do not even have a DECL_WEAK field. */ - if (decl_function_context (*node) - || current_function_decl - || (TREE_CODE (*node) != VAR_DECL && TREE_CODE (*node) != FUNCTION_DECL)) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - return NULL_TREE; - } - - /* The idea here is that `weakref("name")' mutates into `weakref, - alias("name")', and weakref without arguments, in turn, - implicitly adds weak. */ - - if (args) - { - attr = tree_cons (get_identifier ("alias"), args, attr); - attr = tree_cons (get_identifier ("weakref"), NULL_TREE, attr); - - *no_add_attrs = true; - - decl_attributes (node, attr, flags); - } - else - { - if (lookup_attribute ("alias", DECL_ATTRIBUTES (*node))) - error_at (DECL_SOURCE_LOCATION (*node), - "weakref attribute must appear before alias attribute"); - - /* Can't call declare_weak because it wants this to be TREE_PUBLIC, - and that isn't supported; and because it wants to add it to - the list of weak decls, which isn't helpful. */ - DECL_WEAK (*node) = 1; - } - - return NULL_TREE; -} - -/* Handle an "visibility" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_visibility_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), - bool *ARG_UNUSED (no_add_attrs)) -{ - tree decl = *node; - tree id = TREE_VALUE (args); - enum symbol_visibility vis; - - if (TYPE_P (*node)) - { - if (TREE_CODE (*node) == ENUMERAL_TYPE) - /* OK */; - else if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE) - { - warning (OPT_Wattributes, "%qE attribute ignored on non-class types", - name); - return NULL_TREE; - } - else if (TYPE_FIELDS (*node)) - { - error ("%qE attribute ignored because %qT is already defined", - name, *node); - return NULL_TREE; - } - } - else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl)) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - return NULL_TREE; - } - - if (TREE_CODE (id) != STRING_CST) - { - error ("visibility argument not a string"); - return NULL_TREE; - } - - /* If this is a type, set the visibility on the type decl. */ - if (TYPE_P (decl)) - { - decl = TYPE_NAME (decl); - if (!decl) - return NULL_TREE; - if (TREE_CODE (decl) == IDENTIFIER_NODE) - { - warning (OPT_Wattributes, "%qE attribute ignored on types", - name); - return NULL_TREE; - } - } - - if (strcmp (TREE_STRING_POINTER (id), "default") == 0) - vis = VISIBILITY_DEFAULT; - else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0) - vis = VISIBILITY_INTERNAL; - else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0) - vis = VISIBILITY_HIDDEN; - else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0) - vis = VISIBILITY_PROTECTED; - else - { - error ("visibility argument must be one of \"default\", \"hidden\", \"protected\" or \"internal\""); - vis = VISIBILITY_DEFAULT; - } - - if (DECL_VISIBILITY_SPECIFIED (decl) - && vis != DECL_VISIBILITY (decl)) - { - tree attributes = (TYPE_P (*node) - ? TYPE_ATTRIBUTES (*node) - : DECL_ATTRIBUTES (decl)); - if (lookup_attribute ("visibility", attributes)) - error ("%qD redeclared with different visibility", decl); - else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES - && lookup_attribute ("dllimport", attributes)) - error ("%qD was declared %qs which implies default visibility", - decl, "dllimport"); - else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES - && lookup_attribute ("dllexport", attributes)) - error ("%qD was declared %qs which implies default visibility", - decl, "dllexport"); - } - - DECL_VISIBILITY (decl) = vis; - DECL_VISIBILITY_SPECIFIED (decl) = 1; - - /* Go ahead and attach the attribute to the node as well. This is needed - so we can determine whether we have VISIBILITY_DEFAULT because the - visibility was not specified, or because it was explicitly overridden - from the containing scope. */ - - return NULL_TREE; -} - -/* Determine the ELF symbol visibility for DECL, which is either a - variable or a function. It is an error to use this function if a - definition of DECL is not available in this translation unit. - Returns true if the final visibility has been determined by this - function; false if the caller is free to make additional - modifications. */ - -bool -c_determine_visibility (tree decl) -{ - gcc_assert (TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL); - - /* If the user explicitly specified the visibility with an - attribute, honor that. DECL_VISIBILITY will have been set during - the processing of the attribute. We check for an explicit - attribute, rather than just checking DECL_VISIBILITY_SPECIFIED, - to distinguish the use of an attribute from the use of a "#pragma - GCC visibility push(...)"; in the latter case we still want other - considerations to be able to overrule the #pragma. */ - if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)) - || (TARGET_DLLIMPORT_DECL_ATTRIBUTES - && (lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)) - || lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))))) - return true; - - /* Set default visibility to whatever the user supplied with - visibility_specified depending on #pragma GCC visibility. */ - if (!DECL_VISIBILITY_SPECIFIED (decl)) - { - if (visibility_options.inpragma - || DECL_VISIBILITY (decl) != default_visibility) - { - DECL_VISIBILITY (decl) = default_visibility; - DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma; - /* If visibility changed and DECL already has DECL_RTL, ensure - symbol flags are updated. */ - if (((TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) - || TREE_CODE (decl) == FUNCTION_DECL) - && DECL_RTL_SET_P (decl)) - make_decl_rtl (decl); - } - } - return false; -} - -/* Handle an "tls_model" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_tls_model_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - tree id; - tree decl = *node; - enum tls_model kind; - - *no_add_attrs = true; - - if (TREE_CODE (decl) != VAR_DECL || !DECL_THREAD_LOCAL_P (decl)) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - return NULL_TREE; - } - - kind = DECL_TLS_MODEL (decl); - id = TREE_VALUE (args); - if (TREE_CODE (id) != STRING_CST) - { - error ("tls_model argument not a string"); - return NULL_TREE; - } - - if (!strcmp (TREE_STRING_POINTER (id), "local-exec")) - kind = TLS_MODEL_LOCAL_EXEC; - else if (!strcmp (TREE_STRING_POINTER (id), "initial-exec")) - kind = TLS_MODEL_INITIAL_EXEC; - else if (!strcmp (TREE_STRING_POINTER (id), "local-dynamic")) - kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC; - else if (!strcmp (TREE_STRING_POINTER (id), "global-dynamic")) - kind = TLS_MODEL_GLOBAL_DYNAMIC; - else - error ("tls_model argument must be one of \"local-exec\", \"initial-exec\", \"local-dynamic\" or \"global-dynamic\""); - - DECL_TLS_MODEL (decl) = kind; - return NULL_TREE; -} - -/* Handle a "no_instrument_function" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_no_instrument_function_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - tree decl = *node; - - if (TREE_CODE (decl) != FUNCTION_DECL) - { - error_at (DECL_SOURCE_LOCATION (decl), - "%qE attribute applies only to functions", name); - *no_add_attrs = true; - } - else if (DECL_INITIAL (decl)) - { - error_at (DECL_SOURCE_LOCATION (decl), - "can%'t set %qE attribute after definition", name); - *no_add_attrs = true; - } - else - DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; - - return NULL_TREE; -} - -/* Handle a "malloc" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL - && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))) - DECL_IS_MALLOC (*node) = 1; - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "alloc_size" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - unsigned arg_count = type_num_arguments (*node); - for (; args; args = TREE_CHAIN (args)) - { - tree position = TREE_VALUE (args); - - if (TREE_CODE (position) != INTEGER_CST - || TREE_INT_CST_HIGH (position) - || TREE_INT_CST_LOW (position) < 1 - || TREE_INT_CST_LOW (position) > arg_count ) - { - warning (OPT_Wattributes, - "alloc_size parameter outside range"); - *no_add_attrs = true; - return NULL_TREE; - } - } - return NULL_TREE; -} - -/* Handle a "fn spec" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name), - tree args, int ARG_UNUSED (flags), - bool *no_add_attrs ATTRIBUTE_UNUSED) -{ - gcc_assert (args - && TREE_CODE (TREE_VALUE (args)) == STRING_CST - && !TREE_CHAIN (args)); - return NULL_TREE; -} - -/* Handle a "returns_twice" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_returns_twice_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - DECL_IS_RETURNS_TWICE (*node) = 1; - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "no_limit_stack" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_no_limit_stack_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - tree decl = *node; - - if (TREE_CODE (decl) != FUNCTION_DECL) - { - error_at (DECL_SOURCE_LOCATION (decl), - "%qE attribute applies only to functions", name); - *no_add_attrs = true; - } - else if (DECL_INITIAL (decl)) - { - error_at (DECL_SOURCE_LOCATION (decl), - "can%'t set %qE attribute after definition", name); - *no_add_attrs = true; - } - else - DECL_NO_LIMIT_STACK (decl) = 1; - - return NULL_TREE; -} - -/* Handle a "pure" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - DECL_PURE_P (*node) = 1; - /* ??? TODO: Support types. */ - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "no vops" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_novops_attribute (tree *node, tree ARG_UNUSED (name), - tree ARG_UNUSED (args), int ARG_UNUSED (flags), - bool *ARG_UNUSED (no_add_attrs)) -{ - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); - DECL_IS_NOVOPS (*node) = 1; - return NULL_TREE; -} - -/* Handle a "deprecated" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_deprecated_attribute (tree *node, tree name, - tree args, int flags, - bool *no_add_attrs) -{ - tree type = NULL_TREE; - int warn = 0; - tree what = NULL_TREE; - - if (!args) - *no_add_attrs = true; - else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) - { - error ("deprecated message is not a string"); - *no_add_attrs = true; - } - - if (DECL_P (*node)) - { - tree decl = *node; - type = TREE_TYPE (decl); - - if (TREE_CODE (decl) == TYPE_DECL - || TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == FIELD_DECL) - TREE_DEPRECATED (decl) = 1; - else - warn = 1; - } - else if (TYPE_P (*node)) - { - if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *node = build_variant_type_copy (*node); - TREE_DEPRECATED (*node) = 1; - type = *node; - } - else - warn = 1; - - if (warn) - { - *no_add_attrs = true; - if (type && TYPE_NAME (type)) - { - if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) - what = TYPE_NAME (*node); - else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (type))) - what = DECL_NAME (TYPE_NAME (type)); - } - if (what) - warning (OPT_Wattributes, "%qE attribute ignored for %qE", name, what); - else - warning (OPT_Wattributes, "%qE attribute ignored", name); - } - - return NULL_TREE; -} - -/* Handle a "vector_size" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_vector_size_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - unsigned HOST_WIDE_INT vecsize, nunits; - enum machine_mode orig_mode; - tree type = *node, new_type, size; - - *no_add_attrs = true; - - size = TREE_VALUE (args); - - if (!host_integerp (size, 1)) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - return NULL_TREE; - } - - /* Get the vector size (in bytes). */ - vecsize = tree_low_cst (size, 1); - - /* We need to provide for vector pointers, vector arrays, and - functions returning vectors. For example: - - __attribute__((vector_size(16))) short *foo; - - In this case, the mode is SI, but the type being modified is - HI, so we need to look further. */ - - while (POINTER_TYPE_P (type) - || TREE_CODE (type) == FUNCTION_TYPE - || TREE_CODE (type) == METHOD_TYPE - || TREE_CODE (type) == ARRAY_TYPE - || TREE_CODE (type) == OFFSET_TYPE) - type = TREE_TYPE (type); - - /* Get the mode of the type being modified. */ - orig_mode = TYPE_MODE (type); - - if ((!INTEGRAL_TYPE_P (type) - && !SCALAR_FLOAT_TYPE_P (type) - && !FIXED_POINT_TYPE_P (type)) - || (!SCALAR_FLOAT_MODE_P (orig_mode) - && GET_MODE_CLASS (orig_mode) != MODE_INT - && !ALL_SCALAR_FIXED_POINT_MODE_P (orig_mode)) - || !host_integerp (TYPE_SIZE_UNIT (type), 1) - || TREE_CODE (type) == BOOLEAN_TYPE) - { - error ("invalid vector type for attribute %qE", name); - return NULL_TREE; - } - - if (vecsize % tree_low_cst (TYPE_SIZE_UNIT (type), 1)) - { - error ("vector size not an integral multiple of component size"); - return NULL; - } - - if (vecsize == 0) - { - error ("zero vector size"); - return NULL; - } - - /* Calculate how many units fit in the vector. */ - nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1); - if (nunits & (nunits - 1)) - { - error ("number of components of the vector not a power of two"); - return NULL_TREE; - } - - new_type = build_vector_type (type, nunits); - - /* Build back pointers if needed. */ - *node = lang_hooks.types.reconstruct_complex_type (*node, new_type); - - return NULL_TREE; -} - -/* Handle the "nonnull" attribute. */ -static tree -handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), - tree args, int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - tree type = *node; - unsigned HOST_WIDE_INT attr_arg_num; - - /* If no arguments are specified, all pointer arguments should be - non-null. Verify a full prototype is given so that the arguments - will have the correct types when we actually check them later. */ - if (!args) - { - if (!TYPE_ARG_TYPES (type)) - { - error ("nonnull attribute without arguments on a non-prototype"); - *no_add_attrs = true; - } - return NULL_TREE; - } - - /* Argument list specified. Verify that each argument number references - a pointer argument. */ - for (attr_arg_num = 1; args; args = TREE_CHAIN (args)) - { - tree argument; - unsigned HOST_WIDE_INT arg_num = 0, ck_num; - - if (!get_nonnull_operand (TREE_VALUE (args), &arg_num)) - { - error ("nonnull argument has invalid operand number (argument %lu)", - (unsigned long) attr_arg_num); - *no_add_attrs = true; - return NULL_TREE; - } - - argument = TYPE_ARG_TYPES (type); - if (argument) - { - for (ck_num = 1; ; ck_num++) - { - if (!argument || ck_num == arg_num) - break; - argument = TREE_CHAIN (argument); - } - - if (!argument - || TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE) - { - error ("nonnull argument with out-of-range operand number (argument %lu, operand %lu)", - (unsigned long) attr_arg_num, (unsigned long) arg_num); - *no_add_attrs = true; - return NULL_TREE; - } - - if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE) - { - error ("nonnull argument references non-pointer operand (argument %lu, operand %lu)", - (unsigned long) attr_arg_num, (unsigned long) arg_num); - *no_add_attrs = true; - return NULL_TREE; - } - } - } - - return NULL_TREE; -} - -/* Check the argument list of a function call for null in argument slots - that are marked as requiring a non-null pointer argument. The NARGS - arguments are passed in the array ARGARRAY. -*/ - -static void -check_function_nonnull (tree attrs, int nargs, tree *argarray) -{ - tree a, args; - int i; - - for (a = attrs; a; a = TREE_CHAIN (a)) - { - if (is_attribute_p ("nonnull", TREE_PURPOSE (a))) - { - args = TREE_VALUE (a); - - /* Walk the argument list. If we encounter an argument number we - should check for non-null, do it. If the attribute has no args, - then every pointer argument is checked (in which case the check - for pointer type is done in check_nonnull_arg). */ - for (i = 0; i < nargs; i++) - { - if (!args || nonnull_check_p (args, i + 1)) - check_function_arguments_recurse (check_nonnull_arg, NULL, - argarray[i], - i + 1); - } - } - } -} - -/* Check that the Nth argument of a function call (counting backwards - from the end) is a (pointer)0. The NARGS arguments are passed in the - array ARGARRAY. */ - -static void -check_function_sentinel (tree attrs, int nargs, tree *argarray, tree typelist) -{ - tree attr = lookup_attribute ("sentinel", attrs); - - if (attr) - { - int len = 0; - int pos = 0; - tree sentinel; - - /* Skip over the named arguments. */ - while (typelist && len < nargs) - { - typelist = TREE_CHAIN (typelist); - len++; - } - - if (TREE_VALUE (attr)) - { - tree p = TREE_VALUE (TREE_VALUE (attr)); - pos = TREE_INT_CST_LOW (p); - } - - /* The sentinel must be one of the varargs, i.e. - in position >= the number of fixed arguments. */ - if ((nargs - 1 - pos) < len) - { - warning (OPT_Wformat, - "not enough variable arguments to fit a sentinel"); - return; - } - - /* Validate the sentinel. */ - sentinel = argarray[nargs - 1 - pos]; - if ((!POINTER_TYPE_P (TREE_TYPE (sentinel)) - || !integer_zerop (sentinel)) - /* Although __null (in C++) is only an integer we allow it - nevertheless, as we are guaranteed that it's exactly - as wide as a pointer, and we don't want to force - users to cast the NULL they have written there. - We warn with -Wstrict-null-sentinel, though. */ - && (warn_strict_null_sentinel || null_node != sentinel)) - warning (OPT_Wformat, "missing sentinel in function call"); - } -} - -/* Helper for check_function_nonnull; given a list of operands which - must be non-null in ARGS, determine if operand PARAM_NUM should be - checked. */ - -static bool -nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num) -{ - unsigned HOST_WIDE_INT arg_num = 0; - - for (; args; args = TREE_CHAIN (args)) - { - bool found = get_nonnull_operand (TREE_VALUE (args), &arg_num); - - gcc_assert (found); - - if (arg_num == param_num) - return true; - } - return false; -} - -/* Check that the function argument PARAM (which is operand number - PARAM_NUM) is non-null. This is called by check_function_nonnull - via check_function_arguments_recurse. */ - -static void -check_nonnull_arg (void * ARG_UNUSED (ctx), tree param, - unsigned HOST_WIDE_INT param_num) -{ - /* Just skip checking the argument if it's not a pointer. This can - happen if the "nonnull" attribute was given without an operand - list (which means to check every pointer argument). */ - - if (TREE_CODE (TREE_TYPE (param)) != POINTER_TYPE) - return; - - if (integer_zerop (param)) - warning (OPT_Wnonnull, "null argument where non-null required " - "(argument %lu)", (unsigned long) param_num); -} - -/* Helper for nonnull attribute handling; fetch the operand number - from the attribute argument list. */ - -static bool -get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp) -{ - /* Verify the arg number is a constant. */ - if (TREE_CODE (arg_num_expr) != INTEGER_CST - || TREE_INT_CST_HIGH (arg_num_expr) != 0) - return false; - - *valp = TREE_INT_CST_LOW (arg_num_expr); - return true; -} - -/* Handle a "nothrow" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_nothrow_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - TREE_NOTHROW (*node) = 1; - /* ??? TODO: Support types. */ - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "cleanup" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_cleanup_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - tree decl = *node; - tree cleanup_id, cleanup_decl; - - /* ??? Could perhaps support cleanups on TREE_STATIC, much like we do - for global destructors in C++. This requires infrastructure that - we don't have generically at the moment. It's also not a feature - we'd be missing too much, since we do have attribute constructor. */ - if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl)) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - return NULL_TREE; - } - - /* Verify that the argument is a function in scope. */ - /* ??? We could support pointers to functions here as well, if - that was considered desirable. */ - cleanup_id = TREE_VALUE (args); - if (TREE_CODE (cleanup_id) != IDENTIFIER_NODE) - { - error ("cleanup argument not an identifier"); - *no_add_attrs = true; - return NULL_TREE; - } - cleanup_decl = lookup_name (cleanup_id); - if (!cleanup_decl || TREE_CODE (cleanup_decl) != FUNCTION_DECL) - { - error ("cleanup argument not a function"); - *no_add_attrs = true; - return NULL_TREE; - } - - /* That the function has proper type is checked with the - eventual call to build_function_call. */ - - return NULL_TREE; -} - -/* Handle a "warn_unused_result" attribute. No special handling. */ - -static tree -handle_warn_unused_result_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - /* Ignore the attribute for functions not returning any value. */ - if (VOID_TYPE_P (TREE_TYPE (*node))) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "sentinel" attribute. */ - -static tree -handle_sentinel_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - tree params = TYPE_ARG_TYPES (*node); - - if (!params) - { - warning (OPT_Wattributes, - "%qE attribute requires prototypes with named arguments", name); - *no_add_attrs = true; - } - else - { - while (TREE_CHAIN (params)) - params = TREE_CHAIN (params); - - if (VOID_TYPE_P (TREE_VALUE (params))) - { - warning (OPT_Wattributes, - "%qE attribute only applies to variadic functions", name); - *no_add_attrs = true; - } - } - - if (args) - { - tree position = TREE_VALUE (args); - - if (TREE_CODE (position) != INTEGER_CST) - { - warning (OPT_Wattributes, - "requested position is not an integer constant"); - *no_add_attrs = true; - } - else - { - if (tree_int_cst_lt (position, integer_zero_node)) - { - warning (OPT_Wattributes, - "requested position is less than zero"); - *no_add_attrs = true; - } - } - } - - return NULL_TREE; -} - -/* Handle a "type_generic" attribute. */ - -static tree -handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name), - tree ARG_UNUSED (args), int ARG_UNUSED (flags), - bool * ARG_UNUSED (no_add_attrs)) -{ - tree params; - - /* Ensure we have a function type. */ - gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); - - params = TYPE_ARG_TYPES (*node); - while (params && ! VOID_TYPE_P (TREE_VALUE (params))) - params = TREE_CHAIN (params); - - /* Ensure we have a variadic function. */ - gcc_assert (!params); - - return NULL_TREE; -} - -/* Handle a "target" attribute. */ - -static tree -handle_target_attribute (tree *node, tree name, tree args, int flags, - bool *no_add_attrs) -{ - /* Ensure we have a function type. */ - if (TREE_CODE (*node) != FUNCTION_DECL) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - else if (! targetm.target_option.valid_attribute_p (*node, name, args, - flags)) - *no_add_attrs = true; - - return NULL_TREE; -} - -/* Arguments being collected for optimization. */ -typedef const char *const_char_p; /* For DEF_VEC_P. */ -DEF_VEC_P(const_char_p); -DEF_VEC_ALLOC_P(const_char_p, gc); -static GTY(()) VEC(const_char_p, gc) *optimize_args; - - -/* Inner function to convert a TREE_LIST to argv string to parse the optimize - options in ARGS. ATTR_P is true if this is for attribute(optimize), and - false for #pragma GCC optimize. */ - -bool -parse_optimize_options (tree args, bool attr_p) -{ - bool ret = true; - unsigned opt_argc; - unsigned i; - int saved_flag_strict_aliasing; - const char **opt_argv; - tree ap; - - /* Build up argv vector. Just in case the string is stored away, use garbage - collected strings. */ - VEC_truncate (const_char_p, optimize_args, 0); - VEC_safe_push (const_char_p, gc, optimize_args, NULL); - - for (ap = args; ap != NULL_TREE; ap = TREE_CHAIN (ap)) - { - tree value = TREE_VALUE (ap); - - if (TREE_CODE (value) == INTEGER_CST) - { - char buffer[20]; - sprintf (buffer, "-O%ld", (long) TREE_INT_CST_LOW (value)); - VEC_safe_push (const_char_p, gc, optimize_args, ggc_strdup (buffer)); - } - - else if (TREE_CODE (value) == STRING_CST) - { - /* Split string into multiple substrings. */ - size_t len = TREE_STRING_LENGTH (value); - char *p = ASTRDUP (TREE_STRING_POINTER (value)); - char *end = p + len; - char *comma; - char *next_p = p; - - while (next_p != NULL) - { - size_t len2; - char *q, *r; - - p = next_p; - comma = strchr (p, ','); - if (comma) - { - len2 = comma - p; - *comma = '\0'; - next_p = comma+1; - } - else - { - len2 = end - p; - next_p = NULL; - } - - r = q = (char *) ggc_alloc (len2 + 3); - - /* If the user supplied -Oxxx or -fxxx, only allow -Oxxx or -fxxx - options. */ - if (*p == '-' && p[1] != 'O' && p[1] != 'f') - { - ret = false; - if (attr_p) - warning (OPT_Wattributes, - "Bad option %s to optimize attribute.", p); - else - warning (OPT_Wpragmas, - "Bad option %s to pragma attribute", p); - continue; - } - - if (*p != '-') - { - *r++ = '-'; - - /* Assume that Ox is -Ox, a numeric value is -Ox, a s by - itself is -Os, and any other switch begins with a -f. */ - if ((*p >= '0' && *p <= '9') - || (p[0] == 's' && p[1] == '\0')) - *r++ = 'O'; - else if (*p != 'O') - *r++ = 'f'; - } - - memcpy (r, p, len2); - r[len2] = '\0'; - VEC_safe_push (const_char_p, gc, optimize_args, q); - } - - } - } - - opt_argc = VEC_length (const_char_p, optimize_args); - opt_argv = (const char **) alloca (sizeof (char *) * (opt_argc + 1)); - - for (i = 1; i < opt_argc; i++) - opt_argv[i] = VEC_index (const_char_p, optimize_args, i); - - saved_flag_strict_aliasing = flag_strict_aliasing; - - /* Now parse the options. */ - decode_options (opt_argc, opt_argv); - - targetm.override_options_after_change(); - - /* Don't allow changing -fstrict-aliasing. */ - flag_strict_aliasing = saved_flag_strict_aliasing; - - VEC_truncate (const_char_p, optimize_args, 0); - return ret; -} - -/* For handling "optimize" attribute. arguments as in - struct attribute_spec.handler. */ - -static tree -handle_optimize_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - /* Ensure we have a function type. */ - if (TREE_CODE (*node) != FUNCTION_DECL) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - else - { - struct cl_optimization cur_opts; - tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node); - - /* Save current options. */ - cl_optimization_save (&cur_opts); - - /* If we previously had some optimization options, use them as the - default. */ - if (old_opts) - cl_optimization_restore (TREE_OPTIMIZATION (old_opts)); - - /* Parse options, and update the vector. */ - parse_optimize_options (args, true); - DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) - = build_optimization_node (); - - /* Restore current options. */ - cl_optimization_restore (&cur_opts); - } - - return NULL_TREE; -} - -/* Check for valid arguments being passed to a function. - ATTRS is a list of attributes. There are NARGS arguments in the array - ARGARRAY. TYPELIST is the list of argument types for the function. - */ -void -check_function_arguments (tree attrs, int nargs, tree *argarray, tree typelist) -{ - /* Check for null being passed in a pointer argument that must be - non-null. We also need to do this if format checking is enabled. */ - - if (warn_nonnull) - check_function_nonnull (attrs, nargs, argarray); - - /* Check for errors in format strings. */ - - if (warn_format || warn_missing_format_attribute) - check_function_format (attrs, nargs, argarray); - - if (warn_format) - check_function_sentinel (attrs, nargs, argarray, typelist); -} - -/* Generic argument checking recursion routine. PARAM is the argument to - be checked. PARAM_NUM is the number of the argument. CALLBACK is invoked - once the argument is resolved. CTX is context for the callback. */ -void -check_function_arguments_recurse (void (*callback) - (void *, tree, unsigned HOST_WIDE_INT), - void *ctx, tree param, - unsigned HOST_WIDE_INT param_num) -{ - if (CONVERT_EXPR_P (param) - && (TYPE_PRECISION (TREE_TYPE (param)) - == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (param, 0))))) - { - /* Strip coercion. */ - check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 0), param_num); - return; - } - - if (TREE_CODE (param) == CALL_EXPR) - { - tree type = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (param))); - tree attrs; - bool found_format_arg = false; - - /* See if this is a call to a known internationalization function - that modifies a format arg. Such a function may have multiple - format_arg attributes (for example, ngettext). */ - - for (attrs = TYPE_ATTRIBUTES (type); - attrs; - attrs = TREE_CHAIN (attrs)) - if (is_attribute_p ("format_arg", TREE_PURPOSE (attrs))) - { - tree inner_arg; - tree format_num_expr; - int format_num; - int i; - call_expr_arg_iterator iter; - - /* Extract the argument number, which was previously checked - to be valid. */ - format_num_expr = TREE_VALUE (TREE_VALUE (attrs)); - - gcc_assert (TREE_CODE (format_num_expr) == INTEGER_CST - && !TREE_INT_CST_HIGH (format_num_expr)); - - format_num = TREE_INT_CST_LOW (format_num_expr); - - for (inner_arg = first_call_expr_arg (param, &iter), i = 1; - inner_arg != 0; - inner_arg = next_call_expr_arg (&iter), i++) - if (i == format_num) - { - check_function_arguments_recurse (callback, ctx, - inner_arg, param_num); - found_format_arg = true; - break; - } - } - - /* If we found a format_arg attribute and did a recursive check, - we are done with checking this argument. Otherwise, we continue - and this will be considered a non-literal. */ - if (found_format_arg) - return; - } - - if (TREE_CODE (param) == COND_EXPR) - { - /* Check both halves of the conditional expression. */ - check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 1), param_num); - check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 2), param_num); - return; - } - - (*callback) (ctx, param, param_num); -} - -/* Checks for a builtin function FNDECL that the number of arguments - NARGS against the required number REQUIRED and issues an error if - there is a mismatch. Returns true if the number of arguments is - correct, otherwise false. */ - -static bool -builtin_function_validate_nargs (tree fndecl, int nargs, int required) -{ - if (nargs < required) - { - error_at (input_location, - "not enough arguments to function %qE", fndecl); - return false; - } - else if (nargs > required) - { - error_at (input_location, - "too many arguments to function %qE", fndecl); - return false; - } - return true; -} - -/* Verifies the NARGS arguments ARGS to the builtin function FNDECL. - Returns false if there was an error, otherwise true. */ - -bool -check_builtin_function_arguments (tree fndecl, int nargs, tree *args) -{ - if (!DECL_BUILT_IN (fndecl) - || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL) - return true; - - switch (DECL_FUNCTION_CODE (fndecl)) - { - case BUILT_IN_CONSTANT_P: - return builtin_function_validate_nargs (fndecl, nargs, 1); - - case BUILT_IN_ISFINITE: - case BUILT_IN_ISINF: - case BUILT_IN_ISINF_SIGN: - case BUILT_IN_ISNAN: - case BUILT_IN_ISNORMAL: - if (builtin_function_validate_nargs (fndecl, nargs, 1)) - { - if (TREE_CODE (TREE_TYPE (args[0])) != REAL_TYPE) - { - error ("non-floating-point argument in call to " - "function %qE", fndecl); - return false; - } - return true; - } - return false; - - case BUILT_IN_ISGREATER: - case BUILT_IN_ISGREATEREQUAL: - case BUILT_IN_ISLESS: - case BUILT_IN_ISLESSEQUAL: - case BUILT_IN_ISLESSGREATER: - case BUILT_IN_ISUNORDERED: - if (builtin_function_validate_nargs (fndecl, nargs, 2)) - { - enum tree_code code0, code1; - code0 = TREE_CODE (TREE_TYPE (args[0])); - code1 = TREE_CODE (TREE_TYPE (args[1])); - if (!((code0 == REAL_TYPE && code1 == REAL_TYPE) - || (code0 == REAL_TYPE && code1 == INTEGER_TYPE) - || (code0 == INTEGER_TYPE && code1 == REAL_TYPE))) - { - error ("non-floating-point arguments in call to " - "function %qE", fndecl); - return false; - } - return true; - } - return false; - - case BUILT_IN_FPCLASSIFY: - if (builtin_function_validate_nargs (fndecl, nargs, 6)) - { - unsigned i; - - for (i=0; i<5; i++) - if (TREE_CODE (args[i]) != INTEGER_CST) - { - error ("non-const integer argument %u in call to function %qE", - i+1, fndecl); - return false; - } - - if (TREE_CODE (TREE_TYPE (args[5])) != REAL_TYPE) - { - error ("non-floating-point argument in call to function %qE", - fndecl); - return false; - } - return true; - } - return false; - - default: - return true; - } -} - -/* Function to help qsort sort FIELD_DECLs by name order. */ - -int -field_decl_cmp (const void *x_p, const void *y_p) -{ - const tree *const x = (const tree *const) x_p; - const tree *const y = (const tree *const) 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; -} - -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 *const) x_p; - const tree *const y = (const tree *const) 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, resort_data.cookie); - resort_data.new_value (&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); -} - -/* Subroutine of c_parse_error. - Return the result of concatenating LHS and RHS. RHS is really - a string literal, its first character is indicated by RHS_START and - RHS_SIZE is its length (including the terminating NUL character). - - The caller is responsible for deleting the returned pointer. */ - -static char * -catenate_strings (const char *lhs, const char *rhs_start, int rhs_size) -{ - const int lhs_size = strlen (lhs); - char *result = XNEWVEC (char, lhs_size + rhs_size); - strncpy (result, lhs, lhs_size); - strncpy (result + lhs_size, rhs_start, rhs_size); - return result; -} - -/* Issue the error given by GMSGID, indicating that it occurred before - TOKEN, which had the associated VALUE. */ - -void -c_parse_error (const char *gmsgid, enum cpp_ttype token_type, - tree value, unsigned char token_flags) -{ -#define catenate_messages(M1, M2) catenate_strings ((M1), (M2), sizeof (M2)) - - char *message = NULL; - - if (token_type == CPP_EOF) - message = catenate_messages (gmsgid, " at end of input"); - else if (token_type == CPP_CHAR - || token_type == CPP_WCHAR - || token_type == CPP_CHAR16 - || token_type == CPP_CHAR32) - { - unsigned int val = TREE_INT_CST_LOW (value); - const char *prefix; - - switch (token_type) - { - default: - prefix = ""; - break; - case CPP_WCHAR: - prefix = "L"; - break; - case CPP_CHAR16: - prefix = "u"; - break; - case CPP_CHAR32: - prefix = "U"; - break; - } - - if (val <= UCHAR_MAX && ISGRAPH (val)) - message = catenate_messages (gmsgid, " before %s'%c'"); - else - message = catenate_messages (gmsgid, " before %s'\\x%x'"); - - error (message, prefix, val); - free (message); - message = NULL; - } - else if (token_type == CPP_STRING - || token_type == CPP_WSTRING - || token_type == CPP_STRING16 - || token_type == CPP_STRING32 - || token_type == CPP_UTF8STRING) - message = catenate_messages (gmsgid, " before string constant"); - else if (token_type == CPP_NUMBER) - message = catenate_messages (gmsgid, " before numeric constant"); - else if (token_type == CPP_NAME) - { - message = catenate_messages (gmsgid, " before %qE"); - error (message, value); - free (message); - message = NULL; - } - else if (token_type == CPP_PRAGMA) - message = catenate_messages (gmsgid, " before %<#pragma%>"); - else if (token_type == CPP_PRAGMA_EOL) - message = catenate_messages (gmsgid, " before end of line"); - else if (token_type < N_TTYPES) - { - message = catenate_messages (gmsgid, " before %qs token"); - error (message, cpp_type2name (token_type, token_flags)); - free (message); - message = NULL; - } - else - error (gmsgid); - - if (message) - { - error (message); - free (message); - } -#undef catenate_messages -} - -/* Mapping for cpp message reasons to the options that enable them. */ - -struct reason_option_codes_t -{ - const int reason; /* cpplib message reason. */ - const int option_code; /* gcc option that controls this message. */ -}; - -static const struct reason_option_codes_t option_codes[] = { - {CPP_W_DEPRECATED, OPT_Wdeprecated}, - {CPP_W_COMMENTS, OPT_Wcomments}, - {CPP_W_TRIGRAPHS, OPT_Wtrigraphs}, - {CPP_W_MULTICHAR, OPT_Wmultichar}, - {CPP_W_TRADITIONAL, OPT_Wtraditional}, - {CPP_W_LONG_LONG, OPT_Wlong_long}, - {CPP_W_ENDIF_LABELS, OPT_Wendif_labels}, - {CPP_W_VARIADIC_MACROS, OPT_Wvariadic_macros}, - {CPP_W_BUILTIN_MACRO_REDEFINED, OPT_Wbuiltin_macro_redefined}, - {CPP_W_UNDEF, OPT_Wundef}, - {CPP_W_UNUSED_MACROS, OPT_Wunused_macros}, - {CPP_W_CXX_OPERATOR_NAMES, OPT_Wc___compat}, - {CPP_W_NORMALIZE, OPT_Wnormalized_}, - {CPP_W_INVALID_PCH, OPT_Winvalid_pch}, - {CPP_W_WARNING_DIRECTIVE, OPT_Wcpp}, - {CPP_W_NONE, 0} -}; - -/* Return the gcc option code associated with the reason for a cpp - message, or 0 if none. */ - -static int -c_option_controlling_cpp_error (int reason) -{ - const struct reason_option_codes_t *entry; - - for (entry = option_codes; entry->reason != CPP_W_NONE; entry++) - { - if (entry->reason == reason) - return entry->option_code; - } - return 0; -} - -/* Callback from cpp_error for PFILE to print diagnostics from the - preprocessor. The diagnostic is of type LEVEL, with REASON set - to the reason code if LEVEL is represents a warning, at location - LOCATION unless this is after lexing and the compiler's location - should be used instead, with column number possibly overridden by - COLUMN_OVERRIDE if not zero; MSG is the translated message and AP - the arguments. Returns true if a diagnostic was emitted, false - otherwise. */ - -bool -c_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, int reason, - location_t location, unsigned int column_override, - const char *msg, va_list *ap) -{ - diagnostic_info diagnostic; - diagnostic_t dlevel; - bool save_warn_system_headers = global_dc->warn_system_headers; - bool ret; - - switch (level) - { - case CPP_DL_WARNING_SYSHDR: - if (flag_no_output) - return false; - global_dc->warn_system_headers = 1; - /* Fall through. */ - case CPP_DL_WARNING: - if (flag_no_output) - return false; - dlevel = DK_WARNING; - break; - case CPP_DL_PEDWARN: - if (flag_no_output && !flag_pedantic_errors) - return false; - dlevel = DK_PEDWARN; - break; - case CPP_DL_ERROR: - dlevel = DK_ERROR; - break; - case CPP_DL_ICE: - dlevel = DK_ICE; - break; - case CPP_DL_NOTE: - dlevel = DK_NOTE; - break; - case CPP_DL_FATAL: - dlevel = DK_FATAL; - break; - default: - gcc_unreachable (); - } - if (done_lexing) - location = input_location; - diagnostic_set_info_translated (&diagnostic, msg, ap, - location, dlevel); - if (column_override) - diagnostic_override_column (&diagnostic, column_override); - diagnostic_override_option_index (&diagnostic, - c_option_controlling_cpp_error (reason)); - ret = report_diagnostic (&diagnostic); - if (level == CPP_DL_WARNING_SYSHDR) - global_dc->warn_system_headers = save_warn_system_headers; - return ret; -} - -/* Convert a character from the host to the target execution character - set. cpplib handles this, mostly. */ - -HOST_WIDE_INT -c_common_to_target_charset (HOST_WIDE_INT c) -{ - /* Character constants in GCC proper are sign-extended under -fsigned-char, - zero-extended under -fno-signed-char. cpplib insists that characters - and character constants are always unsigned. Hence we must convert - back and forth. */ - cppchar_t uc = ((cppchar_t)c) & ((((cppchar_t)1) << CHAR_BIT)-1); - - uc = cpp_host_to_exec_charset (parse_in, uc); - - if (flag_signed_char) - return ((HOST_WIDE_INT)uc) << (HOST_BITS_PER_WIDE_INT - CHAR_TYPE_SIZE) - >> (HOST_BITS_PER_WIDE_INT - CHAR_TYPE_SIZE); - else - return uc; -} - -/* Build the result of __builtin_offsetof. EXPR is a nested sequence of - component references, with STOP_REF, or alternatively an INDIRECT_REF of - NULL, at the bottom; much like the traditional rendering of offsetof as a - macro. Returns the folded and properly cast result. */ - -static tree -fold_offsetof_1 (tree expr, tree stop_ref) -{ - enum tree_code code = PLUS_EXPR; - tree base, off, t; - - if (expr == stop_ref && TREE_CODE (expr) != ERROR_MARK) - return size_zero_node; - - switch (TREE_CODE (expr)) - { - case ERROR_MARK: - return expr; - - case VAR_DECL: - error ("cannot apply % to static data member %qD", expr); - return error_mark_node; - - case CALL_EXPR: - case TARGET_EXPR: - error ("cannot apply % when % is overloaded"); - return error_mark_node; - - case NOP_EXPR: - case INDIRECT_REF: - if (!integer_zerop (TREE_OPERAND (expr, 0))) - { - error ("cannot apply % to a non constant address"); - return error_mark_node; - } - return size_zero_node; - - case COMPONENT_REF: - base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref); - if (base == error_mark_node) - return base; - - t = TREE_OPERAND (expr, 1); - if (DECL_C_BIT_FIELD (t)) - { - error ("attempt to take address of bit-field structure " - "member %qD", t); - return error_mark_node; - } - off = size_binop_loc (input_location, PLUS_EXPR, DECL_FIELD_OFFSET (t), - size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), - 1) - / BITS_PER_UNIT)); - break; - - case ARRAY_REF: - base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref); - if (base == error_mark_node) - return base; - - t = TREE_OPERAND (expr, 1); - if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0) - { - code = MINUS_EXPR; - t = fold_build1_loc (input_location, NEGATE_EXPR, TREE_TYPE (t), t); - } - t = convert (sizetype, t); - off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t); - - /* Check if the offset goes beyond the upper bound of the array. */ - if (code == PLUS_EXPR && TREE_CODE (t) == INTEGER_CST) - { - tree upbound = array_ref_up_bound (expr); - if (upbound != NULL_TREE - && TREE_CODE (upbound) == INTEGER_CST - && !tree_int_cst_equal (upbound, - TYPE_MAX_VALUE (TREE_TYPE (upbound)))) - { - upbound = size_binop (PLUS_EXPR, upbound, - build_int_cst (TREE_TYPE (upbound), 1)); - if (tree_int_cst_lt (upbound, t)) - { - tree v; - - for (v = TREE_OPERAND (expr, 0); - TREE_CODE (v) == COMPONENT_REF; - v = TREE_OPERAND (v, 0)) - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) - == RECORD_TYPE) - { - tree fld_chain = TREE_CHAIN (TREE_OPERAND (v, 1)); - for (; fld_chain; fld_chain = TREE_CHAIN (fld_chain)) - if (TREE_CODE (fld_chain) == FIELD_DECL) - break; - - if (fld_chain) - break; - } - /* Don't warn if the array might be considered a poor - man's flexible array member with a very permissive - definition thereof. */ - if (TREE_CODE (v) == ARRAY_REF - || TREE_CODE (v) == COMPONENT_REF) - warning (OPT_Warray_bounds, - "index %E denotes an offset " - "greater than size of %qT", - t, TREE_TYPE (TREE_OPERAND (expr, 0))); - } - } - } - break; - - case COMPOUND_EXPR: - /* Handle static members of volatile structs. */ - t = TREE_OPERAND (expr, 1); - gcc_assert (TREE_CODE (t) == VAR_DECL); - return fold_offsetof_1 (t, stop_ref); - - default: - gcc_unreachable (); - } - - return size_binop (code, base, off); -} - -tree -fold_offsetof (tree expr, tree stop_ref) -{ - /* Convert back from the internal sizetype to size_t. */ - return convert (size_type_node, fold_offsetof_1 (expr, stop_ref)); -} - -/* Print an error message for an invalid lvalue. USE says - how the lvalue is being used and so selects the error message. */ - -void -lvalue_error (enum lvalue_use use) -{ - switch (use) - { - case lv_assign: - error ("lvalue required as left operand of assignment"); - break; - case lv_increment: - error ("lvalue required as increment operand"); - break; - case lv_decrement: - error ("lvalue required as decrement operand"); - break; - case lv_addressof: - error ("lvalue required as unary %<&%> operand"); - break; - case lv_asm: - error ("lvalue required in asm statement"); - break; - default: - gcc_unreachable (); - } -} - -/* *PTYPE is an incomplete array. Complete it with a domain based on - INITIAL_VALUE. If INITIAL_VALUE is not present, use 1 if DO_DEFAULT - is true. Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered, - 2 if INITIAL_VALUE was NULL, and 3 if INITIAL_VALUE was empty. */ - -int -complete_array_type (tree *ptype, tree initial_value, bool do_default) -{ - tree maxindex, type, main_type, elt, unqual_elt; - int failure = 0, quals; - hashval_t hashcode = 0; - - maxindex = size_zero_node; - if (initial_value) - { - if (TREE_CODE (initial_value) == STRING_CST) - { - int eltsize - = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value))); - maxindex = size_int (TREE_STRING_LENGTH (initial_value)/eltsize - 1); - } - else if (TREE_CODE (initial_value) == CONSTRUCTOR) - { - VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (initial_value); - - if (VEC_empty (constructor_elt, v)) - { - if (pedantic) - failure = 3; - maxindex = integer_minus_one_node; - } - else - { - tree curindex; - unsigned HOST_WIDE_INT cnt; - constructor_elt *ce; - bool fold_p = false; - - if (VEC_index (constructor_elt, v, 0)->index) - maxindex = fold_convert_loc (input_location, sizetype, - VEC_index (constructor_elt, - v, 0)->index); - curindex = maxindex; - - for (cnt = 1; - VEC_iterate (constructor_elt, v, cnt, ce); - cnt++) - { - bool curfold_p = false; - if (ce->index) - curindex = ce->index, curfold_p = true; - else - { - if (fold_p) - curindex = fold_convert (sizetype, curindex); - curindex = size_binop (PLUS_EXPR, curindex, - size_one_node); - } - if (tree_int_cst_lt (maxindex, curindex)) - maxindex = curindex, fold_p = curfold_p; - } - if (fold_p) - maxindex = fold_convert (sizetype, maxindex); - } - } - else - { - /* Make an error message unless that happened already. */ - if (initial_value != error_mark_node) - failure = 1; - } - } - else - { - failure = 2; - if (!do_default) - return failure; - } - - type = *ptype; - elt = TREE_TYPE (type); - quals = TYPE_QUALS (strip_array_types (elt)); - if (quals == 0) - unqual_elt = elt; - else - unqual_elt = c_build_qualified_type (elt, KEEP_QUAL_ADDR_SPACE (quals)); - - /* Using build_distinct_type_copy and modifying things afterward instead - of using build_array_type to create a new type preserves all of the - TYPE_LANG_FLAG_? bits that the front end may have set. */ - main_type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); - TREE_TYPE (main_type) = unqual_elt; - TYPE_DOMAIN (main_type) = build_index_type (maxindex); - layout_type (main_type); - - /* Make sure we have the canonical MAIN_TYPE. */ - hashcode = iterative_hash_object (TYPE_HASH (unqual_elt), hashcode); - hashcode = iterative_hash_object (TYPE_HASH (TYPE_DOMAIN (main_type)), - hashcode); - main_type = type_hash_canon (hashcode, main_type); - - /* Fix the canonical type. */ - if (TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (main_type)) - || TYPE_STRUCTURAL_EQUALITY_P (TYPE_DOMAIN (main_type))) - SET_TYPE_STRUCTURAL_EQUALITY (main_type); - else if (TYPE_CANONICAL (TREE_TYPE (main_type)) != TREE_TYPE (main_type) - || (TYPE_CANONICAL (TYPE_DOMAIN (main_type)) - != TYPE_DOMAIN (main_type))) - TYPE_CANONICAL (main_type) - = build_array_type (TYPE_CANONICAL (TREE_TYPE (main_type)), - TYPE_CANONICAL (TYPE_DOMAIN (main_type))); - else - TYPE_CANONICAL (main_type) = main_type; - - if (quals == 0) - type = main_type; - else - type = c_build_qualified_type (main_type, quals); - - if (COMPLETE_TYPE_P (type) - && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST - && TREE_OVERFLOW (TYPE_SIZE_UNIT (type))) - { - error ("size of array is too large"); - /* If we proceed with the array type as it is, we'll eventually - crash in tree_low_cst(). */ - type = error_mark_node; - } - - *ptype = type; - return failure; -} - - -/* Used to help initialize the builtin-types.def table. When a type of - the correct size doesn't exist, use error_mark_node instead of NULL. - The later results in segfaults even when a decl using the type doesn't - get invoked. */ - -tree -builtin_type_for_size (int size, bool unsignedp) -{ - tree type = lang_hooks.types.type_for_size (size, unsignedp); - return type ? type : error_mark_node; -} - -/* A helper function for resolve_overloaded_builtin in resolving the - overloaded __sync_ builtins. Returns a positive power of 2 if the - first operand of PARAMS is a pointer to a supported data type. - Returns 0 if an error is encountered. */ - -static int -sync_resolve_size (tree function, VEC(tree,gc) *params) -{ - tree type; - int size; - - if (VEC_empty (tree, params)) - { - error ("too few arguments to function %qE", function); - return 0; - } - - type = TREE_TYPE (VEC_index (tree, params, 0)); - if (TREE_CODE (type) != POINTER_TYPE) - goto incompatible; - - type = TREE_TYPE (type); - if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) - goto incompatible; - - size = tree_low_cst (TYPE_SIZE_UNIT (type), 1); - if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16) - return size; - - incompatible: - error ("incompatible type for argument %d of %qE", 1, function); - return 0; -} - -/* A helper function for resolve_overloaded_builtin. Adds casts to - PARAMS to make arguments match up with those of FUNCTION. Drops - the variadic arguments at the end. Returns false if some error - was encountered; true on success. */ - -static bool -sync_resolve_params (tree orig_function, tree function, VEC(tree, gc) *params) -{ - tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (function)); - tree ptype; - unsigned int parmnum; - - /* We've declared the implementation functions to use "volatile void *" - as the pointer parameter, so we shouldn't get any complaints from the - call to check_function_arguments what ever type the user used. */ - arg_types = TREE_CHAIN (arg_types); - ptype = TREE_TYPE (TREE_TYPE (VEC_index (tree, params, 0))); - - /* For the rest of the values, we need to cast these to FTYPE, so that we - don't get warnings for passing pointer types, etc. */ - parmnum = 0; - while (arg_types != void_list_node) - { - tree val; - - ++parmnum; - if (VEC_length (tree, params) <= parmnum) - { - error ("too few arguments to function %qE", orig_function); - return false; - } - - /* ??? Ideally for the first conversion we'd use convert_for_assignment - so that we get warnings for anything that doesn't match the pointer - type. This isn't portable across the C and C++ front ends atm. */ - val = VEC_index (tree, params, parmnum); - val = convert (ptype, val); - val = convert (TREE_VALUE (arg_types), val); - VEC_replace (tree, params, parmnum, val); - - arg_types = TREE_CHAIN (arg_types); - } - - /* The definition of these primitives is variadic, with the remaining - being "an optional list of variables protected by the memory barrier". - No clue what that's supposed to mean, precisely, but we consider all - call-clobbered variables to be protected so we're safe. */ - VEC_truncate (tree, params, parmnum + 1); - - return true; -} - -/* A helper function for resolve_overloaded_builtin. Adds a cast to - RESULT to make it match the type of the first pointer argument in - PARAMS. */ - -static tree -sync_resolve_return (tree first_param, tree result) -{ - tree ptype = TREE_TYPE (TREE_TYPE (first_param)); - ptype = TYPE_MAIN_VARIANT (ptype); - return convert (ptype, result); -} - -/* Some builtin functions are placeholders for other expressions. This - function should be called immediately after parsing the call expression - before surrounding code has committed to the type of the expression. - - LOC is the location of the builtin call. - - FUNCTION is the DECL that has been invoked; it is known to be a builtin. - PARAMS is the argument list for the call. The return value is non-null - when expansion is complete, and null if normal processing should - continue. */ - -tree -resolve_overloaded_builtin (location_t loc, tree function, VEC(tree,gc) *params) -{ - enum built_in_function orig_code = DECL_FUNCTION_CODE (function); - switch (DECL_BUILT_IN_CLASS (function)) - { - case BUILT_IN_NORMAL: - break; - case BUILT_IN_MD: - if (targetm.resolve_overloaded_builtin) - return targetm.resolve_overloaded_builtin (loc, function, params); - else - return NULL_TREE; - default: - return NULL_TREE; - } - - /* Handle BUILT_IN_NORMAL here. */ - switch (orig_code) - { - case BUILT_IN_FETCH_AND_ADD_N: - case BUILT_IN_FETCH_AND_SUB_N: - case BUILT_IN_FETCH_AND_OR_N: - case BUILT_IN_FETCH_AND_AND_N: - case BUILT_IN_FETCH_AND_XOR_N: - case BUILT_IN_FETCH_AND_NAND_N: - case BUILT_IN_ADD_AND_FETCH_N: - case BUILT_IN_SUB_AND_FETCH_N: - case BUILT_IN_OR_AND_FETCH_N: - case BUILT_IN_AND_AND_FETCH_N: - case BUILT_IN_XOR_AND_FETCH_N: - case BUILT_IN_NAND_AND_FETCH_N: - case BUILT_IN_BOOL_COMPARE_AND_SWAP_N: - case BUILT_IN_VAL_COMPARE_AND_SWAP_N: - case BUILT_IN_LOCK_TEST_AND_SET_N: - case BUILT_IN_LOCK_RELEASE_N: - { - int n = sync_resolve_size (function, params); - tree new_function, first_param, result; - - if (n == 0) - return error_mark_node; - - new_function = built_in_decls[orig_code + exact_log2 (n) + 1]; - if (!sync_resolve_params (function, new_function, params)) - return error_mark_node; - - first_param = VEC_index (tree, params, 0); - result = build_function_call_vec (loc, new_function, params, NULL); - if (orig_code != BUILT_IN_BOOL_COMPARE_AND_SWAP_N - && orig_code != BUILT_IN_LOCK_RELEASE_N) - result = sync_resolve_return (first_param, result); - - return result; - } - - default: - return NULL_TREE; - } -} - -/* Ignoring their sign, return true if two scalar types are the same. */ -bool -same_scalar_type_ignoring_signedness (tree t1, tree t2) -{ - enum tree_code c1 = TREE_CODE (t1), c2 = TREE_CODE (t2); - - gcc_assert ((c1 == INTEGER_TYPE || c1 == REAL_TYPE || c1 == FIXED_POINT_TYPE) - && (c2 == INTEGER_TYPE || c2 == REAL_TYPE - || c2 == FIXED_POINT_TYPE)); - - /* Equality works here because c_common_signed_type uses - TYPE_MAIN_VARIANT. */ - return c_common_signed_type (t1) - == c_common_signed_type (t2); -} - -/* Check for missing format attributes on function pointers. LTYPE is - the new type or left-hand side type. RTYPE is the old type or - right-hand side type. Returns TRUE if LTYPE is missing the desired - attribute. */ - -bool -check_missing_format_attribute (tree ltype, tree rtype) -{ - tree const ttr = TREE_TYPE (rtype), ttl = TREE_TYPE (ltype); - tree ra; - - for (ra = TYPE_ATTRIBUTES (ttr); ra; ra = TREE_CHAIN (ra)) - if (is_attribute_p ("format", TREE_PURPOSE (ra))) - break; - if (ra) - { - tree la; - for (la = TYPE_ATTRIBUTES (ttl); la; la = TREE_CHAIN (la)) - if (is_attribute_p ("format", TREE_PURPOSE (la))) - break; - return !la; - } - else - return false; -} - -/* Subscripting with type char is likely to lose on a machine where - chars are signed. So warn on any machine, but optionally. Don't - warn for unsigned char since that type is safe. Don't warn for - signed char because anyone who uses that must have done so - deliberately. Furthermore, we reduce the false positive load by - warning only for non-constant value of type char. */ - -void -warn_array_subscript_with_type_char (tree index) -{ - if (TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node - && TREE_CODE (index) != INTEGER_CST) - warning (OPT_Wchar_subscripts, "array subscript has type %"); -} - -/* Implement -Wparentheses for the unexpected C precedence rules, to - cover cases like x + y << z which readers are likely to - misinterpret. We have seen an expression in which CODE is a binary - operator used to combine expressions ARG_LEFT and ARG_RIGHT, which - before folding had CODE_LEFT and CODE_RIGHT. CODE_LEFT and - CODE_RIGHT may be ERROR_MARK, which means that that side of the - expression was not formed using a binary or unary operator, or it - was enclosed in parentheses. */ - -void -warn_about_parentheses (enum tree_code code, - enum tree_code code_left, tree arg_left, - enum tree_code code_right, tree arg_right) -{ - if (!warn_parentheses) - return; - - /* This macro tests that the expression ARG with original tree code - CODE appears to be a boolean expression. or the result of folding a - boolean expression. */ -#define APPEARS_TO_BE_BOOLEAN_EXPR_P(CODE, ARG) \ - (truth_value_p (TREE_CODE (ARG)) \ - || TREE_CODE (TREE_TYPE (ARG)) == BOOLEAN_TYPE \ - /* Folding may create 0 or 1 integers from other expressions. */ \ - || ((CODE) != INTEGER_CST \ - && (integer_onep (ARG) || integer_zerop (ARG)))) - - switch (code) - { - case LSHIFT_EXPR: - if (code_left == PLUS_EXPR || code_right == PLUS_EXPR) - warning (OPT_Wparentheses, - "suggest parentheses around %<+%> inside %<<<%>"); - else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR) - warning (OPT_Wparentheses, - "suggest parentheses around %<-%> inside %<<<%>"); - return; - - case RSHIFT_EXPR: - if (code_left == PLUS_EXPR || code_right == PLUS_EXPR) - warning (OPT_Wparentheses, - "suggest parentheses around %<+%> inside %<>>%>"); - else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR) - warning (OPT_Wparentheses, - "suggest parentheses around %<-%> inside %<>>%>"); - return; - - case TRUTH_ORIF_EXPR: - if (code_left == TRUTH_ANDIF_EXPR || code_right == TRUTH_ANDIF_EXPR) - warning (OPT_Wparentheses, - "suggest parentheses around %<&&%> within %<||%>"); - return; - - case BIT_IOR_EXPR: - if (code_left == BIT_AND_EXPR || code_left == BIT_XOR_EXPR - || code_left == PLUS_EXPR || code_left == MINUS_EXPR - || code_right == BIT_AND_EXPR || code_right == BIT_XOR_EXPR - || code_right == PLUS_EXPR || code_right == MINUS_EXPR) - warning (OPT_Wparentheses, - "suggest parentheses around arithmetic in operand of %<|%>"); - /* Check cases like x|y==z */ - else if (TREE_CODE_CLASS (code_left) == tcc_comparison - || TREE_CODE_CLASS (code_right) == tcc_comparison) - warning (OPT_Wparentheses, - "suggest parentheses around comparison in operand of %<|%>"); - /* Check cases like !x | y */ - else if (code_left == TRUTH_NOT_EXPR - && !APPEARS_TO_BE_BOOLEAN_EXPR_P (code_right, arg_right)) - warning (OPT_Wparentheses, "suggest parentheses around operand of " - "% or change %<|%> to %<||%> or % to %<~%>"); - return; - - case BIT_XOR_EXPR: - if (code_left == BIT_AND_EXPR - || code_left == PLUS_EXPR || code_left == MINUS_EXPR - || code_right == BIT_AND_EXPR - || code_right == PLUS_EXPR || code_right == MINUS_EXPR) - warning (OPT_Wparentheses, - "suggest parentheses around arithmetic in operand of %<^%>"); - /* Check cases like x^y==z */ - else if (TREE_CODE_CLASS (code_left) == tcc_comparison - || TREE_CODE_CLASS (code_right) == tcc_comparison) - warning (OPT_Wparentheses, - "suggest parentheses around comparison in operand of %<^%>"); - return; - - case BIT_AND_EXPR: - if (code_left == PLUS_EXPR || code_right == PLUS_EXPR) - warning (OPT_Wparentheses, - "suggest parentheses around %<+%> in operand of %<&%>"); - else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR) - warning (OPT_Wparentheses, - "suggest parentheses around %<-%> in operand of %<&%>"); - /* Check cases like x&y==z */ - else if (TREE_CODE_CLASS (code_left) == tcc_comparison - || TREE_CODE_CLASS (code_right) == tcc_comparison) - warning (OPT_Wparentheses, - "suggest parentheses around comparison in operand of %<&%>"); - /* Check cases like !x & y */ - else if (code_left == TRUTH_NOT_EXPR - && !APPEARS_TO_BE_BOOLEAN_EXPR_P (code_right, arg_right)) - warning (OPT_Wparentheses, "suggest parentheses around operand of " - "% or change %<&%> to %<&&%> or % to %<~%>"); - return; - - case EQ_EXPR: - if (TREE_CODE_CLASS (code_left) == tcc_comparison - || TREE_CODE_CLASS (code_right) == tcc_comparison) - warning (OPT_Wparentheses, - "suggest parentheses around comparison in operand of %<==%>"); - return; - case NE_EXPR: - if (TREE_CODE_CLASS (code_left) == tcc_comparison - || TREE_CODE_CLASS (code_right) == tcc_comparison) - warning (OPT_Wparentheses, - "suggest parentheses around comparison in operand of %"); - return; - - default: - if (TREE_CODE_CLASS (code) == tcc_comparison - && ((TREE_CODE_CLASS (code_left) == tcc_comparison - && code_left != NE_EXPR && code_left != EQ_EXPR - && INTEGRAL_TYPE_P (TREE_TYPE (arg_left))) - || (TREE_CODE_CLASS (code_right) == tcc_comparison - && code_right != NE_EXPR && code_right != EQ_EXPR - && INTEGRAL_TYPE_P (TREE_TYPE (arg_right))))) - warning (OPT_Wparentheses, "comparisons like % do not " - "have their mathematical meaning"); - return; - } -#undef NOT_A_BOOLEAN_EXPR_P -} - -/* If LABEL (a LABEL_DECL) has not been used, issue a warning. */ - -void -warn_for_unused_label (tree label) -{ - if (!TREE_USED (label)) - { - if (DECL_INITIAL (label)) - warning (OPT_Wunused_label, "label %q+D defined but not used", label); - else - warning (OPT_Wunused_label, "label %q+D declared but not defined", label); - } -} - -#ifndef TARGET_HAS_TARGETCM -struct gcc_targetcm targetcm = TARGETCM_INITIALIZER; -#endif - -/* Warn for division by zero according to the value of DIVISOR. LOC - is the location of the division operator. */ - -void -warn_for_div_by_zero (location_t loc, tree divisor) -{ - /* If DIVISOR is zero, and has integral or fixed-point type, issue a warning - about division by zero. Do not issue a warning if DIVISOR has a - floating-point type, since we consider 0.0/0.0 a valid way of - generating a NaN. */ - if (c_inhibit_evaluation_warnings == 0 - && (integer_zerop (divisor) || fixed_zerop (divisor))) - warning_at (loc, OPT_Wdiv_by_zero, "division by zero"); -} - -/* Subroutine of build_binary_op. Give warnings for comparisons - between signed and unsigned quantities that may fail. Do the - checking based on the original operand trees ORIG_OP0 and ORIG_OP1, - so that casts will be considered, but default promotions won't - be. - - LOCATION is the location of the comparison operator. - - The arguments of this function map directly to local variables - of build_binary_op. */ - -void -warn_for_sign_compare (location_t location, - tree orig_op0, tree orig_op1, - tree op0, tree op1, - tree result_type, enum tree_code resultcode) -{ - int op0_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op0)); - int op1_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op1)); - int unsignedp0, unsignedp1; - - /* In C++, check for comparison of different enum types. */ - if (c_dialect_cxx() - && TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE - && TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE - && TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0)) - != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1))) - { - warning_at (location, - OPT_Wsign_compare, "comparison between types %qT and %qT", - TREE_TYPE (orig_op0), TREE_TYPE (orig_op1)); - } - - /* Do not warn if the comparison is being done in a signed type, - 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 */; - /* Do not warn if both operands are unsigned. */ - else if (op0_signed == op1_signed) - /* OK */; - else - { - tree sop, uop, base_type; - bool ovf; - - if (op0_signed) - sop = orig_op0, uop = orig_op1; - else - sop = orig_op1, uop = orig_op0; - - STRIP_TYPE_NOPS (sop); - STRIP_TYPE_NOPS (uop); - base_type = (TREE_CODE (result_type) == COMPLEX_TYPE - ? TREE_TYPE (result_type) : result_type); - - /* Do not warn if the signed quantity is an unsuffixed integer - literal (or some static constant expression involving such - literals or a conditional expression involving such literals) - and it is non-negative. */ - if (tree_expr_nonnegative_warnv_p (sop, &ovf)) - /* OK */; - /* Do not warn if the comparison is an equality operation, the - unsigned quantity is an integral constant, and it would fit - in the result if the result were signed. */ - else if (TREE_CODE (uop) == INTEGER_CST - && (resultcode == EQ_EXPR || resultcode == NE_EXPR) - && int_fits_type_p (uop, c_common_signed_type (base_type))) - /* OK */; - /* In C, do not warn if the unsigned quantity is an enumeration - constant and its maximum value would fit in the result if the - result were signed. */ - else if (!c_dialect_cxx() && TREE_CODE (uop) == INTEGER_CST - && TREE_CODE (TREE_TYPE (uop)) == ENUMERAL_TYPE - && int_fits_type_p (TYPE_MAX_VALUE (TREE_TYPE (uop)), - c_common_signed_type (base_type))) - /* OK */; - else - warning_at (location, - OPT_Wsign_compare, - "comparison between signed and unsigned integer expressions"); - } - - /* Warn if two unsigned values are being compared in a size larger - than their original size, and one (and only one) is the result of - a `~' operator. This comparison will always fail. - - Also warn if one operand is a constant, and the constant does not - have all bits set that are set in the ~ operand when it is - extended. */ - - op0 = get_narrower (op0, &unsignedp0); - op1 = get_narrower (op1, &unsignedp1); - - if ((TREE_CODE (op0) == BIT_NOT_EXPR) - ^ (TREE_CODE (op1) == BIT_NOT_EXPR)) - { - if (TREE_CODE (op0) == BIT_NOT_EXPR) - op0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0); - if (TREE_CODE (op1) == BIT_NOT_EXPR) - op1 = get_narrower (TREE_OPERAND (op1, 0), &unsignedp1); - - if (host_integerp (op0, 0) || host_integerp (op1, 0)) - { - tree primop; - HOST_WIDE_INT constant, mask; - int unsignedp; - unsigned int bits; - - if (host_integerp (op0, 0)) - { - primop = op1; - unsignedp = unsignedp1; - constant = tree_low_cst (op0, 0); - } - else - { - primop = op0; - unsignedp = unsignedp0; - constant = tree_low_cst (op1, 0); - } - - bits = TYPE_PRECISION (TREE_TYPE (primop)); - if (bits < TYPE_PRECISION (result_type) - && bits < HOST_BITS_PER_LONG && unsignedp) - { - mask = (~ (HOST_WIDE_INT) 0) << bits; - if ((mask & constant) != mask) - { - if (constant == 0) - warning (OPT_Wsign_compare, - "promoted ~unsigned is always non-zero"); - else - warning_at (location, OPT_Wsign_compare, - "comparison of promoted ~unsigned with constant"); - } - } - } - else if (unsignedp0 && unsignedp1 - && (TYPE_PRECISION (TREE_TYPE (op0)) - < TYPE_PRECISION (result_type)) - && (TYPE_PRECISION (TREE_TYPE (op1)) - < TYPE_PRECISION (result_type))) - warning_at (location, OPT_Wsign_compare, - "comparison of promoted ~unsigned with unsigned"); - } -} - -/* Setup a TYPE_DECL node as a typedef representation. - - X is a TYPE_DECL for a typedef statement. Create a brand new - ..._TYPE node (which will be just a variant of the existing - ..._TYPE node with identical properties) and then install X - as the TYPE_NAME of this brand new (duplicate) ..._TYPE node. - - The whole point here is to end up with a situation where each - and every ..._TYPE node the compiler creates will be uniquely - associated with AT MOST one node representing a typedef name. - This way, even though the compiler substitutes corresponding - ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very - early on, later parts of the compiler can always do the reverse - translation and get back the corresponding typedef name. For - example, given: - - typedef struct S MY_TYPE; - MY_TYPE object; - - Later parts of the compiler might only know that `object' was of - type `struct S' if it were not for code just below. With this - code however, later parts of the compiler see something like: - - struct S' == struct S - typedef struct S' MY_TYPE; - struct S' object; - - And they can then deduce (from the node for type struct S') that - the original object declaration was: - - MY_TYPE object; - - Being able to do this is important for proper support of protoize, - and also for generating precise symbolic debugging information - which takes full account of the programmer's (typedef) vocabulary. - - Obviously, we don't want to generate a duplicate ..._TYPE node if - the TYPE_DECL node that we are now processing really represents a - standard built-in type. */ - -void -set_underlying_type (tree x) -{ - if (x == error_mark_node) - return; - if (DECL_IS_BUILTIN (x)) - { - if (TYPE_NAME (TREE_TYPE (x)) == 0) - TYPE_NAME (TREE_TYPE (x)) = x; - } - else if (TREE_TYPE (x) != error_mark_node - && DECL_ORIGINAL_TYPE (x) == NULL_TREE) - { - tree tt = TREE_TYPE (x); - DECL_ORIGINAL_TYPE (x) = tt; - tt = build_variant_type_copy (tt); - TYPE_STUB_DECL (tt) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x)); - TYPE_NAME (tt) = x; - TREE_USED (tt) = TREE_USED (x); - TREE_TYPE (x) = tt; - } -} - -/* Returns true if X is a typedef decl. */ - -bool -is_typedef_decl (tree x) -{ - return (x && TREE_CODE (x) == TYPE_DECL - && DECL_ORIGINAL_TYPE (x) != NULL_TREE); -} - -/* Record the types used by the current global variable declaration - being parsed, so that we can decide later to emit their debug info. - Those types are in types_used_by_cur_var_decl, and we are going to - store them in the types_used_by_vars_hash hash table. - DECL is the declaration of the global variable that has been parsed. */ - -void -record_types_used_by_current_var_decl (tree decl) -{ - gcc_assert (decl && DECL_P (decl) && TREE_STATIC (decl)); - - if (types_used_by_cur_var_decl) - { - tree node; - for (node = types_used_by_cur_var_decl; - node; - node = TREE_CHAIN (node)) - { - tree type = TREE_PURPOSE (node); - types_used_by_var_decl_insert (type, decl); - } - types_used_by_cur_var_decl = NULL; - } -} - -/* The C and C++ parsers both use vectors to hold function arguments. - For efficiency, we keep a cache of unused vectors. This is the - cache. */ - -typedef VEC(tree,gc)* tree_gc_vec; -DEF_VEC_P(tree_gc_vec); -DEF_VEC_ALLOC_P(tree_gc_vec,gc); -static GTY((deletable)) VEC(tree_gc_vec,gc) *tree_vector_cache; - -/* Return a new vector from the cache. If the cache is empty, - allocate a new vector. These vectors are GC'ed, so it is OK if the - pointer is not released.. */ - -VEC(tree,gc) * -make_tree_vector (void) -{ - if (!VEC_empty (tree_gc_vec, tree_vector_cache)) - return VEC_pop (tree_gc_vec, tree_vector_cache); - else - { - /* Passing 0 to VEC_alloc returns NULL, and our callers require - that we always return a non-NULL value. The vector code uses - 4 when growing a NULL vector, so we do too. */ - return VEC_alloc (tree, gc, 4); - } -} - -/* Release a vector of trees back to the cache. */ - -void -release_tree_vector (VEC(tree,gc) *vec) -{ - if (vec != NULL) - { - VEC_truncate (tree, vec, 0); - VEC_safe_push (tree_gc_vec, gc, tree_vector_cache, vec); - } -} - -/* Get a new tree vector holding a single tree. */ - -VEC(tree,gc) * -make_tree_vector_single (tree t) -{ - VEC(tree,gc) *ret = make_tree_vector (); - VEC_quick_push (tree, ret, t); - return ret; -} - -/* Get a new tree vector which is a copy of an existing one. */ - -VEC(tree,gc) * -make_tree_vector_copy (const VEC(tree,gc) *orig) -{ - VEC(tree,gc) *ret; - unsigned int ix; - tree t; - - ret = make_tree_vector (); - VEC_reserve (tree, gc, ret, VEC_length (tree, orig)); - for (ix = 0; VEC_iterate (tree, orig, ix, t); ++ix) - VEC_quick_push (tree, ret, t); - return ret; -} - -#include "gt-c-common.h" diff --git a/gcc/c-common.def b/gcc/c-common.def deleted file mode 100644 index 1c59363..0000000 --- a/gcc/c-common.def +++ /dev/null @@ -1,53 +0,0 @@ -/* This file contains the definitions and documentation for the - additional tree codes used in the GNU C compiler (see tree.def - for the standard codes). - Copyright (C) 1987, 1988, 1990, 1993, 1997, 1998, - 1999, 2000, 2001, 2004, 2005, 2007, 2009 Free Software Foundation, Inc. - Written by Benjamin Chelf - -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 -. */ - -/* Tree nodes used in the C frontend. These are also shared with the - C++ and Objective C frontends. */ - -/* A C_MAYBE_CONST_EXPR, currently only used for C and Objective C, - tracks information about constancy of an expression and VLA type - sizes or VM expressions from typeof that need to be evaluated - before the main expression. It is used during parsing and removed - in c_fully_fold. C_MAYBE_CONST_EXPR_PRE is the expression to - evaluate first, if not NULL; C_MAYBE_CONST_EXPR_EXPR is the main - expression. If C_MAYBE_CONST_EXPR_INT_OPERANDS is set then the - expression may be used in an unevaluated part of an integer - constant expression, but not in an evaluated part. If - C_MAYBE_CONST_EXPR_NON_CONST is set then the expression contains - something that cannot occur in an evaluated part of a constant - expression (or outside of sizeof in C90 mode); otherwise it does - not. */ -DEFTREECODE (C_MAYBE_CONST_EXPR, "c_maybe_const_expr", tcc_expression, 2) - -/* An EXCESS_PRECISION_EXPR, currently only used for C and Objective - C, represents an expression evaluated in greater range or precision - than its type. The type of the EXCESS_PRECISION_EXPR is the - semantic type while the operand represents what is actually being - evaluated. */ -DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1) - -/* -Local variables: -mode:c -End: -*/ diff --git a/gcc/c-common.h b/gcc/c-common.h deleted file mode 100644 index 289d70c..0000000 --- a/gcc/c-common.h +++ /dev/null @@ -1,1191 +0,0 @@ -/* Definitions for c-common.c. - Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 - 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 -. */ - -#ifndef GCC_C_COMMON_H -#define GCC_C_COMMON_H - -#include "splay-tree.h" -#include "cpplib.h" -#include "ggc.h" - -/* In order for the format checking to accept the C frontend - diagnostic framework extensions, you must include this file before - toplev.h, not after. The C front end formats are a subset of those - for C++, so they are the appropriate set to use in common code; - cp-tree.h overrides this for C++. */ -#ifndef GCC_DIAG_STYLE -#define GCC_DIAG_STYLE __gcc_cdiag__ -#endif -#include "diagnostic-core.h" - -/* Usage of TREE_LANG_FLAG_?: - 0: TREE_NEGATED_INT (in INTEGER_CST). - IDENTIFIER_MARKED (used by search routines). - DECL_PRETTY_FUNCTION_P (in VAR_DECL) - C_MAYBE_CONST_EXPR_INT_OPERANDS (in C_MAYBE_CONST_EXPR, for C) - 1: C_DECLARED_LABEL_FLAG (in LABEL_DECL) - STATEMENT_LIST_STMT_EXPR (in STATEMENT_LIST) - C_MAYBE_CONST_EXPR_NON_CONST (in C_MAYBE_CONST_EXPR, for C) - 2: unused - 3: STATEMENT_LIST_HAS_LABEL (in STATEMENT_LIST) - 4: unused -*/ - -/* Reserved identifiers. This is the union of all the keywords for C, - C++, and Objective-C. All the type modifiers have to be in one - block at the beginning, because they are used as mask bits. There - are 27 type modifiers; if we add many more we will have to redesign - the mask mechanism. */ - -enum rid -{ - /* Modifiers: */ - /* C, in empirical order of frequency. */ - RID_STATIC = 0, - RID_UNSIGNED, RID_LONG, RID_CONST, RID_EXTERN, - RID_REGISTER, RID_TYPEDEF, RID_SHORT, RID_INLINE, - RID_VOLATILE, RID_SIGNED, RID_AUTO, RID_RESTRICT, - - /* C extensions */ - RID_COMPLEX, RID_THREAD, RID_SAT, - - /* C++ */ - RID_FRIEND, RID_VIRTUAL, RID_EXPLICIT, RID_EXPORT, RID_MUTABLE, - - /* ObjC */ - RID_IN, RID_OUT, RID_INOUT, RID_BYCOPY, RID_BYREF, RID_ONEWAY, - - /* C (reserved and imaginary types not implemented, so any use is a - syntax error) */ - RID_IMAGINARY, - - /* C */ - RID_INT, RID_CHAR, RID_FLOAT, RID_DOUBLE, RID_VOID, - RID_INT128, - RID_ENUM, RID_STRUCT, RID_UNION, RID_IF, RID_ELSE, - RID_WHILE, RID_DO, RID_FOR, RID_SWITCH, RID_CASE, - RID_DEFAULT, RID_BREAK, RID_CONTINUE, RID_RETURN, RID_GOTO, - RID_SIZEOF, - - /* C extensions */ - RID_ASM, RID_TYPEOF, RID_ALIGNOF, RID_ATTRIBUTE, RID_VA_ARG, - RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, - RID_TYPES_COMPATIBLE_P, - RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, - RID_FRACT, RID_ACCUM, - - /* This means to warn that this is a C++ keyword, and then treat it - as a normal identifier. */ - RID_CXX_COMPAT_WARN, - - /* Too many ways of getting the name of a function as a string */ - RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME, - - /* C++ */ - RID_BOOL, RID_WCHAR, RID_CLASS, - RID_PUBLIC, RID_PRIVATE, RID_PROTECTED, - RID_TEMPLATE, RID_NULL, RID_CATCH, - RID_DELETE, RID_FALSE, RID_NAMESPACE, - RID_NEW, RID_OFFSETOF, RID_OPERATOR, - RID_THIS, RID_THROW, RID_TRUE, - RID_TRY, RID_TYPENAME, RID_TYPEID, - RID_USING, RID_CHAR16, RID_CHAR32, - - /* casts */ - RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, - - /* C++ extensions */ - RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, - RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, - RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY, - RID_HAS_TRIVIAL_DESTRUCTOR, RID_HAS_VIRTUAL_DESTRUCTOR, - RID_IS_ABSTRACT, RID_IS_BASE_OF, - RID_IS_CONVERTIBLE_TO, RID_IS_CLASS, - RID_IS_EMPTY, RID_IS_ENUM, - RID_IS_POD, RID_IS_POLYMORPHIC, - RID_IS_STD_LAYOUT, RID_IS_TRIVIAL, - RID_IS_UNION, - - /* C++0x */ - RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT, - - /* Objective-C */ - RID_AT_ENCODE, RID_AT_END, - RID_AT_CLASS, RID_AT_ALIAS, RID_AT_DEFS, - RID_AT_PRIVATE, RID_AT_PROTECTED, RID_AT_PUBLIC, - RID_AT_PROTOCOL, RID_AT_SELECTOR, - RID_AT_THROW, RID_AT_TRY, RID_AT_CATCH, - RID_AT_FINALLY, RID_AT_SYNCHRONIZED, - RID_AT_INTERFACE, - RID_AT_IMPLEMENTATION, - - /* Named address support, mapping the keyword to a particular named address - number. Named address space 0 is reserved for the generic address. If - there are more than 254 named addresses, the addr_space_t type will need - to be grown from an unsigned char to unsigned short. */ - RID_ADDR_SPACE_0, /* generic address */ - RID_ADDR_SPACE_1, - RID_ADDR_SPACE_2, - RID_ADDR_SPACE_3, - RID_ADDR_SPACE_4, - RID_ADDR_SPACE_5, - RID_ADDR_SPACE_6, - RID_ADDR_SPACE_7, - RID_ADDR_SPACE_8, - RID_ADDR_SPACE_9, - RID_ADDR_SPACE_10, - RID_ADDR_SPACE_11, - RID_ADDR_SPACE_12, - RID_ADDR_SPACE_13, - RID_ADDR_SPACE_14, - RID_ADDR_SPACE_15, - - RID_FIRST_ADDR_SPACE = RID_ADDR_SPACE_0, - RID_LAST_ADDR_SPACE = RID_ADDR_SPACE_15, - - RID_MAX, - - RID_FIRST_MODIFIER = RID_STATIC, - RID_LAST_MODIFIER = RID_ONEWAY, - - RID_FIRST_CXX0X = RID_CONSTEXPR, - RID_LAST_CXX0X = RID_STATIC_ASSERT, - RID_FIRST_AT = RID_AT_ENCODE, - RID_LAST_AT = RID_AT_IMPLEMENTATION, - RID_FIRST_PQ = RID_IN, - RID_LAST_PQ = RID_ONEWAY -}; - -#define OBJC_IS_AT_KEYWORD(rid) \ - ((unsigned int) (rid) >= (unsigned int) RID_FIRST_AT && \ - (unsigned int) (rid) <= (unsigned int) RID_LAST_AT) - -#define OBJC_IS_PQ_KEYWORD(rid) \ - ((unsigned int) (rid) >= (unsigned int) RID_FIRST_PQ && \ - (unsigned int) (rid) <= (unsigned int) RID_LAST_PQ) - -/* The elements of `ridpointers' are identifier nodes for the reserved - type names and storage classes. It is indexed by a RID_... value. */ -extern GTY ((length ("(int) RID_MAX"))) tree *ridpointers; - -/* Standard named or nameless data types of the C compiler. */ - -enum c_tree_index -{ - CTI_CHAR16_TYPE, - CTI_CHAR32_TYPE, - CTI_WCHAR_TYPE, - CTI_UNDERLYING_WCHAR_TYPE, - CTI_WINT_TYPE, - CTI_SIGNED_SIZE_TYPE, /* For format checking only. */ - CTI_UNSIGNED_PTRDIFF_TYPE, /* For format checking only. */ - CTI_INTMAX_TYPE, - CTI_UINTMAX_TYPE, - CTI_WIDEST_INT_LIT_TYPE, - CTI_WIDEST_UINT_LIT_TYPE, - - /* Types for , that may not be defined on all - targets. */ - CTI_SIG_ATOMIC_TYPE, - CTI_INT8_TYPE, - CTI_INT16_TYPE, - CTI_INT32_TYPE, - CTI_INT64_TYPE, - CTI_UINT8_TYPE, - CTI_UINT16_TYPE, - CTI_UINT32_TYPE, - CTI_UINT64_TYPE, - CTI_INT_LEAST8_TYPE, - CTI_INT_LEAST16_TYPE, - CTI_INT_LEAST32_TYPE, - CTI_INT_LEAST64_TYPE, - CTI_UINT_LEAST8_TYPE, - CTI_UINT_LEAST16_TYPE, - CTI_UINT_LEAST32_TYPE, - CTI_UINT_LEAST64_TYPE, - CTI_INT_FAST8_TYPE, - CTI_INT_FAST16_TYPE, - CTI_INT_FAST32_TYPE, - CTI_INT_FAST64_TYPE, - CTI_UINT_FAST8_TYPE, - CTI_UINT_FAST16_TYPE, - CTI_UINT_FAST32_TYPE, - CTI_UINT_FAST64_TYPE, - CTI_INTPTR_TYPE, - CTI_UINTPTR_TYPE, - - CTI_CHAR_ARRAY_TYPE, - CTI_CHAR16_ARRAY_TYPE, - CTI_CHAR32_ARRAY_TYPE, - CTI_WCHAR_ARRAY_TYPE, - CTI_INT_ARRAY_TYPE, - CTI_STRING_TYPE, - CTI_CONST_STRING_TYPE, - - /* Type for boolean expressions (bool in C++, int in C). */ - CTI_TRUTHVALUE_TYPE, - CTI_TRUTHVALUE_TRUE, - CTI_TRUTHVALUE_FALSE, - - CTI_DEFAULT_FUNCTION_TYPE, - - /* These are not types, but we have to look them up all the time. */ - CTI_FUNCTION_NAME_DECL, - CTI_PRETTY_FUNCTION_NAME_DECL, - CTI_C99_FUNCTION_NAME_DECL, - CTI_SAVED_FUNCTION_NAME_DECLS, - - CTI_VOID_ZERO, - - CTI_NULL, - - CTI_MAX -}; - -#define C_CPP_HASHNODE(id) \ - (&(((struct c_common_identifier *) (id))->node)) -#define C_RID_CODE(id) \ - ((enum rid) (((struct c_common_identifier *) (id))->node.rid_code)) -#define C_SET_RID_CODE(id, code) \ - (((struct c_common_identifier *) (id))->node.rid_code = (unsigned char) code) - -/* Identifier part common to the C front ends. Inherits from - tree_identifier, despite appearances. */ -struct GTY(()) c_common_identifier { - struct tree_common common; - struct cpp_hashnode node; -}; - -/* An entry in the reserved keyword table. */ - -struct c_common_resword -{ - const char *const word; - ENUM_BITFIELD(rid) const rid : 16; - const unsigned int disable : 16; -}; - -/* Disable mask. Keywords are disabled if (reswords[i].disable & - mask) is _true_. Thus for keywords which are present in all - languages the disable field is zero. */ - -#define D_CONLY 0x001 /* C only (not in C++). */ -#define D_CXXONLY 0x002 /* C++ only (not in C). */ -#define D_C99 0x004 /* In C, C99 only. */ -#define D_CXX0X 0x008 /* In C++, C++0X only. */ -#define D_EXT 0x010 /* GCC extension. */ -#define D_EXT89 0x020 /* GCC extension incorporated in C99. */ -#define D_ASM 0x040 /* Disabled by -fno-asm. */ -#define D_OBJC 0x080 /* In Objective C and neither C nor C++. */ -#define D_CXX_OBJC 0x100 /* In Objective C, and C++, but not C. */ -#define D_CXXWARN 0x200 /* In C warn with -Wcxx-compat. */ - -/* The reserved keyword table. */ -extern const struct c_common_resword c_common_reswords[]; - -/* The number of items in the reserved keyword table. */ -extern const unsigned int num_c_common_reswords; - -#define char16_type_node c_global_trees[CTI_CHAR16_TYPE] -#define char32_type_node c_global_trees[CTI_CHAR32_TYPE] -#define wchar_type_node c_global_trees[CTI_WCHAR_TYPE] -#define underlying_wchar_type_node c_global_trees[CTI_UNDERLYING_WCHAR_TYPE] -#define wint_type_node c_global_trees[CTI_WINT_TYPE] -#define signed_size_type_node c_global_trees[CTI_SIGNED_SIZE_TYPE] -#define unsigned_ptrdiff_type_node c_global_trees[CTI_UNSIGNED_PTRDIFF_TYPE] -#define intmax_type_node c_global_trees[CTI_INTMAX_TYPE] -#define uintmax_type_node c_global_trees[CTI_UINTMAX_TYPE] -#define widest_integer_literal_type_node c_global_trees[CTI_WIDEST_INT_LIT_TYPE] -#define widest_unsigned_literal_type_node c_global_trees[CTI_WIDEST_UINT_LIT_TYPE] - -#define sig_atomic_type_node c_global_trees[CTI_SIG_ATOMIC_TYPE] -#define int8_type_node c_global_trees[CTI_INT8_TYPE] -#define int16_type_node c_global_trees[CTI_INT16_TYPE] -#define int32_type_node c_global_trees[CTI_INT32_TYPE] -#define int64_type_node c_global_trees[CTI_INT64_TYPE] -#define uint8_type_node c_global_trees[CTI_UINT8_TYPE] -#define uint16_type_node c_global_trees[CTI_UINT16_TYPE] -#define c_uint32_type_node c_global_trees[CTI_UINT32_TYPE] -#define c_uint64_type_node c_global_trees[CTI_UINT64_TYPE] -#define int_least8_type_node c_global_trees[CTI_INT_LEAST8_TYPE] -#define int_least16_type_node c_global_trees[CTI_INT_LEAST16_TYPE] -#define int_least32_type_node c_global_trees[CTI_INT_LEAST32_TYPE] -#define int_least64_type_node c_global_trees[CTI_INT_LEAST64_TYPE] -#define uint_least8_type_node c_global_trees[CTI_UINT_LEAST8_TYPE] -#define uint_least16_type_node c_global_trees[CTI_UINT_LEAST16_TYPE] -#define uint_least32_type_node c_global_trees[CTI_UINT_LEAST32_TYPE] -#define uint_least64_type_node c_global_trees[CTI_UINT_LEAST64_TYPE] -#define int_fast8_type_node c_global_trees[CTI_INT_FAST8_TYPE] -#define int_fast16_type_node c_global_trees[CTI_INT_FAST16_TYPE] -#define int_fast32_type_node c_global_trees[CTI_INT_FAST32_TYPE] -#define int_fast64_type_node c_global_trees[CTI_INT_FAST64_TYPE] -#define uint_fast8_type_node c_global_trees[CTI_UINT_FAST8_TYPE] -#define uint_fast16_type_node c_global_trees[CTI_UINT_FAST16_TYPE] -#define uint_fast32_type_node c_global_trees[CTI_UINT_FAST32_TYPE] -#define uint_fast64_type_node c_global_trees[CTI_UINT_FAST64_TYPE] -#define intptr_type_node c_global_trees[CTI_INTPTR_TYPE] -#define uintptr_type_node c_global_trees[CTI_UINTPTR_TYPE] - -#define truthvalue_type_node c_global_trees[CTI_TRUTHVALUE_TYPE] -#define truthvalue_true_node c_global_trees[CTI_TRUTHVALUE_TRUE] -#define truthvalue_false_node c_global_trees[CTI_TRUTHVALUE_FALSE] - -#define char_array_type_node c_global_trees[CTI_CHAR_ARRAY_TYPE] -#define char16_array_type_node c_global_trees[CTI_CHAR16_ARRAY_TYPE] -#define char32_array_type_node c_global_trees[CTI_CHAR32_ARRAY_TYPE] -#define wchar_array_type_node c_global_trees[CTI_WCHAR_ARRAY_TYPE] -#define int_array_type_node c_global_trees[CTI_INT_ARRAY_TYPE] -#define string_type_node c_global_trees[CTI_STRING_TYPE] -#define const_string_type_node c_global_trees[CTI_CONST_STRING_TYPE] - -#define default_function_type c_global_trees[CTI_DEFAULT_FUNCTION_TYPE] - -#define function_name_decl_node c_global_trees[CTI_FUNCTION_NAME_DECL] -#define pretty_function_name_decl_node c_global_trees[CTI_PRETTY_FUNCTION_NAME_DECL] -#define c99_function_name_decl_node c_global_trees[CTI_C99_FUNCTION_NAME_DECL] -#define saved_function_name_decls c_global_trees[CTI_SAVED_FUNCTION_NAME_DECLS] - -/* A node for `((void) 0)'. */ -#define void_zero_node c_global_trees[CTI_VOID_ZERO] - -/* The node for C++ `__null'. */ -#define null_node c_global_trees[CTI_NULL] - -extern GTY(()) tree c_global_trees[CTI_MAX]; - -/* In a RECORD_TYPE, a sorted array of the fields of the type, not a - tree for size reasons. */ -struct GTY(()) sorted_fields_type { - int len; - tree GTY((length ("%h.len"))) elts[1]; -}; - -/* Mark which labels are explicitly declared. - These may be shadowed, and may be referenced from nested functions. */ -#define C_DECLARED_LABEL_FLAG(label) TREE_LANG_FLAG_1 (label) - -typedef enum c_language_kind -{ - clk_c = 0, /* C90, C94 or C99 */ - clk_objc = 1, /* clk_c with ObjC features. */ - clk_cxx = 2, /* ANSI/ISO C++ */ - clk_objcxx = 3 /* clk_cxx with ObjC features. */ -} -c_language_kind; - -/* To test for a specific language use c_language, defined by each - front end. For "ObjC features" or "not C++" use the macros. */ -extern c_language_kind c_language; - -#define c_dialect_cxx() ((c_language & clk_cxx) != 0) -#define c_dialect_objc() ((c_language & clk_objc) != 0) - -/* The various name of operator that appears in error messages. */ -typedef enum ref_operator { - /* NULL */ - RO_NULL, - /* array indexing */ - RO_ARRAY_INDEXING, - /* unary * */ - RO_UNARY_STAR, - /* -> */ - RO_ARROW, - /* implicit conversion */ - RO_IMPLICIT_CONVERSION -} ref_operator; - -/* Information about a statement tree. */ - -struct GTY(()) stmt_tree_s { - /* The current statement list being collected. */ - tree x_cur_stmt_list; - - /* In C++, Nonzero if we should treat statements as full - expressions. In particular, this variable is no-zero if at the - end of a statement we should destroy any temporaries created - during that statement. Similarly, if, at the end of a block, we - should destroy any local variables in this block. Normally, this - variable is nonzero, since those are the normal semantics of - C++. - - However, in order to represent aggregate initialization code as - tree structure, we use statement-expressions. The statements - within the statement expression should not result in cleanups - being run until the entire enclosing statement is complete. - - This flag has no effect in C. */ - int stmts_are_full_exprs_p; -}; - -typedef struct stmt_tree_s *stmt_tree; - -/* Global state pertinent to the current function. Some C dialects - extend this structure with additional fields. */ - -struct GTY(()) c_language_function { - /* While we are parsing the function, this contains information - about the statement-tree that we are building. */ - struct stmt_tree_s x_stmt_tree; -}; - -/* When building a statement-tree, this is the current statement list - being collected. It's TREE_CHAIN is a back-pointer to the previous - statement list. */ - -#define cur_stmt_list (current_stmt_tree ()->x_cur_stmt_list) - -/* Language-specific hooks. */ - -/* If non-NULL, this function is called after a precompile header file - is loaded. */ -extern void (*lang_post_pch_load) (void); - -extern void push_file_scope (void); -extern void pop_file_scope (void); -extern stmt_tree current_stmt_tree (void); -extern tree push_stmt_list (void); -extern tree pop_stmt_list (tree); -extern tree add_stmt (tree); -extern void push_cleanup (tree, tree, bool); -extern tree pushdecl_top_level (tree); -extern tree pushdecl (tree); -extern tree build_modify_expr (location_t, tree, tree, enum tree_code, - location_t, tree, tree); -extern tree build_indirect_ref (location_t, tree, ref_operator); - -extern int c_expand_decl (tree); - -extern int field_decl_cmp (const void *, const void *); -extern void resort_sorted_fields (void *, void *, gt_pointer_operator, - void *); -extern bool has_c_linkage (const_tree decl); - -/* Switches common to the C front ends. */ - -/* Nonzero if prepreprocessing only. */ - -extern int flag_preprocess_only; - -/* Zero means that faster, ...NonNil variants of objc_msgSend... - calls will be used in ObjC; passing nil receivers to such calls - will most likely result in crashes. */ -extern int flag_nil_receivers; - -/* Nonzero means that we will allow new ObjC exception syntax (@throw, - @try, etc.) in source code. */ -extern int flag_objc_exceptions; - -/* Nonzero means that we generate NeXT setjmp based exceptions. */ -extern int flag_objc_sjlj_exceptions; - -/* Nonzero means that code generation will be altered to support - "zero-link" execution. This currently affects ObjC only, but may - affect other languages in the future. */ -extern int flag_zero_link; - -/* Nonzero means emit an '__OBJC, __image_info' for the current translation - unit. It will inform the ObjC runtime that class definition(s) herein - contained are to replace one(s) previously loaded. */ -extern int flag_replace_objc_classes; - -/* Nonzero means don't output line number information. */ - -extern char flag_no_line_commands; - -/* Nonzero causes -E output not to be done, but directives such as - #define that have side effects are still obeyed. */ - -extern char flag_no_output; - -/* Nonzero means dump macros in some fashion; contains the 'D', 'M', - 'N' or 'U' of the command line switch. */ - -extern char flag_dump_macros; - -/* Nonzero means pass #include lines through to the output. */ - -extern char flag_dump_includes; - -/* Nonzero means process PCH files while preprocessing. */ - -extern bool flag_pch_preprocess; - -/* The file name to which we should write a precompiled header, or - NULL if no header will be written in this compile. */ - -extern const char *pch_file; - -/* Nonzero if an ISO standard was selected. It rejects macros in the - user's namespace. */ - -extern int flag_iso; - -/* Nonzero if -undef was given. It suppresses target built-in macros - and assertions. */ - -extern int flag_undef; - -/* Nonzero means don't recognize the non-ANSI builtin functions. */ - -extern int flag_no_builtin; - -/* Nonzero means don't recognize the non-ANSI builtin functions. - -ansi sets this. */ - -extern int flag_no_nonansi_builtin; - -/* Nonzero means give `double' the same size as `float'. */ - -extern int flag_short_double; - -/* Nonzero means give `wchar_t' the same size as `short'. */ - -extern int flag_short_wchar; - -/* Nonzero means allow implicit conversions between vectors with - differing numbers of subparts and/or differing element types. */ -extern int flag_lax_vector_conversions; - -/* Nonzero means allow Microsoft extensions without warnings or errors. */ -extern int flag_ms_extensions; - -/* Nonzero means don't recognize the keyword `asm'. */ - -extern int flag_no_asm; - -/* Nonzero means give string constants the type `const char *', as mandated - by the standard. */ - -extern int flag_const_strings; - -/* Nonzero means to treat bitfields as signed unless they say `unsigned'. */ - -extern int flag_signed_bitfields; - -/* Warn about #pragma directives that are not recognized. */ - -extern int warn_unknown_pragmas; /* Tri state variable. */ - -/* Warn about format/argument anomalies in calls to formatted I/O functions - (*printf, *scanf, strftime, strfmon, etc.). */ - -extern int warn_format; - - -/* C/ObjC language option variables. */ - - -/* Nonzero means allow type mismatches in conditional expressions; - just make their values `void'. */ - -extern int flag_cond_mismatch; - -/* Nonzero means enable C89 Amendment 1 features. */ - -extern int flag_isoc94; - -/* Nonzero means use the ISO C99 (or C1X) dialect of C. */ - -extern int flag_isoc99; - -/* Nonzero means use the ISO C1X dialect of C. */ - -extern int flag_isoc1x; - -/* Nonzero means that we have builtin functions, and main is an int. */ - -extern int flag_hosted; - -/* ObjC language option variables. */ - - -/* Open and close the file for outputting class declarations, if - requested (ObjC). */ - -extern int flag_gen_declaration; - -/* Tells the compiler that this is a special run. Do not perform any - compiling, instead we are to test some platform dependent features - and output a C header file with appropriate definitions. */ - -extern int print_struct_values; - -/* ???. Undocumented. */ - -extern const char *constant_string_class_name; - - -/* C++ language option variables. */ - - -/* Nonzero means don't recognize any extension keywords. */ - -extern int flag_no_gnu_keywords; - -/* Nonzero means do emit exported implementations of functions even if - they can be inlined. */ - -extern int flag_implement_inlines; - -/* Nonzero means that implicit instantiations will be emitted if needed. */ - -extern int flag_implicit_templates; - -/* Nonzero means that implicit instantiations of inline templates will be - emitted if needed, even if instantiations of non-inline templates - aren't. */ - -extern int flag_implicit_inline_templates; - -/* Nonzero means generate separate instantiation control files and - juggle them at link time. */ - -extern int flag_use_repository; - -/* Nonzero if we want to issue diagnostics that the standard says are not - required. */ - -extern int flag_optional_diags; - -/* Nonzero means we should attempt to elide constructors when possible. */ - -extern int flag_elide_constructors; - -/* Nonzero means that member functions defined in class scope are - inline by default. */ - -extern int flag_default_inline; - -/* Controls whether compiler generates 'type descriptor' that give - run-time type information. */ - -extern int flag_rtti; - -/* Nonzero if we want to conserve space in the .o files. We do this - by putting uninitialized data and runtime initialized data into - .common instead of .data at the expense of not flagging multiple - definitions. */ - -extern int flag_conserve_space; - -/* Nonzero if we want to obey access control semantics. */ - -extern int flag_access_control; - -/* Nonzero if we want to check the return value of new and avoid calling - constructors if it is a null pointer. */ - -extern int flag_check_new; - -/* The supported C++ dialects. */ - -enum cxx_dialect { - /* C++98 */ - cxx98, - /* Experimental features that are likely to become part of - C++0x. */ - cxx0x -}; - -/* The C++ dialect being used. C++98 is the default. */ -extern enum cxx_dialect cxx_dialect; - -/* Nonzero if we want the new ISO rules for pushing a new scope for `for' - initialization variables. - 0: Old rules, set by -fno-for-scope. - 2: New ISO rules, set by -ffor-scope. - 1: Try to implement new ISO rules, but with backup compatibility - (and warnings). This is the default, for now. */ - -extern int flag_new_for_scope; - -/* Nonzero if we want to emit defined symbols with common-like linkage as - weak symbols where possible, in order to conform to C++ semantics. - Otherwise, emit them as local symbols. */ - -extern int flag_weak; - -/* 0 means we want the preprocessor to not emit line directives for - the current working directory. 1 means we want it to do it. -1 - means we should decide depending on whether debugging information - is being emitted or not. */ - -extern int flag_working_directory; - -/* Nonzero to use __cxa_atexit, rather than atexit, to register - destructors for local statics and global objects. */ - -extern int flag_use_cxa_atexit; - -/* Nonzero to use __cxa_get_exception_ptr in the C++ exception-handling - logic. */ - -extern int flag_use_cxa_get_exception_ptr; - -/* Nonzero means to implement standard semantics for exception - specifications, calling unexpected if an exception is thrown that - doesn't match the specification. Zero means to treat them as - assertions and optimize accordingly, but not check them. */ - -extern int flag_enforce_eh_specs; - -/* Nonzero (the default) means to generate thread-safe code for - initializing local statics. */ - -extern int flag_threadsafe_statics; - -/* Nonzero if we want to pretty-print template specializations as the - template signature followed by the arguments. */ - -extern int flag_pretty_templates; - -/* Warn about using __null (as NULL in C++) as sentinel. For code compiled - with GCC this doesn't matter as __null is guaranteed to have the right - size. */ - -extern int warn_strict_null_sentinel; - -/* Maximum template instantiation depth. This limit is rather - arbitrary, but it exists to limit the time it takes to notice - infinite template instantiations. */ - -extern int max_tinst_depth; - -/* Nonzero means that we should not issue warnings about problems that - occur when the code is executed, because the code being processed - is not expected to be executed. This is set during parsing. This - is used for cases like sizeof() and "0 ? a : b". This is a count, - not a bool, because unexecuted expressions can nest. */ - -extern int c_inhibit_evaluation_warnings; - -/* Whether lexing has been completed, so subsequent preprocessor - errors should use the compiler's input_location. */ - -extern bool done_lexing; - -/* C types are partitioned into three subsets: object, function, and - incomplete types. */ -#define C_TYPE_OBJECT_P(type) \ - (TREE_CODE (type) != FUNCTION_TYPE && TYPE_SIZE (type)) - -#define C_TYPE_INCOMPLETE_P(type) \ - (TREE_CODE (type) != FUNCTION_TYPE && TYPE_SIZE (type) == 0) - -#define C_TYPE_FUNCTION_P(type) \ - (TREE_CODE (type) == FUNCTION_TYPE) - -/* For convenience we define a single macro to identify the class of - object or incomplete types. */ -#define C_TYPE_OBJECT_OR_INCOMPLETE_P(type) \ - (!C_TYPE_FUNCTION_P (type)) - -/* Attribute table common to the C front ends. */ -extern const struct attribute_spec c_common_attribute_table[]; -extern const struct attribute_spec c_common_format_attribute_table[]; - -/* Pointer to function to lazily generate the VAR_DECL for __FUNCTION__ etc. - ID is the identifier to use, NAME is the string. - TYPE_DEP indicates whether it depends on type of the function or not - (i.e. __PRETTY_FUNCTION__). */ - -extern tree (*make_fname_decl) (location_t, tree, int); - -/* In c-decl.c and cp/tree.c. FIXME. */ -extern void c_register_addr_space (const char *str, addr_space_t as); - -/* In c-common.c. */ -extern const char *c_addr_space_name (addr_space_t as); -extern tree identifier_global_value (tree); -extern void record_builtin_type (enum rid, const char *, tree); -extern tree build_void_list_node (void); -extern void start_fname_decls (void); -extern void finish_fname_decls (void); -extern const char *fname_as_string (int); -extern tree fname_decl (location_t, unsigned, tree); - -extern void check_function_arguments (tree, int, tree *, tree); -extern void check_function_arguments_recurse (void (*) - (void *, tree, - unsigned HOST_WIDE_INT), - void *, tree, - unsigned HOST_WIDE_INT); -extern bool check_builtin_function_arguments (tree, int, tree *); -extern void check_function_format (tree, int, tree *); -extern void set_Wformat (int); -extern tree handle_format_attribute (tree *, tree, tree, int, bool *); -extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); -extern bool attribute_takes_identifier_p (const_tree); -extern int c_common_handle_option (size_t code, const char *arg, int value, int kind); -extern bool c_common_missing_argument (const char *opt, size_t code); -extern tree c_common_type_for_mode (enum machine_mode, int); -extern tree c_common_type_for_size (unsigned int, int); -extern tree c_common_fixed_point_type_for_size (unsigned int, unsigned int, - int, int); -extern tree c_common_unsigned_type (tree); -extern tree c_common_signed_type (tree); -extern tree c_common_signed_or_unsigned_type (int, tree); -extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int); -extern bool decl_with_nonnull_addr_p (const_tree); -extern tree c_fully_fold (tree, bool, bool *); -extern tree decl_constant_value_for_optimization (tree); -extern tree c_wrap_maybe_const (tree, bool); -extern tree c_save_expr (tree); -extern tree c_common_truthvalue_conversion (location_t, tree); -extern void c_apply_type_quals_to_decl (int, tree); -extern tree c_sizeof_or_alignof_type (location_t, tree, bool, int); -extern tree c_alignof_expr (location_t, tree); -/* Print an error message for invalid operands to arith operation CODE. - NOP_EXPR is used as a special case (see truthvalue_conversion). */ -extern void binary_op_error (location_t, enum tree_code, tree, tree); -extern tree fix_string_type (tree); -extern void constant_expression_warning (tree); -extern void constant_expression_error (tree); -extern bool strict_aliasing_warning (tree, tree, tree); -extern void warnings_for_convert_and_check (tree, tree, tree); -extern tree convert_and_check (tree, tree); -extern void overflow_warning (location_t, tree); -extern void warn_logical_operator (location_t, enum tree_code, tree, - enum tree_code, tree, enum tree_code, tree); -extern void check_main_parameter_types (tree decl); -extern bool c_determine_visibility (tree); -extern bool same_scalar_type_ignoring_signedness (tree, tree); -extern void mark_valid_location_for_stdc_pragma (bool); -extern bool valid_location_for_stdc_pragma_p (void); -extern void set_float_const_decimal64 (void); -extern void clear_float_const_decimal64 (void); -extern bool float_const_decimal64_p (void); - -#define c_sizeof(LOC, T) c_sizeof_or_alignof_type (LOC, T, true, 1) -#define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, 1) - -/* Subroutine of build_binary_op, used for certain operations. */ -extern tree shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise); - -/* Subroutine of build_binary_op, used for comparison operations. - See if the operands have both been converted from subword integer types - and, if so, perhaps change them both back to their original type. */ -extern tree shorten_compare (tree *, tree *, tree *, enum tree_code *); - -extern tree pointer_int_sum (location_t, enum tree_code, tree, tree); - -/* Add qualifiers to a type, in the fashion for C. */ -extern tree c_build_qualified_type (tree, int); - -/* Build tree nodes and builtin functions common to both C and C++ language - frontends. */ -extern void c_common_nodes_and_builtins (void); - -extern void disable_builtin_function (const char *); - -extern void set_compound_literal_name (tree decl); - -extern tree build_va_arg (location_t, tree, tree); - -extern unsigned int c_common_init_options (unsigned int, const char **); -extern bool c_common_post_options (const char **); -extern bool c_common_init (void); -extern void c_common_finish (void); -extern void c_common_parse_file (int); -extern alias_set_type c_common_get_alias_set (tree); -extern void c_register_builtin_type (tree, const char*); -extern bool c_promoting_integer_type_p (const_tree); -extern int self_promoting_args_p (const_tree); -extern tree strip_pointer_operator (tree); -extern tree strip_pointer_or_array_types (tree); -extern HOST_WIDE_INT c_common_to_target_charset (HOST_WIDE_INT); - -/* This is the basic parsing function. */ -extern void c_parse_file (void); -/* This is misnamed, it actually performs end-of-compilation processing. */ -extern void finish_file (void); - - -/* These macros provide convenient access to the various _STMT nodes. */ - -/* Nonzero if a given STATEMENT_LIST represents the outermost binding - if a statement expression. */ -#define STATEMENT_LIST_STMT_EXPR(NODE) \ - TREE_LANG_FLAG_1 (STATEMENT_LIST_CHECK (NODE)) - -/* Nonzero if a label has been added to the statement list. */ -#define STATEMENT_LIST_HAS_LABEL(NODE) \ - TREE_LANG_FLAG_3 (STATEMENT_LIST_CHECK (NODE)) - -/* C_MAYBE_CONST_EXPR accessors. */ -#define C_MAYBE_CONST_EXPR_PRE(NODE) \ - TREE_OPERAND (C_MAYBE_CONST_EXPR_CHECK (NODE), 0) -#define C_MAYBE_CONST_EXPR_EXPR(NODE) \ - TREE_OPERAND (C_MAYBE_CONST_EXPR_CHECK (NODE), 1) -#define C_MAYBE_CONST_EXPR_INT_OPERANDS(NODE) \ - TREE_LANG_FLAG_0 (C_MAYBE_CONST_EXPR_CHECK (NODE)) -#define C_MAYBE_CONST_EXPR_NON_CONST(NODE) \ - TREE_LANG_FLAG_1 (C_MAYBE_CONST_EXPR_CHECK (NODE)) -#define EXPR_INT_CONST_OPERANDS(EXPR) \ - (INTEGRAL_TYPE_P (TREE_TYPE (EXPR)) \ - && (TREE_CODE (EXPR) == INTEGER_CST \ - || (TREE_CODE (EXPR) == C_MAYBE_CONST_EXPR \ - && C_MAYBE_CONST_EXPR_INT_OPERANDS (EXPR)))) - -/* In a FIELD_DECL, nonzero if the decl was originally a bitfield. */ -#define DECL_C_BIT_FIELD(NODE) \ - (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1) -#define SET_DECL_C_BIT_FIELD(NODE) \ - (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1) -#define CLEAR_DECL_C_BIT_FIELD(NODE) \ - (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 0) - -extern tree do_case (location_t, tree, tree); -extern tree build_stmt (location_t, enum tree_code, ...); -extern tree build_case_label (location_t, tree, tree, tree); - -/* These functions must be defined by each front-end which implements - a variant of the C language. They are used in c-common.c. */ - -extern tree build_unary_op (location_t, enum tree_code, tree, int); -extern tree build_binary_op (location_t, enum tree_code, tree, tree, int); -extern tree perform_integral_promotions (tree); - -/* These functions must be defined by each front-end which implements - a variant of the C language. They are used by port files. */ - -extern tree default_conversion (tree); - -/* Given two integer or real types, return the type for their sum. - Given two compatible ANSI C types, returns the merged type. */ - -extern tree common_type (tree, tree); - -extern tree decl_constant_value (tree); - -/* Handle increment and decrement of boolean types. */ -extern tree boolean_increment (enum tree_code, tree); - -extern int case_compare (splay_tree_key, splay_tree_key); - -extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree, tree); - -extern void c_do_switch_warnings (splay_tree, location_t, tree, tree); - -extern tree build_function_call (location_t, tree, tree); - -extern tree build_function_call_vec (location_t, tree, - VEC(tree,gc) *, VEC(tree,gc) *); - -extern tree resolve_overloaded_builtin (location_t, tree, VEC(tree,gc) *); - -extern tree finish_label_address_expr (tree, location_t); - -/* Same function prototype, but the C and C++ front ends have - different implementations. Used in c-common.c. */ -extern tree lookup_label (tree); -extern tree lookup_name (tree); -extern bool lvalue_p (const_tree); - -extern bool vector_targets_convertible_p (const_tree t1, const_tree t2); -extern bool vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note); - -extern rtx c_expand_expr (tree, rtx, enum machine_mode, int, rtx *); - -extern void init_c_lex (void); - -extern void c_cpp_builtins (cpp_reader *); -extern void c_cpp_builtins_optimize_pragma (cpp_reader *, tree, tree); -extern bool c_cpp_error (cpp_reader *, int, int, location_t, unsigned int, - const char *, va_list *) - ATTRIBUTE_GCC_DIAG(6,0); - -/* Positive if an implicit `extern "C"' scope has just been entered; - negative if such a scope has just been exited. */ -extern GTY(()) int pending_lang_change; - -/* Information recorded about each file examined during compilation. */ - -struct c_fileinfo -{ - int time; /* Time spent in the file. */ - - /* Flags used only by C++. - INTERFACE_ONLY nonzero means that we are in an "interface" section - of the compiler. INTERFACE_UNKNOWN nonzero means we cannot trust - the value of INTERFACE_ONLY. If INTERFACE_UNKNOWN is zero and - INTERFACE_ONLY is zero, it means that we are responsible for - exporting definitions that others might need. */ - short interface_only; - short interface_unknown; -}; - -struct c_fileinfo *get_fileinfo (const char *); -extern void dump_time_statistics (void); - -extern bool c_dump_tree (void *, tree); - -extern void verify_sequence_points (tree); - -extern tree fold_offsetof (tree, tree); - -/* Places where an lvalue, or modifiable lvalue, may be required. - Used to select diagnostic messages in lvalue_error and - readonly_error. */ -enum lvalue_use { - lv_assign, - lv_increment, - lv_decrement, - lv_addressof, - lv_asm -}; - -extern void lvalue_error (enum lvalue_use); - -extern int complete_array_type (tree *, tree, bool); - -extern tree builtin_type_for_size (int, bool); - -extern void warn_array_subscript_with_type_char (tree); -extern void warn_about_parentheses (enum tree_code, - enum tree_code, tree, - enum tree_code, tree); -extern void warn_for_unused_label (tree label); -extern void warn_for_div_by_zero (location_t, tree divisor); -extern void warn_for_sign_compare (location_t, - tree orig_op0, tree orig_op1, - tree op0, tree op1, - tree result_type, - enum tree_code resultcode); -extern void set_underlying_type (tree x); -extern bool is_typedef_decl (tree x); -extern VEC(tree,gc) *make_tree_vector (void); -extern void release_tree_vector (VEC(tree,gc) *); -extern VEC(tree,gc) *make_tree_vector_single (tree); -extern VEC(tree,gc) *make_tree_vector_copy (const VEC(tree,gc) *); - -/* In c-gimplify.c */ -extern void c_genericize (tree); -extern int c_gimplify_expr (tree *, gimple_seq *, gimple_seq *); -extern tree c_build_bind_expr (location_t, tree, tree); - -/* In c-pch.c */ -extern void pch_init (void); -extern int c_common_valid_pch (cpp_reader *pfile, const char *name, int fd); -extern void c_common_read_pch (cpp_reader *pfile, const char *name, int fd, - const char *orig); -extern void c_common_write_pch (void); -extern void c_common_no_more_pch (void); -extern void c_common_pch_pragma (cpp_reader *pfile, const char *); -extern void c_common_print_pch_checksum (FILE *f); - -/* In *-checksum.c */ -extern const unsigned char executable_checksum[16]; - -/* In c-cppbuiltin.c */ -extern void builtin_define_std (const char *macro); -extern void builtin_define_with_value (const char *, const char *, int); -extern void c_stddef_cpp_builtins (void); -extern void fe_file_change (const struct line_map *); -extern void c_parse_error (const char *, enum cpp_ttype, tree, unsigned char); - -/* Objective-C / Objective-C++ entry points. */ - -/* The following ObjC/ObjC++ functions are called by the C and/or C++ - front-ends; they all must have corresponding stubs in stub-objc.c. */ -extern tree objc_is_class_name (tree); -extern tree objc_is_object_ptr (tree); -extern void objc_check_decl (tree); -extern int objc_is_reserved_word (tree); -extern bool objc_compare_types (tree, tree, int, tree); -extern void objc_volatilize_decl (tree); -extern bool objc_type_quals_match (tree, tree); -extern tree objc_rewrite_function_call (tree, tree); -extern tree objc_message_selector (void); -extern tree objc_lookup_ivar (tree, tree); -extern void objc_clear_super_receiver (void); -extern int objc_is_public (tree, tree); -extern tree objc_is_id (tree); -extern void objc_declare_alias (tree, tree); -extern void objc_declare_class (tree); -extern void objc_declare_protocols (tree); -extern tree objc_build_message_expr (tree); -extern tree objc_finish_message_expr (tree, tree, tree); -extern tree objc_build_selector_expr (location_t, tree); -extern tree objc_build_protocol_expr (tree); -extern tree objc_build_encode_expr (tree); -extern tree objc_build_string_object (tree); -extern tree objc_get_protocol_qualified_type (tree, tree); -extern tree objc_get_class_reference (tree); -extern tree objc_get_class_ivars (tree); -extern void objc_start_class_interface (tree, tree, tree); -extern void objc_start_category_interface (tree, tree, tree); -extern void objc_start_protocol (tree, tree); -extern void objc_continue_interface (void); -extern void objc_finish_interface (void); -extern void objc_start_class_implementation (tree, tree); -extern void objc_start_category_implementation (tree, tree); -extern void objc_continue_implementation (void); -extern void objc_finish_implementation (void); -extern void objc_set_visibility (int); -extern void objc_set_method_type (enum tree_code); -extern tree objc_build_method_signature (tree, tree, tree, bool); -extern void objc_add_method_declaration (tree); -extern void objc_start_method_definition (tree); -extern void objc_finish_method_definition (tree); -extern void objc_add_instance_variable (tree); -extern tree objc_build_keyword_decl (tree, tree, tree); -extern tree objc_build_throw_stmt (location_t, tree); -extern void objc_begin_try_stmt (location_t, tree); -extern tree objc_finish_try_stmt (void); -extern void objc_begin_catch_clause (tree); -extern void objc_finish_catch_clause (void); -extern void objc_build_finally_clause (location_t, tree); -extern tree objc_build_synchronized (location_t, tree, tree); -extern int objc_static_init_needed_p (void); -extern tree objc_generate_static_init_call (tree); -extern tree objc_generate_write_barrier (tree, enum tree_code, tree); - -/* The following are provided by the C and C++ front-ends, and called by - ObjC/ObjC++. */ -extern void *objc_get_current_scope (void); -extern void objc_mark_locals_volatile (void *); - -/* In c-ppoutput.c */ -extern void init_pp_output (FILE *); -extern void preprocess_file (cpp_reader *); -extern void pp_file_change (const struct line_map *); -extern void pp_dir_change (cpp_reader *, const char *); -extern bool check_missing_format_attribute (tree, tree); - -/* In c-omp.c */ -extern tree c_finish_omp_master (location_t, tree); -extern tree c_finish_omp_critical (location_t, tree, tree); -extern tree c_finish_omp_ordered (location_t, tree); -extern void c_finish_omp_barrier (location_t); -extern tree c_finish_omp_atomic (location_t, enum tree_code, tree, tree); -extern void c_finish_omp_flush (location_t); -extern void c_finish_omp_taskwait (location_t); -extern tree c_finish_omp_for (location_t, tree, tree, tree, tree, tree, tree); -extern void c_split_parallel_clauses (location_t, tree, tree *, tree *); -extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); - -/* Not in c-omp.c; provided by the front end. */ -extern bool c_omp_sharing_predetermined (tree); -extern tree c_omp_remap_decl (tree, bool); -extern void record_types_used_by_current_var_decl (tree); - -#endif /* ! GCC_C_COMMON_H */ diff --git a/gcc/c-config-lang.in b/gcc/c-config-lang.in index d3cd6f9..2565186 100644 --- a/gcc/c-config-lang.in +++ b/gcc/c-config-lang.in @@ -22,4 +22,4 @@ # files used by C that have garbage collection GTY macros in them # which therefore need to be scanned by gengtype.c. -gtfiles="\$(srcdir)/c-lang.c \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-pragma.h \$(srcdir)/c-pragma.c \$(srcdir)/c-objc-common.c \$(srcdir)/c-parser.c \$(srcdir)/c-lang.h" +gtfiles="\$(srcdir)/c-lang.c \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/c-objc-common.c \$(srcdir)/c-parser.c \$(srcdir)/c-lang.h" diff --git a/gcc/c-convert.c b/gcc/c-convert.c index 09638d5..4de3cdb 100644 --- a/gcc/c-convert.c +++ b/gcc/c-convert.c @@ -31,7 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "flags.h" #include "convert.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "c-tree.h" #include "langhooks.h" #include "toplev.h" diff --git a/gcc/c-cppbuiltin.c b/gcc/c-cppbuiltin.c deleted file mode 100644 index 6bbdb46..0000000 --- a/gcc/c-cppbuiltin.c +++ /dev/null @@ -1,1107 +0,0 @@ -/* Define builtin-in macros for the C family front ends. - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 - 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 "tree.h" -#include "version.h" -#include "flags.h" -#include "c-common.h" -#include "c-pragma.h" -#include "output.h" -#include "except.h" /* For USING_SJLJ_EXCEPTIONS. */ -#include "debug.h" /* For dwarf2out_do_cfi_asm. */ -#include "toplev.h" -#include "tm_p.h" /* For TARGET_CPU_CPP_BUILTINS & friends. */ -#include "target.h" - -#ifndef TARGET_OS_CPP_BUILTINS -# define TARGET_OS_CPP_BUILTINS() -#endif - -#ifndef TARGET_OBJFMT_CPP_BUILTINS -# define TARGET_OBJFMT_CPP_BUILTINS() -#endif - -#ifndef REGISTER_PREFIX -#define REGISTER_PREFIX "" -#endif - -/* Non-static as some targets don't use it. */ -void builtin_define_std (const char *) ATTRIBUTE_UNUSED; -static void builtin_define_with_int_value (const char *, HOST_WIDE_INT); -static void builtin_define_with_hex_fp_value (const char *, tree, - int, const char *, - const char *, - const char *); -static void builtin_define_stdint_macros (void); -static void builtin_define_constants (const char *, tree); -static void builtin_define_type_max (const char *, tree); -static void builtin_define_type_minmax (const char *, const char *, tree); -static void builtin_define_type_precision (const char *, tree); -static void builtin_define_type_sizeof (const char *, tree); -static void builtin_define_float_constants (const char *, - const char *, - const char *, - tree); -static void define__GNUC__ (void); - -/* Define NAME with value TYPE precision. */ -static void -builtin_define_type_precision (const char *name, tree type) -{ - builtin_define_with_int_value (name, TYPE_PRECISION (type)); -} - -/* Define NAME with value TYPE size_unit. */ -static void -builtin_define_type_sizeof (const char *name, tree type) -{ - builtin_define_with_int_value (name, - tree_low_cst (TYPE_SIZE_UNIT (type), 1)); -} - -/* Define the float.h constants for TYPE using NAME_PREFIX, FP_SUFFIX, - and FP_CAST. */ -static void -builtin_define_float_constants (const char *name_prefix, - const char *fp_suffix, - const char *fp_cast, - tree type) -{ - /* Used to convert radix-based values to base 10 values in several cases. - - In the max_exp -> max_10_exp conversion for 128-bit IEEE, we need at - least 6 significant digits for correct results. Using the fraction - formed by (log(2)*1e6)/(log(10)*1e6) overflows a 32-bit integer as an - intermediate; perhaps someone can find a better approximation, in the - mean time, I suspect using doubles won't harm the bootstrap here. */ - - const double log10_2 = .30102999566398119521; - double log10_b; - const struct real_format *fmt; - const struct real_format *ldfmt; - - char name[64], buf[128]; - int dig, min_10_exp, max_10_exp; - int decimal_dig; - int type_decimal_dig; - - fmt = REAL_MODE_FORMAT (TYPE_MODE (type)); - gcc_assert (fmt->b != 10); - ldfmt = REAL_MODE_FORMAT (TYPE_MODE (long_double_type_node)); - gcc_assert (ldfmt->b != 10); - - /* The radix of the exponent representation. */ - if (type == float_type_node) - builtin_define_with_int_value ("__FLT_RADIX__", fmt->b); - log10_b = log10_2; - - /* The number of radix digits, p, in the floating-point significand. */ - sprintf (name, "__%s_MANT_DIG__", name_prefix); - builtin_define_with_int_value (name, fmt->p); - - /* The number of decimal digits, q, such that any floating-point number - with q decimal digits can be rounded into a floating-point number with - p radix b digits and back again without change to the q decimal digits, - - p log10 b if b is a power of 10 - floor((p - 1) log10 b) otherwise - */ - dig = (fmt->p - 1) * log10_b; - sprintf (name, "__%s_DIG__", name_prefix); - builtin_define_with_int_value (name, dig); - - /* The minimum negative int x such that b**(x-1) is a normalized float. */ - sprintf (name, "__%s_MIN_EXP__", name_prefix); - sprintf (buf, "(%d)", fmt->emin); - builtin_define_with_value (name, buf, 0); - - /* The minimum negative int x such that 10**x is a normalized float, - - ceil (log10 (b ** (emin - 1))) - = ceil (log10 (b) * (emin - 1)) - - Recall that emin is negative, so the integer truncation calculates - the ceiling, not the floor, in this case. */ - min_10_exp = (fmt->emin - 1) * log10_b; - sprintf (name, "__%s_MIN_10_EXP__", name_prefix); - sprintf (buf, "(%d)", min_10_exp); - builtin_define_with_value (name, buf, 0); - - /* The maximum int x such that b**(x-1) is a representable float. */ - sprintf (name, "__%s_MAX_EXP__", name_prefix); - builtin_define_with_int_value (name, fmt->emax); - - /* The maximum int x such that 10**x is in the range of representable - finite floating-point numbers, - - floor (log10((1 - b**-p) * b**emax)) - = floor (log10(1 - b**-p) + log10(b**emax)) - = floor (log10(1 - b**-p) + log10(b)*emax) - - The safest thing to do here is to just compute this number. But since - we don't link cc1 with libm, we cannot. We could implement log10 here - a series expansion, but that seems too much effort because: - - Note that the first term, for all extant p, is a number exceedingly close - to zero, but slightly negative. Note that the second term is an integer - scaling an irrational number, and that because of the floor we are only - interested in its integral portion. - - In order for the first term to have any effect on the integral portion - of the second term, the second term has to be exceedingly close to an - integer itself (e.g. 123.000000000001 or something). Getting a result - that close to an integer requires that the irrational multiplicand have - a long series of zeros in its expansion, which doesn't occur in the - first 20 digits or so of log10(b). - - Hand-waving aside, crunching all of the sets of constants above by hand - does not yield a case for which the first term is significant, which - in the end is all that matters. */ - max_10_exp = fmt->emax * log10_b; - sprintf (name, "__%s_MAX_10_EXP__", name_prefix); - builtin_define_with_int_value (name, max_10_exp); - - /* The number of decimal digits, n, such that any floating-point number - can be rounded to n decimal digits and back again without change to - the value. - - p * log10(b) if b is a power of 10 - ceil(1 + p * log10(b)) otherwise - - The only macro we care about is this number for the widest supported - floating type, but we want this value for rendering constants below. */ - { - double d_decimal_dig - = 1 + (fmt->p < ldfmt->p ? ldfmt->p : fmt->p) * log10_b; - decimal_dig = d_decimal_dig; - if (decimal_dig < d_decimal_dig) - decimal_dig++; - } - /* Similar, for this type rather than long double. */ - { - double type_d_decimal_dig = 1 + fmt->p * log10_b; - type_decimal_dig = type_d_decimal_dig; - if (type_decimal_dig < type_d_decimal_dig) - type_decimal_dig++; - } - if (type == long_double_type_node) - builtin_define_with_int_value ("__DECIMAL_DIG__", decimal_dig); - else - { - sprintf (name, "__%s_DECIMAL_DIG__", name_prefix); - builtin_define_with_int_value (name, type_decimal_dig); - } - - /* Since, for the supported formats, B is always a power of 2, we - construct the following numbers directly as a hexadecimal - constants. */ - get_max_float (fmt, buf, sizeof (buf)); - - sprintf (name, "__%s_MAX__", name_prefix); - builtin_define_with_hex_fp_value (name, type, decimal_dig, buf, fp_suffix, fp_cast); - - /* The minimum normalized positive floating-point number, - b**(emin-1). */ - sprintf (name, "__%s_MIN__", name_prefix); - sprintf (buf, "0x1p%d", fmt->emin - 1); - builtin_define_with_hex_fp_value (name, type, decimal_dig, buf, fp_suffix, fp_cast); - - /* The difference between 1 and the least value greater than 1 that is - representable in the given floating point type, b**(1-p). */ - sprintf (name, "__%s_EPSILON__", name_prefix); - if (fmt->pnan < fmt->p) - /* This is an IBM extended double format, so 1.0 + any double is - representable precisely. */ - sprintf (buf, "0x1p%d", fmt->emin - fmt->p); - else - sprintf (buf, "0x1p%d", 1 - fmt->p); - builtin_define_with_hex_fp_value (name, type, decimal_dig, buf, fp_suffix, fp_cast); - - /* For C++ std::numeric_limits::denorm_min. The minimum denormalized - positive floating-point number, b**(emin-p). Zero for formats that - don't support denormals. */ - sprintf (name, "__%s_DENORM_MIN__", name_prefix); - if (fmt->has_denorm) - { - sprintf (buf, "0x1p%d", fmt->emin - fmt->p); - builtin_define_with_hex_fp_value (name, type, decimal_dig, - buf, fp_suffix, fp_cast); - } - else - { - sprintf (buf, "0.0%s", fp_suffix); - builtin_define_with_value (name, buf, 0); - } - - sprintf (name, "__%s_HAS_DENORM__", name_prefix); - builtin_define_with_value (name, fmt->has_denorm ? "1" : "0", 0); - - /* For C++ std::numeric_limits::has_infinity. */ - sprintf (name, "__%s_HAS_INFINITY__", name_prefix); - builtin_define_with_int_value (name, - MODE_HAS_INFINITIES (TYPE_MODE (type))); - /* For C++ std::numeric_limits::has_quiet_NaN. We do not have a - predicate to distinguish a target that has both quiet and - signalling NaNs from a target that has only quiet NaNs or only - signalling NaNs, so we assume that a target that has any kind of - NaN has quiet NaNs. */ - sprintf (name, "__%s_HAS_QUIET_NAN__", name_prefix); - builtin_define_with_int_value (name, MODE_HAS_NANS (TYPE_MODE (type))); -} - -/* Define __DECx__ constants for TYPE using NAME_PREFIX and SUFFIX. */ -static void -builtin_define_decimal_float_constants (const char *name_prefix, - const char *suffix, - tree type) -{ - const struct real_format *fmt; - char name[64], buf[128], *p; - int digits; - - fmt = REAL_MODE_FORMAT (TYPE_MODE (type)); - - /* The number of radix digits, p, in the significand. */ - sprintf (name, "__%s_MANT_DIG__", name_prefix); - builtin_define_with_int_value (name, fmt->p); - - /* The minimum negative int x such that b**(x-1) is a normalized float. */ - sprintf (name, "__%s_MIN_EXP__", name_prefix); - sprintf (buf, "(%d)", fmt->emin); - builtin_define_with_value (name, buf, 0); - - /* The maximum int x such that b**(x-1) is a representable float. */ - sprintf (name, "__%s_MAX_EXP__", name_prefix); - builtin_define_with_int_value (name, fmt->emax); - - /* Compute the minimum representable value. */ - sprintf (name, "__%s_MIN__", name_prefix); - sprintf (buf, "1E%d%s", fmt->emin - 1, suffix); - builtin_define_with_value (name, buf, 0); - - /* Compute the maximum representable value. */ - sprintf (name, "__%s_MAX__", name_prefix); - p = buf; - for (digits = fmt->p; digits; digits--) - { - *p++ = '9'; - if (digits == fmt->p) - *p++ = '.'; - } - *p = 0; - /* fmt->p plus 1, to account for the decimal point and fmt->emax - minus 1 because the digits are nines, not 1.0. */ - sprintf (&buf[fmt->p + 1], "E%d%s", fmt->emax - 1, suffix); - builtin_define_with_value (name, buf, 0); - - /* Compute epsilon (the difference between 1 and least value greater - than 1 representable). */ - sprintf (name, "__%s_EPSILON__", name_prefix); - sprintf (buf, "1E-%d%s", fmt->p - 1, suffix); - builtin_define_with_value (name, buf, 0); - - /* Minimum subnormal positive decimal value. */ - sprintf (name, "__%s_SUBNORMAL_MIN__", name_prefix); - p = buf; - for (digits = fmt->p; digits > 1; digits--) - { - *p++ = '0'; - if (digits == fmt->p) - *p++ = '.'; - } - *p = 0; - sprintf (&buf[fmt->p], "1E%d%s", fmt->emin - 1, suffix); - builtin_define_with_value (name, buf, 0); -} - -/* Define fixed-point constants for TYPE using NAME_PREFIX and SUFFIX. */ - -static void -builtin_define_fixed_point_constants (const char *name_prefix, - const char *suffix, - tree type) -{ - char name[64], buf[256], *new_buf; - int i, mod; - - sprintf (name, "__%s_FBIT__", name_prefix); - builtin_define_with_int_value (name, TYPE_FBIT (type)); - - sprintf (name, "__%s_IBIT__", name_prefix); - builtin_define_with_int_value (name, TYPE_IBIT (type)); - - /* If there is no suffix, defines are for fixed-point modes. - We just return. */ - if (strcmp (suffix, "") == 0) - return; - - if (TYPE_UNSIGNED (type)) - { - sprintf (name, "__%s_MIN__", name_prefix); - sprintf (buf, "0.0%s", suffix); - builtin_define_with_value (name, buf, 0); - } - else - { - sprintf (name, "__%s_MIN__", name_prefix); - if (ALL_ACCUM_MODE_P (TYPE_MODE (type))) - sprintf (buf, "(-0X1P%d%s-0X1P%d%s)", TYPE_IBIT (type) - 1, suffix, - TYPE_IBIT (type) - 1, suffix); - else - sprintf (buf, "(-0.5%s-0.5%s)", suffix, suffix); - builtin_define_with_value (name, buf, 0); - } - - sprintf (name, "__%s_MAX__", name_prefix); - sprintf (buf, "0X"); - new_buf = buf + 2; - mod = (TYPE_FBIT (type) + TYPE_IBIT (type)) % 4; - if (mod) - sprintf (new_buf++, "%x", (1 << mod) - 1); - for (i = 0; i < (TYPE_FBIT (type) + TYPE_IBIT (type)) / 4; i++) - sprintf (new_buf++, "F"); - sprintf (new_buf, "P-%d%s", TYPE_FBIT (type), suffix); - builtin_define_with_value (name, buf, 0); - - sprintf (name, "__%s_EPSILON__", name_prefix); - sprintf (buf, "0x1P-%d%s", TYPE_FBIT (type), suffix); - builtin_define_with_value (name, buf, 0); -} - -/* Define __GNUC__, __GNUC_MINOR__ and __GNUC_PATCHLEVEL__. */ -static void -define__GNUC__ (void) -{ - int major, minor, patchlevel; - - if (sscanf (BASEVER, "%d.%d.%d", &major, &minor, &patchlevel) != 3) - { - sscanf (BASEVER, "%d.%d", &major, &minor); - patchlevel = 0; - } - cpp_define_formatted (parse_in, "__GNUC__=%d", major); - cpp_define_formatted (parse_in, "__GNUC_MINOR__=%d", minor); - cpp_define_formatted (parse_in, "__GNUC_PATCHLEVEL__=%d", patchlevel); - - if (c_dialect_cxx ()) - cpp_define_formatted (parse_in, "__GNUG__=%d", major); -} - -/* Define macros used by . */ -static void -builtin_define_stdint_macros (void) -{ - builtin_define_type_max ("__INTMAX_MAX__", intmax_type_node); - builtin_define_constants ("__INTMAX_C", intmax_type_node); - builtin_define_type_max ("__UINTMAX_MAX__", uintmax_type_node); - builtin_define_constants ("__UINTMAX_C", uintmax_type_node); - if (sig_atomic_type_node) - builtin_define_type_minmax ("__SIG_ATOMIC_MIN__", "__SIG_ATOMIC_MAX__", - sig_atomic_type_node); - if (int8_type_node) - builtin_define_type_max ("__INT8_MAX__", int8_type_node); - if (int16_type_node) - builtin_define_type_max ("__INT16_MAX__", int16_type_node); - if (int32_type_node) - builtin_define_type_max ("__INT32_MAX__", int32_type_node); - if (int64_type_node) - builtin_define_type_max ("__INT64_MAX__", int64_type_node); - if (uint8_type_node) - builtin_define_type_max ("__UINT8_MAX__", uint8_type_node); - if (uint16_type_node) - builtin_define_type_max ("__UINT16_MAX__", uint16_type_node); - if (c_uint32_type_node) - builtin_define_type_max ("__UINT32_MAX__", c_uint32_type_node); - if (c_uint64_type_node) - builtin_define_type_max ("__UINT64_MAX__", c_uint64_type_node); - if (int_least8_type_node) - { - builtin_define_type_max ("__INT_LEAST8_MAX__", int_least8_type_node); - builtin_define_constants ("__INT8_C", int_least8_type_node); - } - if (int_least16_type_node) - { - builtin_define_type_max ("__INT_LEAST16_MAX__", int_least16_type_node); - builtin_define_constants ("__INT16_C", int_least16_type_node); - } - if (int_least32_type_node) - { - builtin_define_type_max ("__INT_LEAST32_MAX__", int_least32_type_node); - builtin_define_constants ("__INT32_C", int_least32_type_node); - } - if (int_least64_type_node) - { - builtin_define_type_max ("__INT_LEAST64_MAX__", int_least64_type_node); - builtin_define_constants ("__INT64_C", int_least64_type_node); - } - if (uint_least8_type_node) - { - builtin_define_type_max ("__UINT_LEAST8_MAX__", uint_least8_type_node); - builtin_define_constants ("__UINT8_C", uint_least8_type_node); - } - if (uint_least16_type_node) - { - builtin_define_type_max ("__UINT_LEAST16_MAX__", uint_least16_type_node); - builtin_define_constants ("__UINT16_C", uint_least16_type_node); - } - if (uint_least32_type_node) - { - builtin_define_type_max ("__UINT_LEAST32_MAX__", uint_least32_type_node); - builtin_define_constants ("__UINT32_C", uint_least32_type_node); - } - if (uint_least64_type_node) - { - builtin_define_type_max ("__UINT_LEAST64_MAX__", uint_least64_type_node); - builtin_define_constants ("__UINT64_C", uint_least64_type_node); - } - if (int_fast8_type_node) - builtin_define_type_max ("__INT_FAST8_MAX__", int_fast8_type_node); - if (int_fast16_type_node) - builtin_define_type_max ("__INT_FAST16_MAX__", int_fast16_type_node); - if (int_fast32_type_node) - builtin_define_type_max ("__INT_FAST32_MAX__", int_fast32_type_node); - if (int_fast64_type_node) - builtin_define_type_max ("__INT_FAST64_MAX__", int_fast64_type_node); - if (uint_fast8_type_node) - builtin_define_type_max ("__UINT_FAST8_MAX__", uint_fast8_type_node); - if (uint_fast16_type_node) - builtin_define_type_max ("__UINT_FAST16_MAX__", uint_fast16_type_node); - if (uint_fast32_type_node) - builtin_define_type_max ("__UINT_FAST32_MAX__", uint_fast32_type_node); - if (uint_fast64_type_node) - builtin_define_type_max ("__UINT_FAST64_MAX__", uint_fast64_type_node); - if (intptr_type_node) - builtin_define_type_max ("__INTPTR_MAX__", intptr_type_node); - if (uintptr_type_node) - builtin_define_type_max ("__UINTPTR_MAX__", uintptr_type_node); -} - -/* Adjust the optimization macros when a #pragma GCC optimization is done to - reflect the current level. */ -void -c_cpp_builtins_optimize_pragma (cpp_reader *pfile, tree prev_tree, - tree cur_tree) -{ - struct cl_optimization *prev = TREE_OPTIMIZATION (prev_tree); - struct cl_optimization *cur = TREE_OPTIMIZATION (cur_tree); - bool prev_fast_math; - bool cur_fast_math; - - /* -undef turns off target-specific built-ins. */ - if (flag_undef) - return; - - /* Other target-independent built-ins determined by command-line - options. */ - if (!prev->optimize_size && cur->optimize_size) - cpp_define (pfile, "__OPTIMIZE_SIZE__"); - else if (prev->optimize_size && !cur->optimize_size) - cpp_undef (pfile, "__OPTIMIZE_SIZE__"); - - if (!prev->optimize && cur->optimize) - cpp_define (pfile, "__OPTIMIZE__"); - else if (prev->optimize && !cur->optimize) - cpp_undef (pfile, "__OPTIMIZE__"); - - prev_fast_math = fast_math_flags_struct_set_p (prev); - cur_fast_math = fast_math_flags_struct_set_p (cur); - if (!prev_fast_math && cur_fast_math) - cpp_define (pfile, "__FAST_MATH__"); - else if (prev_fast_math && !cur_fast_math) - cpp_undef (pfile, "__FAST_MATH__"); - - if (!prev->flag_signaling_nans && cur->flag_signaling_nans) - cpp_define (pfile, "__SUPPORT_SNAN__"); - else if (prev->flag_signaling_nans && !cur->flag_signaling_nans) - cpp_undef (pfile, "__SUPPORT_SNAN__"); - - if (!prev->flag_finite_math_only && cur->flag_finite_math_only) - { - cpp_undef (pfile, "__FINITE_MATH_ONLY__"); - cpp_define (pfile, "__FINITE_MATH_ONLY__=1"); - } - else if (!prev->flag_finite_math_only && cur->flag_finite_math_only) - { - cpp_undef (pfile, "__FINITE_MATH_ONLY__"); - cpp_define (pfile, "__FINITE_MATH_ONLY__=0"); - } -} - - -/* Hook that registers front end and target-specific built-ins. */ -void -c_cpp_builtins (cpp_reader *pfile) -{ - /* -undef turns off target-specific built-ins. */ - if (flag_undef) - return; - - define__GNUC__ (); - - /* For stddef.h. They require macros defined in c-common.c. */ - c_stddef_cpp_builtins (); - - if (c_dialect_cxx ()) - { - if (flag_weak && SUPPORTS_ONE_ONLY) - cpp_define (pfile, "__GXX_WEAK__=1"); - else - cpp_define (pfile, "__GXX_WEAK__=0"); - if (warn_deprecated) - cpp_define (pfile, "__DEPRECATED"); - if (flag_rtti) - cpp_define (pfile, "__GXX_RTTI"); - if (cxx_dialect == cxx0x) - cpp_define (pfile, "__GXX_EXPERIMENTAL_CXX0X__"); - } - /* Note that we define this for C as well, so that we know if - __attribute__((cleanup)) will interface with EH. */ - if (flag_exceptions) - cpp_define (pfile, "__EXCEPTIONS"); - - /* Represents the C++ ABI version, always defined so it can be used while - preprocessing C and assembler. */ - if (flag_abi_version == 0) - /* Use a very large value so that: - - #if __GXX_ABI_VERSION >= - - will work whether the user explicitly says "-fabi-version=x" or - "-fabi-version=0". Do not use INT_MAX because that will be - different from system to system. */ - builtin_define_with_int_value ("__GXX_ABI_VERSION", 999999); - else if (flag_abi_version == 1) - /* Due to a historical accident, this version had the value - "102". */ - builtin_define_with_int_value ("__GXX_ABI_VERSION", 102); - else - /* Newer versions have values 1002, 1003, .... */ - builtin_define_with_int_value ("__GXX_ABI_VERSION", - 1000 + flag_abi_version); - - /* libgcc needs to know this. */ - if (USING_SJLJ_EXCEPTIONS) - cpp_define (pfile, "__USING_SJLJ_EXCEPTIONS__"); - - /* limits.h and stdint.h need to know these. */ - builtin_define_type_max ("__SCHAR_MAX__", signed_char_type_node); - builtin_define_type_max ("__SHRT_MAX__", short_integer_type_node); - builtin_define_type_max ("__INT_MAX__", integer_type_node); - builtin_define_type_max ("__LONG_MAX__", long_integer_type_node); - builtin_define_type_max ("__LONG_LONG_MAX__", long_long_integer_type_node); - builtin_define_type_minmax ("__WCHAR_MIN__", "__WCHAR_MAX__", - underlying_wchar_type_node); - builtin_define_type_minmax ("__WINT_MIN__", "__WINT_MAX__", wint_type_node); - builtin_define_type_max ("__PTRDIFF_MAX__", ptrdiff_type_node); - builtin_define_type_max ("__SIZE_MAX__", size_type_node); - - builtin_define_type_precision ("__CHAR_BIT__", char_type_node); - - /* stdint.h and the testsuite need to know these. */ - builtin_define_stdint_macros (); - - /* float.h needs to know these. */ - - builtin_define_with_int_value ("__FLT_EVAL_METHOD__", - TARGET_FLT_EVAL_METHOD); - - /* And decfloat.h needs this. */ - builtin_define_with_int_value ("__DEC_EVAL_METHOD__", - TARGET_DEC_EVAL_METHOD); - - builtin_define_float_constants ("FLT", "F", "%s", float_type_node); - /* Cast the double precision constants. This is needed when single - precision constants are specified or when pragma FLOAT_CONST_DECIMAL64 - is used. The correct result is computed by the compiler when using - macros that include a cast. */ - builtin_define_float_constants ("DBL", "L", "((double)%s)", double_type_node); - builtin_define_float_constants ("LDBL", "L", "%s", long_double_type_node); - - /* For decfloat.h. */ - builtin_define_decimal_float_constants ("DEC32", "DF", dfloat32_type_node); - builtin_define_decimal_float_constants ("DEC64", "DD", dfloat64_type_node); - builtin_define_decimal_float_constants ("DEC128", "DL", dfloat128_type_node); - - /* For fixed-point fibt, ibit, max, min, and epsilon. */ - if (targetm.fixed_point_supported_p ()) - { - builtin_define_fixed_point_constants ("SFRACT", "HR", - short_fract_type_node); - builtin_define_fixed_point_constants ("USFRACT", "UHR", - unsigned_short_fract_type_node); - builtin_define_fixed_point_constants ("FRACT", "R", - fract_type_node); - builtin_define_fixed_point_constants ("UFRACT", "UR", - unsigned_fract_type_node); - builtin_define_fixed_point_constants ("LFRACT", "LR", - long_fract_type_node); - builtin_define_fixed_point_constants ("ULFRACT", "ULR", - unsigned_long_fract_type_node); - builtin_define_fixed_point_constants ("LLFRACT", "LLR", - long_long_fract_type_node); - builtin_define_fixed_point_constants ("ULLFRACT", "ULLR", - unsigned_long_long_fract_type_node); - builtin_define_fixed_point_constants ("SACCUM", "HK", - short_accum_type_node); - builtin_define_fixed_point_constants ("USACCUM", "UHK", - unsigned_short_accum_type_node); - builtin_define_fixed_point_constants ("ACCUM", "K", - accum_type_node); - builtin_define_fixed_point_constants ("UACCUM", "UK", - unsigned_accum_type_node); - builtin_define_fixed_point_constants ("LACCUM", "LK", - long_accum_type_node); - builtin_define_fixed_point_constants ("ULACCUM", "ULK", - unsigned_long_accum_type_node); - builtin_define_fixed_point_constants ("LLACCUM", "LLK", - long_long_accum_type_node); - builtin_define_fixed_point_constants ("ULLACCUM", "ULLK", - unsigned_long_long_accum_type_node); - - builtin_define_fixed_point_constants ("QQ", "", qq_type_node); - builtin_define_fixed_point_constants ("HQ", "", hq_type_node); - builtin_define_fixed_point_constants ("SQ", "", sq_type_node); - builtin_define_fixed_point_constants ("DQ", "", dq_type_node); - builtin_define_fixed_point_constants ("TQ", "", tq_type_node); - builtin_define_fixed_point_constants ("UQQ", "", uqq_type_node); - builtin_define_fixed_point_constants ("UHQ", "", uhq_type_node); - builtin_define_fixed_point_constants ("USQ", "", usq_type_node); - builtin_define_fixed_point_constants ("UDQ", "", udq_type_node); - builtin_define_fixed_point_constants ("UTQ", "", utq_type_node); - builtin_define_fixed_point_constants ("HA", "", ha_type_node); - builtin_define_fixed_point_constants ("SA", "", sa_type_node); - builtin_define_fixed_point_constants ("DA", "", da_type_node); - builtin_define_fixed_point_constants ("TA", "", ta_type_node); - builtin_define_fixed_point_constants ("UHA", "", uha_type_node); - builtin_define_fixed_point_constants ("USA", "", usa_type_node); - builtin_define_fixed_point_constants ("UDA", "", uda_type_node); - builtin_define_fixed_point_constants ("UTA", "", uta_type_node); - } - - /* For use in assembly language. */ - builtin_define_with_value ("__REGISTER_PREFIX__", REGISTER_PREFIX, 0); - builtin_define_with_value ("__USER_LABEL_PREFIX__", user_label_prefix, 0); - - /* Misc. */ - builtin_define_with_value ("__VERSION__", version_string, 1); - - if (flag_gnu89_inline) - cpp_define (pfile, "__GNUC_GNU_INLINE__"); - else - cpp_define (pfile, "__GNUC_STDC_INLINE__"); - - /* Definitions for LP64 model. */ - if (TYPE_PRECISION (long_integer_type_node) == 64 - && POINTER_SIZE == 64 - && TYPE_PRECISION (integer_type_node) == 32) - { - cpp_define (pfile, "_LP64"); - cpp_define (pfile, "__LP64__"); - } - - /* Other target-independent built-ins determined by command-line - options. */ - if (optimize_size) - cpp_define (pfile, "__OPTIMIZE_SIZE__"); - if (optimize) - cpp_define (pfile, "__OPTIMIZE__"); - - if (fast_math_flags_set_p ()) - cpp_define (pfile, "__FAST_MATH__"); - if (flag_no_inline) - cpp_define (pfile, "__NO_INLINE__"); - if (flag_signaling_nans) - cpp_define (pfile, "__SUPPORT_SNAN__"); - if (flag_finite_math_only) - cpp_define (pfile, "__FINITE_MATH_ONLY__=1"); - else - cpp_define (pfile, "__FINITE_MATH_ONLY__=0"); - if (flag_pic) - { - builtin_define_with_int_value ("__pic__", flag_pic); - builtin_define_with_int_value ("__PIC__", flag_pic); - } - if (flag_pie) - { - builtin_define_with_int_value ("__pie__", flag_pie); - builtin_define_with_int_value ("__PIE__", flag_pie); - } - - if (flag_iso) - cpp_define (pfile, "__STRICT_ANSI__"); - - if (!flag_signed_char) - cpp_define (pfile, "__CHAR_UNSIGNED__"); - - if (c_dialect_cxx () && TYPE_UNSIGNED (wchar_type_node)) - cpp_define (pfile, "__WCHAR_UNSIGNED__"); - - /* Tell source code if the compiler makes sync_compare_and_swap - builtins available. */ -#ifdef HAVE_sync_compare_and_swapqi - if (HAVE_sync_compare_and_swapqi) - cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); -#endif - -#ifdef HAVE_sync_compare_and_swaphi - if (HAVE_sync_compare_and_swaphi) - cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); -#endif - -#ifdef HAVE_sync_compare_and_swapsi - if (HAVE_sync_compare_and_swapsi) - cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); -#endif - -#ifdef HAVE_sync_compare_and_swapdi - if (HAVE_sync_compare_and_swapdi) - cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); -#endif - -#ifdef HAVE_sync_compare_and_swapti - if (HAVE_sync_compare_and_swapti) - cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); -#endif - -#ifdef DWARF2_UNWIND_INFO - if (dwarf2out_do_cfi_asm ()) - cpp_define (pfile, "__GCC_HAVE_DWARF2_CFI_ASM"); -#endif - - /* Make the choice of ObjC runtime visible to source code. */ - if (c_dialect_objc () && flag_next_runtime) - cpp_define (pfile, "__NEXT_RUNTIME__"); - - /* Show the availability of some target pragmas. */ - cpp_define (pfile, "__PRAGMA_REDEFINE_EXTNAME"); - - if (targetm.handle_pragma_extern_prefix) - cpp_define (pfile, "__PRAGMA_EXTERN_PREFIX"); - - /* Make the choice of the stack protector runtime visible to source code. - The macro names and values here were chosen for compatibility with an - earlier implementation, i.e. ProPolice. */ - if (flag_stack_protect == 2) - cpp_define (pfile, "__SSP_ALL__=2"); - else if (flag_stack_protect == 1) - cpp_define (pfile, "__SSP__=1"); - - if (flag_openmp) - cpp_define (pfile, "_OPENMP=200805"); - - builtin_define_type_sizeof ("__SIZEOF_INT__", integer_type_node); - builtin_define_type_sizeof ("__SIZEOF_LONG__", long_integer_type_node); - builtin_define_type_sizeof ("__SIZEOF_LONG_LONG__", - long_long_integer_type_node); - if (int128_integer_type_node != NULL_TREE) - builtin_define_type_sizeof ("__SIZEOF_INT128__", - int128_integer_type_node); - builtin_define_type_sizeof ("__SIZEOF_SHORT__", short_integer_type_node); - builtin_define_type_sizeof ("__SIZEOF_FLOAT__", float_type_node); - builtin_define_type_sizeof ("__SIZEOF_DOUBLE__", double_type_node); - builtin_define_type_sizeof ("__SIZEOF_LONG_DOUBLE__", long_double_type_node); - builtin_define_type_sizeof ("__SIZEOF_SIZE_T__", size_type_node); - builtin_define_type_sizeof ("__SIZEOF_WCHAR_T__", wchar_type_node); - builtin_define_type_sizeof ("__SIZEOF_WINT_T__", wint_type_node); - builtin_define_type_sizeof ("__SIZEOF_PTRDIFF_T__", - unsigned_ptrdiff_type_node); - /* ptr_type_node can't be used here since ptr_mode is only set when - toplev calls backend_init which is not done with -E switch. */ - builtin_define_with_int_value ("__SIZEOF_POINTER__", - POINTER_SIZE / BITS_PER_UNIT); - - /* A straightforward target hook doesn't work, because of problems - linking that hook's body when part of non-C front ends. */ -# define preprocessing_asm_p() (cpp_get_options (pfile)->lang == CLK_ASM) -# define preprocessing_trad_p() (cpp_get_options (pfile)->traditional) -# define builtin_define(TXT) cpp_define (pfile, TXT) -# define builtin_assert(TXT) cpp_assert (pfile, TXT) - TARGET_CPU_CPP_BUILTINS (); - TARGET_OS_CPP_BUILTINS (); - TARGET_OBJFMT_CPP_BUILTINS (); - - /* Support the __declspec keyword by turning them into attributes. - Note that the current way we do this may result in a collision - with predefined attributes later on. This can be solved by using - one attribute, say __declspec__, and passing args to it. The - problem with that approach is that args are not accumulated: each - new appearance would clobber any existing args. */ - if (TARGET_DECLSPEC) - builtin_define ("__declspec(x)=__attribute__((x))"); - - /* If decimal floating point is supported, tell the user if the - alternate format (BID) is used instead of the standard (DPD) - format. */ - if (ENABLE_DECIMAL_FLOAT && ENABLE_DECIMAL_BID_FORMAT) - cpp_define (pfile, "__DECIMAL_BID_FORMAT__"); - - builtin_define_with_int_value ("__BIGGEST_ALIGNMENT__", - BIGGEST_ALIGNMENT / BITS_PER_UNIT); -} - -/* Pass an object-like macro. If it doesn't lie in the user's - namespace, defines it unconditionally. Otherwise define a version - with two leading underscores, and another version with two leading - and trailing underscores, and define the original only if an ISO - standard was not nominated. - - e.g. passing "unix" defines "__unix", "__unix__" and possibly - "unix". Passing "_mips" defines "__mips", "__mips__" and possibly - "_mips". */ -void -builtin_define_std (const char *macro) -{ - size_t len = strlen (macro); - char *buff = (char *) alloca (len + 5); - char *p = buff + 2; - char *q = p + len; - - /* prepend __ (or maybe just _) if in user's namespace. */ - memcpy (p, macro, len + 1); - if (!( *p == '_' && (p[1] == '_' || ISUPPER (p[1])))) - { - if (*p != '_') - *--p = '_'; - if (p[1] != '_') - *--p = '_'; - } - cpp_define (parse_in, p); - - /* If it was in user's namespace... */ - if (p != buff + 2) - { - /* Define the macro with leading and following __. */ - if (q[-1] != '_') - *q++ = '_'; - if (q[-2] != '_') - *q++ = '_'; - *q = '\0'; - cpp_define (parse_in, p); - - /* Finally, define the original macro if permitted. */ - if (!flag_iso) - cpp_define (parse_in, macro); - } -} - -/* Pass an object-like macro and a value to define it to. The third - parameter says whether or not to turn the value into a string - constant. */ -void -builtin_define_with_value (const char *macro, const char *expansion, int is_str) -{ - char *buf; - size_t mlen = strlen (macro); - size_t elen = strlen (expansion); - size_t extra = 2; /* space for an = and a NUL */ - - if (is_str) - extra += 2; /* space for two quote marks */ - - buf = (char *) alloca (mlen + elen + extra); - if (is_str) - sprintf (buf, "%s=\"%s\"", macro, expansion); - else - sprintf (buf, "%s=%s", macro, expansion); - - cpp_define (parse_in, buf); -} - - -/* Pass an object-like macro and an integer value to define it to. */ -static void -builtin_define_with_int_value (const char *macro, HOST_WIDE_INT value) -{ - char *buf; - size_t mlen = strlen (macro); - size_t vlen = 18; - size_t extra = 2; /* space for = and NUL. */ - - buf = (char *) alloca (mlen + vlen + extra); - memcpy (buf, macro, mlen); - buf[mlen] = '='; - sprintf (buf + mlen + 1, HOST_WIDE_INT_PRINT_DEC, value); - - cpp_define (parse_in, buf); -} - -/* Pass an object-like macro a hexadecimal floating-point value. */ -static void -builtin_define_with_hex_fp_value (const char *macro, - tree type, int digits, - const char *hex_str, - const char *fp_suffix, - const char *fp_cast) -{ - REAL_VALUE_TYPE real; - char dec_str[64], buf1[256], buf2[256]; - - /* Hex values are really cool and convenient, except that they're - not supported in strict ISO C90 mode. First, the "p-" sequence - is not valid as part of a preprocessor number. Second, we get a - pedwarn from the preprocessor, which has no context, so we can't - suppress the warning with __extension__. - - So instead what we do is construct the number in hex (because - it's easy to get the exact correct value), parse it as a real, - then print it back out as decimal. */ - - real_from_string (&real, hex_str); - real_to_decimal_for_mode (dec_str, &real, sizeof (dec_str), digits, 0, - TYPE_MODE (type)); - - /* Assemble the macro in the following fashion - macro = fp_cast [dec_str fp_suffix] */ - sprintf (buf1, "%s%s", dec_str, fp_suffix); - sprintf (buf2, fp_cast, buf1); - sprintf (buf1, "%s=%s", macro, buf2); - - cpp_define (parse_in, buf1); -} - -/* Return a string constant for the suffix for a value of type TYPE - promoted according to the integer promotions. The type must be one - of the standard integer type nodes. */ - -static const char * -type_suffix (tree type) -{ - static const char *const suffixes[] = { "", "U", "L", "UL", "LL", "ULL" }; - int unsigned_suffix; - int is_long; - - if (type == long_long_integer_type_node - || type == long_long_unsigned_type_node) - is_long = 2; - else if (type == long_integer_type_node - || type == long_unsigned_type_node) - is_long = 1; - else if (type == integer_type_node - || type == unsigned_type_node - || type == short_integer_type_node - || type == short_unsigned_type_node - || type == signed_char_type_node - || type == unsigned_char_type_node - /* ??? "char" is not a signed or unsigned integer type and - so is not permitted for the standard typedefs, but some - systems use it anyway. */ - || type == char_type_node) - is_long = 0; - else - gcc_unreachable (); - - unsigned_suffix = TYPE_UNSIGNED (type); - if (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) - unsigned_suffix = 0; - return suffixes[is_long * 2 + unsigned_suffix]; -} - -/* Define MACRO as a constant-suffix macro for TYPE. */ -static void -builtin_define_constants (const char *macro, tree type) -{ - const char *suffix; - char *buf; - - suffix = type_suffix (type); - - if (suffix[0] == 0) - { - buf = (char *) alloca (strlen (macro) + 6); - sprintf (buf, "%s(c)=c", macro); - } - else - { - buf = (char *) alloca (strlen (macro) + 9 + strlen (suffix) + 1); - sprintf (buf, "%s(c)=c ## %s", macro, suffix); - } - - cpp_define (parse_in, buf); -} - -/* Define MAX for TYPE based on the precision of the type. */ - -static void -builtin_define_type_max (const char *macro, tree type) -{ - builtin_define_type_minmax (NULL, macro, type); -} - -/* Define MIN_MACRO (if not NULL) and MAX_MACRO for TYPE based on the - precision of the type. */ - -static void -builtin_define_type_minmax (const char *min_macro, const char *max_macro, - tree type) -{ - static const char *const values[] - = { "127", "255", - "32767", "65535", - "2147483647", "4294967295", - "9223372036854775807", "18446744073709551615", - "170141183460469231731687303715884105727", - "340282366920938463463374607431768211455" }; - - const char *value, *suffix; - char *buf; - size_t idx; - - /* Pre-rendering the values mean we don't have to futz with printing a - multi-word decimal value. There are also a very limited number of - precisions that we support, so it's really a waste of time. */ - switch (TYPE_PRECISION (type)) - { - case 8: idx = 0; break; - case 16: idx = 2; break; - case 32: idx = 4; break; - case 64: idx = 6; break; - case 128: idx = 8; break; - default: gcc_unreachable (); - } - - value = values[idx + TYPE_UNSIGNED (type)]; - suffix = type_suffix (type); - - buf = (char *) alloca (strlen (max_macro) + 1 + strlen (value) - + strlen (suffix) + 1); - sprintf (buf, "%s=%s%s", max_macro, value, suffix); - - cpp_define (parse_in, buf); - - if (min_macro) - { - if (TYPE_UNSIGNED (type)) - { - buf = (char *) alloca (strlen (min_macro) + 2 + strlen (suffix) + 1); - sprintf (buf, "%s=0%s", min_macro, suffix); - } - else - { - buf = (char *) alloca (strlen (min_macro) + 3 - + strlen (max_macro) + 6); - sprintf (buf, "%s=(-%s - 1)", min_macro, max_macro); - } - cpp_define (parse_in, buf); - } -} diff --git a/gcc/c-decl.c b/gcc/c-decl.c index cda6ce3..2485bf4 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -45,8 +45,8 @@ along with GCC; see the file COPYING3. If not see #include "debug.h" #include "opts.h" #include "timevar.h" -#include "c-common.h" -#include "c-pragma.h" +#include "c-family/c-common.h" +#include "c-family/c-pragma.h" #include "c-lang.h" #include "langhooks.h" #include "tree-mudflap.h" @@ -58,7 +58,7 @@ along with GCC; see the file COPYING3. If not see #include "langhooks-def.h" #include "pointer-set.h" #include "plugin.h" -#include "c-ada-spec.h" +#include "c-family/c-ada-spec.h" /* In grokdeclarator, distinguish syntactic contexts of declarators. */ enum decl_context diff --git a/gcc/c-dump.c b/gcc/c-dump.c deleted file mode 100644 index 71e872e..0000000 --- a/gcc/c-dump.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Tree-dumping functionality for C-family languages. - Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc. - Written by Mark Mitchell - -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 "tree.h" -#include "tree-dump.h" -#include "c-common.h" - -/* Dump information common to statements from STMT. */ - -void -dump_stmt (dump_info_p di, const_tree t) -{ - if (EXPR_HAS_LOCATION (t)) - dump_int (di, "line", EXPR_LINENO (t)); -} - -/* Dump any C-specific tree codes and attributes of common codes. */ - -bool -c_dump_tree (void *dump_info, tree t) -{ - enum tree_code code; - dump_info_p di = (dump_info_p) dump_info; - - /* Figure out what kind of node this is. */ - code = TREE_CODE (t); - - switch (code) - { - case FIELD_DECL: - if (DECL_C_BIT_FIELD (t)) - dump_string (di, "bitfield"); - break; - - default: - break; - } - - return false; -} diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog new file mode 100644 index 0000000..f250139 --- /dev/null +++ b/gcc/c-family/ChangeLog @@ -0,0 +1,31 @@ +2010-06-05 Steven Bosscher + + * c-common.c: Moved to here from parent directory. + * c-common.def: Likewise. + * c-common.h: Likewise. + * c-cppbuiltin.c: Likewise. + * c-dump.c: Likewise. + * c-format.c: Likewise. + * c-format.h : Likewise. + * c-gimplify.c: Likewise. + * c-lex.c: Likewise. + * c-omp.c: Likewise. + * c.opt: Likewise. + * c-opts.c: Likewise. + * c-pch.c: Likewise. + * c-ppoutput.c: Likewise. + * c-pragma.c: Likewise. + * c-pragma.h: Likewise. + * c-pretty-print.c: Likewise. + * c-pretty-print.h: Likewise. + * c-semantics.c: Likewise. + * stub-objc.c: Likewise. + + * c-common.c: Include gt-c-family-c-common.h. + * c-pragma.c: Include gt-c-family-c-pragma.h. + +Copyright (C) 2010 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c new file mode 100644 index 0000000..697b963 --- /dev/null +++ b/gcc/c-family/c-ada-spec.c @@ -0,0 +1,3230 @@ +/* Print GENERIC declaration (functions, variables, types) trees coming from + the C and C++ front-ends as well as macros in Ada syntax. + Copyright (C) 2010 Free Software Foundation, Inc. + Adapted from tree-pretty-print.c by Arnaud Charlet + +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 "tree.h" +#include "tree-pass.h" /* For TDI_ada and friends. */ +#include "output.h" +#include "c-ada-spec.h" +#include "cpplib.h" +#include "c-pragma.h" +#include "cpp-id-data.h" + +/* Local functions, macros and variables. */ +static int dump_generic_ada_node (pretty_printer *, tree, tree, + int (*)(tree, cpp_operation), int, int, bool); +static int print_ada_declaration (pretty_printer *, tree, tree, + int (*cpp_check)(tree, cpp_operation), int); +static void print_ada_struct_decl (pretty_printer *, tree, tree, + int (*cpp_check)(tree, cpp_operation), int, + bool); +static void dump_sloc (pretty_printer *buffer, tree node); +static void print_comment (pretty_printer *, const char *); +static void print_generic_ada_decl (pretty_printer *, tree, + int (*)(tree, cpp_operation), const char *); +static char *get_ada_package (const char *); +static void dump_ada_nodes (pretty_printer *, const char *, + int (*)(tree, cpp_operation)); +static void reset_ada_withs (void); +static void dump_ada_withs (FILE *); +static void dump_ads (const char *, void (*)(const char *), + int (*)(tree, cpp_operation)); +static char *to_ada_name (const char *, int *); + +#define LOCATION_COL(LOC) ((expand_location (LOC)).column) + +#define INDENT(SPACE) do { \ + int i; for (i = 0; ifun_like) + { + param_len++; + for (i = 0; i < macro->paramc; i++) + { + cpp_hashnode *param = macro->params[i]; + + *param_len += NODE_LEN (param); + + if (i + 1 < macro->paramc) + { + *param_len += 2; /* ", " */ + } + else if (macro->variadic) + { + *supported = 0; + return; + } + } + *param_len += 2; /* ")\0" */ + } + + for (j = 0; j < macro->count; j++) + { + cpp_token *token = ¯o->exp.tokens[j]; + + if (token->flags & PREV_WHITE) + (*buffer_len)++; + + if (token->flags & STRINGIFY_ARG || token->flags & PASTE_LEFT) + { + *supported = 0; + return; + } + + if (token->type == CPP_MACRO_ARG) + *buffer_len += + NODE_LEN (macro->params[token->val.macro_arg.arg_no - 1]); + else + /* Include enough extra space to handle e.g. special characters. */ + *buffer_len += (cpp_token_len (token) + 1) * 8; + } + + (*buffer_len)++; +} + +/* Dump into PP a set of MAX_ADA_MACROS MACROS (C/C++) as Ada constants when + possible. */ + +static void +print_ada_macros (pretty_printer *pp, cpp_hashnode **macros, int max_ada_macros) +{ + int j, num_macros = 0, prev_line = -1; + + for (j = 0; j < max_ada_macros; j++) + { + cpp_hashnode *node = macros [j]; + const cpp_macro *macro = node->value.macro; + unsigned i; + int supported = 1, prev_is_one = 0, buffer_len, param_len; + int is_string = 0, is_char = 0; + char *ada_name; + unsigned char *s, *params, *buffer, *buf_param, *char_one = NULL; + + macro_length (macro, &supported, &buffer_len, ¶m_len); + s = buffer = XALLOCAVEC (unsigned char, buffer_len); + params = buf_param = XALLOCAVEC (unsigned char, param_len); + + if (supported) + { + if (macro->fun_like) + { + *buf_param++ = '('; + for (i = 0; i < macro->paramc; i++) + { + cpp_hashnode *param = macro->params[i]; + + memcpy (buf_param, NODE_NAME (param), NODE_LEN (param)); + buf_param += NODE_LEN (param); + + if (i + 1 < macro->paramc) + { + *buf_param++ = ','; + *buf_param++ = ' '; + } + else if (macro->variadic) + { + supported = 0; + break; + } + } + *buf_param++ = ')'; + *buf_param = '\0'; + } + + for (i = 0; supported && i < macro->count; i++) + { + cpp_token *token = ¯o->exp.tokens[i]; + int is_one = 0; + + if (token->flags & PREV_WHITE) + *buffer++ = ' '; + + if (token->flags & STRINGIFY_ARG || token->flags & PASTE_LEFT) + { + supported = 0; + break; + } + + switch (token->type) + { + case CPP_MACRO_ARG: + { + cpp_hashnode *param = + macro->params[token->val.macro_arg.arg_no - 1]; + memcpy (buffer, NODE_NAME (param), NODE_LEN (param)); + buffer += NODE_LEN (param); + } + break; + + case CPP_EQ_EQ: *buffer++ = '='; break; + case CPP_GREATER: *buffer++ = '>'; break; + case CPP_LESS: *buffer++ = '<'; break; + case CPP_PLUS: *buffer++ = '+'; break; + case CPP_MINUS: *buffer++ = '-'; break; + case CPP_MULT: *buffer++ = '*'; break; + case CPP_DIV: *buffer++ = '/'; break; + case CPP_COMMA: *buffer++ = ','; break; + case CPP_OPEN_SQUARE: + case CPP_OPEN_PAREN: *buffer++ = '('; break; + case CPP_CLOSE_SQUARE: /* fallthrough */ + case CPP_CLOSE_PAREN: *buffer++ = ')'; break; + case CPP_DEREF: /* fallthrough */ + case CPP_SCOPE: /* fallthrough */ + case CPP_DOT: *buffer++ = '.'; break; + + case CPP_EQ: *buffer++ = ':'; *buffer++ = '='; break; + case CPP_NOT_EQ: *buffer++ = '/'; *buffer++ = '='; break; + case CPP_GREATER_EQ: *buffer++ = '>'; *buffer++ = '='; break; + case CPP_LESS_EQ: *buffer++ = '<'; *buffer++ = '='; break; + + case CPP_NOT: + *buffer++ = 'n'; *buffer++ = 'o'; *buffer++ = 't'; break; + case CPP_MOD: + *buffer++ = 'm'; *buffer++ = 'o'; *buffer++ = 'd'; break; + case CPP_AND: + *buffer++ = 'a'; *buffer++ = 'n'; *buffer++ = 'd'; break; + case CPP_OR: + *buffer++ = 'o'; *buffer++ = 'r'; break; + case CPP_XOR: + *buffer++ = 'x'; *buffer++ = 'o'; *buffer++ = 'r'; break; + case CPP_AND_AND: + strcpy ((char *) buffer, " and then "); + buffer += 10; + break; + case CPP_OR_OR: + strcpy ((char *) buffer, " or else "); + buffer += 9; + break; + + case CPP_PADDING: + *buffer++ = ' '; + is_one = prev_is_one; + break; + + case CPP_COMMENT: break; + + case CPP_WSTRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_UTF8STRING: + case CPP_WCHAR: + case CPP_CHAR16: + case CPP_CHAR32: + case CPP_NAME: + case CPP_STRING: + case CPP_NUMBER: + if (!macro->fun_like) + supported = 0; + else + buffer = cpp_spell_token (parse_in, token, buffer, false); + break; + + case CPP_CHAR: + is_char = 1; + { + unsigned chars_seen; + int ignored; + cppchar_t c; + + c = cpp_interpret_charconst (parse_in, token, + &chars_seen, &ignored); + if (c >= 32 && c <= 126) + { + *buffer++ = '\''; + *buffer++ = (char) c; + *buffer++ = '\''; + } + else + { + chars_seen = sprintf + ((char *) buffer, "Character'Val (%d)", (int) c); + buffer += chars_seen; + } + } + break; + + case CPP_LSHIFT: + if (prev_is_one) + { + /* Replace "1 << N" by "2 ** N" */ + *char_one = '2'; + *buffer++ = '*'; + *buffer++ = '*'; + break; + } + /* fallthrough */ + + case CPP_RSHIFT: + case CPP_COMPL: + case CPP_QUERY: + case CPP_EOF: + case CPP_PLUS_EQ: + case CPP_MINUS_EQ: + case CPP_MULT_EQ: + case CPP_DIV_EQ: + case CPP_MOD_EQ: + case CPP_AND_EQ: + case CPP_OR_EQ: + case CPP_XOR_EQ: + case CPP_RSHIFT_EQ: + case CPP_LSHIFT_EQ: + case CPP_PRAGMA: + case CPP_PRAGMA_EOL: + case CPP_HASH: + case CPP_PASTE: + case CPP_OPEN_BRACE: + case CPP_CLOSE_BRACE: + case CPP_SEMICOLON: + case CPP_ELLIPSIS: + case CPP_PLUS_PLUS: + case CPP_MINUS_MINUS: + case CPP_DEREF_STAR: + case CPP_DOT_STAR: + case CPP_ATSIGN: + case CPP_HEADER_NAME: + case CPP_AT_NAME: + case CPP_OTHER: + case CPP_OBJC_STRING: + default: + if (!macro->fun_like) + supported = 0; + else + buffer = cpp_spell_token (parse_in, token, buffer, false); + break; + } + + prev_is_one = is_one; + } + + if (supported) + *buffer = '\0'; + } + + if (macro->fun_like && supported) + { + char *start = (char *) s; + int is_function = 0; + + pp_string (pp, " -- arg-macro: "); + + if (*start == '(' && buffer [-1] == ')') + { + start++; + buffer [-1] = '\0'; + is_function = 1; + pp_string (pp, "function "); + } + else + { + pp_string (pp, "procedure "); + } + + pp_string (pp, (const char *) NODE_NAME (node)); + pp_space (pp); + pp_string (pp, (char *) params); + pp_newline (pp); + pp_string (pp, " -- "); + + if (is_function) + { + pp_string (pp, "return "); + pp_string (pp, start); + pp_semicolon (pp); + } + else + pp_string (pp, start); + + pp_newline (pp); + } + else if (supported) + { + expanded_location sloc = expand_location (macro->line); + + if (sloc.line != prev_line + 1) + pp_newline (pp); + + num_macros++; + prev_line = sloc.line; + + pp_string (pp, " "); + ada_name = to_ada_name ((const char *) NODE_NAME (node), NULL); + pp_string (pp, ada_name); + free (ada_name); + pp_string (pp, " : "); + + if (is_string) + pp_string (pp, "aliased constant String"); + else if (is_char) + pp_string (pp, "aliased constant Character"); + else + pp_string (pp, "constant"); + + pp_string (pp, " := "); + pp_string (pp, (char *) s); + + if (is_string) + pp_string (pp, " & ASCII.NUL"); + + pp_string (pp, "; -- "); + pp_string (pp, sloc.file); + pp_character (pp, ':'); + pp_scalar (pp, "%d", sloc.line); + pp_newline (pp); + } + else + { + pp_string (pp, " -- unsupported macro: "); + pp_string (pp, (const char *) cpp_macro_definition (parse_in, node)); + pp_newline (pp); + } + } + + if (num_macros > 0) + pp_newline (pp); +} + +static const char *source_file; +static int max_ada_macros; + +/* Callback used to count the number of relevant macros from + cpp_forall_identifiers. PFILE and V are not used. NODE is the current macro + to consider. */ + +static int +count_ada_macro (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *node, + void *v ATTRIBUTE_UNUSED) +{ + const cpp_macro *macro = node->value.macro; + + if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN) + && macro->count + && *NODE_NAME (node) != '_' + && LOCATION_FILE (macro->line) == source_file) + max_ada_macros++; + + return 1; +} + +static int store_ada_macro_index; + +/* Callback used to store relevant macros from cpp_forall_identifiers. + PFILE is not used. NODE is the current macro to store if relevant. + MACROS is an array of cpp_hashnode* used to store NODE. */ + +static int +store_ada_macro (cpp_reader *pfile ATTRIBUTE_UNUSED, + cpp_hashnode *node, void *macros) +{ + const cpp_macro *macro = node->value.macro; + + if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN) + && macro->count + && *NODE_NAME (node) != '_' + && LOCATION_FILE (macro->line) == source_file) + ((cpp_hashnode **) macros)[store_ada_macro_index++] = node; + + return 1; +} + +/* Callback used to compare (during qsort) macros. NODE1 and NODE2 are the + two macro nodes to compare. */ + +static int +compare_macro (const void *node1, const void *node2) +{ + typedef const cpp_hashnode *const_hnode; + + const_hnode n1 = *(const const_hnode *) node1; + const_hnode n2 = *(const const_hnode *) node2; + + return n1->value.macro->line - n2->value.macro->line; +} + +/* Dump in PP all relevant macros appearing in FILE. */ + +static void +dump_ada_macros (pretty_printer *pp, const char* file) +{ + cpp_hashnode **macros; + + /* Initialize file-scope variables. */ + max_ada_macros = 0; + store_ada_macro_index = 0; + source_file = file; + + /* Count all potentially relevant macros, and then sort them by sloc. */ + cpp_forall_identifiers (parse_in, count_ada_macro, NULL); + macros = XALLOCAVEC (cpp_hashnode *, max_ada_macros); + cpp_forall_identifiers (parse_in, store_ada_macro, macros); + qsort (macros, max_ada_macros, sizeof (cpp_hashnode *), compare_macro); + + print_ada_macros (pp, macros, max_ada_macros); +} + +/* Current source file being handled. */ + +static const char *source_file_base; + +/* Compare the declaration (DECL) of struct-like types based on the sloc of + their last field (if LAST is true), so that more nested types collate before + less nested ones. + If ORIG_TYPE is true, also consider struct with a DECL_ORIGINAL_TYPE. */ + +static location_t +decl_sloc_common (const_tree decl, bool last, bool orig_type) +{ + tree type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == TYPE_DECL + && (orig_type || !DECL_ORIGINAL_TYPE (decl)) + && RECORD_OR_UNION_TYPE_P (type) + && TYPE_FIELDS (type)) + { + tree f = TYPE_FIELDS (type); + + if (last) + while (TREE_CHAIN (f)) + f = TREE_CHAIN (f); + + return DECL_SOURCE_LOCATION (f); + } + else + return DECL_SOURCE_LOCATION (decl); +} + +/* Return sloc of DECL, using sloc of last field if LAST is true. */ + +location_t +decl_sloc (const_tree decl, bool last) +{ + return decl_sloc_common (decl, last, false); +} + +/* Compare two declarations (LP and RP) by their source location. */ + +static int +compare_node (const void *lp, const void *rp) +{ + const_tree lhs = *((const tree *) lp); + const_tree rhs = *((const tree *) rp); + + return decl_sloc (lhs, true) - decl_sloc (rhs, true); +} + +/* Compare two comments (LP and RP) by their source location. */ + +static int +compare_comment (const void *lp, const void *rp) +{ + const cpp_comment *lhs = (const cpp_comment *) lp; + const cpp_comment *rhs = (const cpp_comment *) rp; + + if (LOCATION_FILE (lhs->sloc) != LOCATION_FILE (rhs->sloc)) + return strcmp (LOCATION_FILE (lhs->sloc), LOCATION_FILE (rhs->sloc)); + + if (LOCATION_LINE (lhs->sloc) != LOCATION_LINE (rhs->sloc)) + return LOCATION_LINE (lhs->sloc) - LOCATION_LINE (rhs->sloc); + + if (LOCATION_COL (lhs->sloc) != LOCATION_COL (rhs->sloc)) + return LOCATION_COL (lhs->sloc) - LOCATION_COL (rhs->sloc); + + return 0; +} + +static tree *to_dump = NULL; +static int to_dump_count = 0; + +/* Collect a list of declarations from T relevant to SOURCE_FILE to be dumped + by a subsequent call to dump_ada_nodes. */ + +void +collect_ada_nodes (tree t, const char *source_file) +{ + tree n; + int i = to_dump_count; + + /* Count the likely relevant nodes. */ + for (n = t; n; n = TREE_CHAIN (n)) + if (!DECL_IS_BUILTIN (n) + && LOCATION_FILE (decl_sloc (n, false)) == source_file) + to_dump_count++; + + /* Allocate sufficient storage for all nodes. */ + to_dump = XRESIZEVEC (tree, to_dump, to_dump_count); + + /* Store the relevant nodes. */ + for (n = t; n; n = TREE_CHAIN (n)) + if (!DECL_IS_BUILTIN (n) + && LOCATION_FILE (decl_sloc (n, false)) == source_file) + to_dump [i++] = n; +} + +/* Call back for walk_tree to clear the TREE_VISITED flag of TP. */ + +static tree +unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + if (TREE_VISITED (*tp)) + TREE_VISITED (*tp) = 0; + else + *walk_subtrees = 0; + + return NULL_TREE; +} + +/* Dump nodes into PP relevant to SOURCE_FILE, as collected by previous calls + to collect_ada_nodes. CPP_CHECK is used to perform C++ queries on nodes. */ + +static void +dump_ada_nodes (pretty_printer *pp, const char *source_file, + int (*cpp_check)(tree, cpp_operation)) +{ + int i, j; + cpp_comment_table *comments; + + /* Sort the table of declarations to dump by sloc. */ + qsort (to_dump, to_dump_count, sizeof (tree), compare_node); + + /* Fetch the table of comments. */ + comments = cpp_get_comments (parse_in); + + /* Sort the comments table by sloc. */ + qsort (comments->entries, comments->count, sizeof (cpp_comment), + compare_comment); + + /* Interleave comments and declarations in line number order. */ + i = j = 0; + do + { + /* Advance j until comment j is in this file. */ + while (j != comments->count + && LOCATION_FILE (comments->entries[j].sloc) != source_file) + j++; + + /* Advance j until comment j is not a duplicate. */ + while (j < comments->count - 1 + && !compare_comment (&comments->entries[j], + &comments->entries[j + 1])) + j++; + + /* Write decls until decl i collates after comment j. */ + while (i != to_dump_count) + { + if (j == comments->count + || LOCATION_LINE (decl_sloc (to_dump[i], false)) + < LOCATION_LINE (comments->entries[j].sloc)) + print_generic_ada_decl (pp, to_dump[i++], cpp_check, source_file); + else + break; + } + + /* Write comment j, if there is one. */ + if (j != comments->count) + print_comment (pp, comments->entries[j++].comment); + + } while (i != to_dump_count || j != comments->count); + + /* Clear the TREE_VISITED flag over each subtree we've dumped. */ + for (i = 0; i < to_dump_count; i++) + walk_tree (&to_dump[i], unmark_visited_r, NULL, NULL); + + /* Finalize the to_dump table. */ + if (to_dump) + { + free (to_dump); + to_dump = NULL; + to_dump_count = 0; + } +} + +/* Print a COMMENT to the output stream PP. */ + +static void +print_comment (pretty_printer *pp, const char *comment) +{ + int len = strlen (comment); + char *str = XALLOCAVEC (char, len + 1); + char *tok; + bool extra_newline = false; + + memcpy (str, comment, len + 1); + + /* Trim C/C++ comment indicators. */ + if (str[len - 2] == '*' && str[len - 1] == '/') + { + str[len - 2] = ' '; + str[len - 1] = '\0'; + } + str += 2; + + tok = strtok (str, "\n"); + while (tok) { + pp_string (pp, " --"); + pp_string (pp, tok); + pp_newline (pp); + tok = strtok (NULL, "\n"); + + /* Leave a blank line after multi-line comments. */ + if (tok) + extra_newline = true; + } + + if (extra_newline) + pp_newline (pp); +} + +/* Prints declaration DECL to PP in Ada syntax. The current source file being + handled is SOURCE_FILE, and CPP_CHECK is used to perform C++ queries on + nodes. */ + +static void +print_generic_ada_decl (pretty_printer *pp, tree decl, + int (*cpp_check)(tree, cpp_operation), + const char* source_file) +{ + source_file_base = source_file; + + if (print_ada_declaration (pp, decl, 0, cpp_check, INDENT_INCR)) + { + pp_newline (pp); + pp_newline (pp); + } +} + +/* Dump a newline and indent BUFFER by SPC chars. */ + +static void +newline_and_indent (pretty_printer *buffer, int spc) +{ + pp_newline (buffer); + INDENT (spc); +} + +struct with { char *s; const char *in_file; int limited; }; +static struct with *withs = NULL; +static int withs_max = 4096; +static int with_len = 0; + +/* Record a "with" clause on package S (a limited with if LIMITED_ACCESS is + true), if not already done. */ + +static void +append_withs (const char *s, int limited_access) +{ + int i; + + if (withs == NULL) + withs = XNEWVEC (struct with, withs_max); + + if (with_len == withs_max) + { + withs_max *= 2; + withs = XRESIZEVEC (struct with, withs, withs_max); + } + + for (i = 0; i < with_len; i++) + if (!strcmp (s, withs [i].s) + && source_file_base == withs [i].in_file) + { + withs [i].limited &= limited_access; + return; + } + + withs [with_len].s = xstrdup (s); + withs [with_len].in_file = source_file_base; + withs [with_len].limited = limited_access; + with_len++; +} + +/* Reset "with" clauses. */ + +static void +reset_ada_withs (void) +{ + int i; + + if (!withs) + return; + + for (i = 0; i < with_len; i++) + free (withs [i].s); + free (withs); + withs = NULL; + withs_max = 4096; + with_len = 0; +} + +/* Dump "with" clauses in F. */ + +static void +dump_ada_withs (FILE *f) +{ + int i; + + fprintf (f, "with Interfaces.C; use Interfaces.C;\n"); + + for (i = 0; i < with_len; i++) + fprintf + (f, "%swith %s;\n", withs [i].limited ? "limited " : "", withs [i].s); +} + +/* Return suitable Ada package name from FILE. */ + +static char * +get_ada_package (const char *file) +{ + const char *base; + char *res; + const char *s; + int i; + + s = strstr (file, "/include/"); + if (s) + base = s + 9; + else + base = lbasename (file); + res = XNEWVEC (char, strlen (base) + 1); + + for (i = 0; *base; base++, i++) + switch (*base) + { + case '+': + res [i] = 'p'; + break; + + case '.': + case '-': + case '_': + case '/': + case '\\': + res [i] = (i == 0 || res [i - 1] == '_') ? 'u' : '_'; + break; + + default: + res [i] = *base; + break; + } + res [i] = '\0'; + + return res; +} + +static const char *ada_reserved[] = { + "abort", "abs", "abstract", "accept", "access", "aliased", "all", "and", + "array", "at", "begin", "body", "case", "constant", "declare", "delay", + "delta", "digits", "do", "else", "elsif", "end", "entry", "exception", + "exit", "for", "function", "generic", "goto", "if", "in", "interface", "is", + "limited", "loop", "mod", "new", "not", "null", "others", "out", "of", "or", + "overriding", "package", "pragma", "private", "procedure", "protected", + "raise", "range", "record", "rem", "renames", "requeue", "return", "reverse", + "select", "separate", "subtype", "synchronized", "tagged", "task", + "terminate", "then", "type", "until", "use", "when", "while", "with", "xor", + NULL}; + +/* ??? would be nice to specify this list via a config file, so that users + can create their own dictionary of conflicts. */ +static const char *c_duplicates[] = { + /* system will cause troubles with System.Address. */ + "system", + + /* The following values have other definitions with same name/other + casing. */ + "funmap", + "rl_vi_fWord", + "rl_vi_bWord", + "rl_vi_eWord", + "rl_readline_version", + "_Vx_ushort", + "USHORT", + "XLookupKeysym", + NULL}; + +/* Return a declaration tree corresponding to TYPE. */ + +static tree +get_underlying_decl (tree type) +{ + tree decl = NULL_TREE; + + if (type == NULL_TREE) + return NULL_TREE; + + /* type is a declaration. */ + if (DECL_P (type)) + decl = type; + + /* type is a typedef. */ + if (TYPE_P (type) && TYPE_NAME (type) && DECL_P (TYPE_NAME (type))) + decl = TYPE_NAME (type); + + /* TYPE_STUB_DECL has been set for type. */ + if (TYPE_P (type) && TYPE_STUB_DECL (type) && + DECL_P (TYPE_STUB_DECL (type))) + decl = TYPE_STUB_DECL (type); + + return decl; +} + +/* Return whether TYPE has static fields. */ + +static int +has_static_fields (const_tree type) +{ + tree tmp; + + for (tmp = TYPE_FIELDS (type); tmp; tmp = TREE_CHAIN (tmp)) + { + if (DECL_NAME (tmp) && TREE_STATIC (tmp)) + return true; + } + return false; +} + +/* Return whether TYPE corresponds to an Ada tagged type (has a dispatch + table). */ + +static int +is_tagged_type (const_tree type) +{ + tree tmp; + + if (!type || !RECORD_OR_UNION_TYPE_P (type)) + return false; + + for (tmp = TYPE_METHODS (type); tmp; tmp = TREE_CHAIN (tmp)) + if (DECL_VINDEX (tmp)) + return true; + + return false; +} + +/* Generate a legal Ada name from a C NAME, returning a malloc'd string. + SPACE_FOUND, if not NULL, is used to indicate whether a space was found in + NAME. */ + +static char * +to_ada_name (const char *name, int *space_found) +{ + const char **names; + int len = strlen (name); + int j, len2 = 0; + int found = false; + char *s = XNEWVEC (char, len * 2 + 5); + char c; + + if (space_found) + *space_found = false; + + /* Add trailing "c_" if name is an Ada reserved word. */ + for (names = ada_reserved; *names; names++) + if (!strcasecmp (name, *names)) + { + s [len2++] = 'c'; + s [len2++] = '_'; + found = true; + break; + } + + if (!found) + /* Add trailing "c_" if name is an potential case sensitive duplicate. */ + for (names = c_duplicates; *names; names++) + if (!strcmp (name, *names)) + { + s [len2++] = 'c'; + s [len2++] = '_'; + found = true; + break; + } + + for (j = 0; name [j] == '_'; j++) + s [len2++] = 'u'; + + if (j > 0) + s [len2++] = '_'; + else if (*name == '.' || *name == '$') + { + s [0] = 'a'; + s [1] = 'n'; + s [2] = 'o'; + s [3] = 'n'; + len2 = 4; + j++; + } + + /* Replace unsuitable characters for Ada identifiers. */ + + for (; j < len; j++) + switch (name [j]) + { + case ' ': + if (space_found) + *space_found = true; + s [len2++] = '_'; + break; + + /* ??? missing some C++ operators. */ + case '=': + s [len2++] = '_'; + + if (name [j + 1] == '=') + { + j++; + s [len2++] = 'e'; + s [len2++] = 'q'; + } + else + { + s [len2++] = 'a'; + s [len2++] = 's'; + } + break; + + case '!': + s [len2++] = '_'; + if (name [j + 1] == '=') + { + j++; + s [len2++] = 'n'; + s [len2++] = 'e'; + } + break; + + case '~': + s [len2++] = '_'; + s [len2++] = 't'; + s [len2++] = 'i'; + break; + + case '&': + case '|': + case '^': + s [len2++] = '_'; + s [len2++] = name [j] == '&' ? 'a' : name [j] == '|' ? 'o' : 'x'; + + if (name [j + 1] == '=') + { + j++; + s [len2++] = 'e'; + } + break; + + case '+': + case '-': + case '*': + case '/': + case '(': + case '[': + if (s [len2 - 1] != '_') + s [len2++] = '_'; + + switch (name [j + 1]) { + case '\0': + j++; + switch (name [j - 1]) { + case '+': s [len2++] = 'p'; break; /* + */ + case '-': s [len2++] = 'm'; break; /* - */ + case '*': s [len2++] = 't'; break; /* * */ + case '/': s [len2++] = 'd'; break; /* / */ + } + break; + + case '=': + j++; + switch (name [j - 1]) { + case '+': s [len2++] = 'p'; break; /* += */ + case '-': s [len2++] = 'm'; break; /* -= */ + case '*': s [len2++] = 't'; break; /* *= */ + case '/': s [len2++] = 'd'; break; /* /= */ + } + s [len2++] = 'a'; + break; + + case '-': /* -- */ + j++; + s [len2++] = 'm'; + s [len2++] = 'm'; + break; + + case '+': /* ++ */ + j++; + s [len2++] = 'p'; + s [len2++] = 'p'; + break; + + case ')': /* () */ + j++; + s [len2++] = 'o'; + s [len2++] = 'p'; + break; + + case ']': /* [] */ + j++; + s [len2++] = 'o'; + s [len2++] = 'b'; + break; + } + + break; + + case '<': + case '>': + c = name [j] == '<' ? 'l' : 'g'; + s [len2++] = '_'; + + switch (name [j + 1]) { + case '\0': + s [len2++] = c; + s [len2++] = 't'; + break; + case '=': + j++; + s [len2++] = c; + s [len2++] = 'e'; + break; + case '>': + j++; + s [len2++] = 's'; + s [len2++] = 'r'; + break; + case '<': + j++; + s [len2++] = 's'; + s [len2++] = 'l'; + break; + default: + break; + } + break; + + case '_': + if (len2 && s [len2 - 1] == '_') + s [len2++] = 'u'; + /* fall through */ + + default: + s [len2++] = name [j]; + } + + if (s [len2 - 1] == '_') + s [len2++] = 'u'; + + s [len2] = '\0'; + + return s; +} + +static bool package_prefix = true; + +/* Dump in BUFFER the name of an identifier NODE of type TYPE, following Ada + syntax. LIMITED_ACCESS indicates whether NODE can be accessed via a limited + 'with' clause rather than a regular 'with' clause. */ + +static void +pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type, + int limited_access) +{ + const char *name = IDENTIFIER_POINTER (node); + int space_found = false; + char *s = to_ada_name (name, &space_found); + tree decl; + + /* If the entity is a type and comes from another file, generate "package" + prefix. */ + + decl = get_underlying_decl (type); + + if (decl) + { + expanded_location xloc = expand_location (decl_sloc (decl, false)); + + if (xloc.file && xloc.line) + { + if (xloc.file != source_file_base) + { + switch (TREE_CODE (type)) + { + case ENUMERAL_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + case BOOLEAN_TYPE: + case REFERENCE_TYPE: + case POINTER_TYPE: + case ARRAY_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + case TYPE_DECL: + { + char *s1 = get_ada_package (xloc.file); + + if (package_prefix) + { + append_withs (s1, limited_access); + pp_string (buffer, s1); + pp_character (buffer, '.'); + } + free (s1); + } + break; + default: + break; + } + } + } + } + + if (space_found) + if (!strcmp (s, "short_int")) + pp_string (buffer, "short"); + else if (!strcmp (s, "short_unsigned_int")) + pp_string (buffer, "unsigned_short"); + else if (!strcmp (s, "unsigned_int")) + pp_string (buffer, "unsigned"); + else if (!strcmp (s, "long_int")) + pp_string (buffer, "long"); + else if (!strcmp (s, "long_unsigned_int")) + pp_string (buffer, "unsigned_long"); + else if (!strcmp (s, "long_long_int")) + pp_string (buffer, "Long_Long_Integer"); + else if (!strcmp (s, "long_long_unsigned_int")) + { + if (package_prefix) + { + append_withs ("Interfaces.C.Extensions", false); + pp_string (buffer, "Extensions.unsigned_long_long"); + } + else + pp_string (buffer, "unsigned_long_long"); + } + else + pp_string(buffer, s); + else + if (!strcmp (s, "bool")) + { + if (package_prefix) + { + append_withs ("Interfaces.C.Extensions", false); + pp_string (buffer, "Extensions.bool"); + } + else + pp_string (buffer, "bool"); + } + else + pp_string(buffer, s); + + free (s); +} + +/* Dump in BUFFER the assembly name of T. */ + +static void +pp_asm_name (pretty_printer *buffer, tree t) +{ + tree name = DECL_ASSEMBLER_NAME (t); + char *ada_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (name) + 1), *s; + const char *ident = IDENTIFIER_POINTER (name); + + for (s = ada_name; *ident; ident++) + { + if (*ident == ' ') + break; + else if (*ident != '*') + *s++ = *ident; + } + + *s = '\0'; + pp_string (buffer, ada_name); +} + +/* Dump in BUFFER the name of a DECL node if set, following Ada syntax. + LIMITED_ACCESS indicates whether NODE can be accessed via a limited + 'with' clause rather than a regular 'with' clause. */ + +static void +dump_ada_decl_name (pretty_printer *buffer, tree decl, int limited_access) +{ + if (DECL_NAME (decl)) + pp_ada_tree_identifier (buffer, DECL_NAME (decl), decl, limited_access); + else + { + tree type_name = TYPE_NAME (TREE_TYPE (decl)); + + if (!type_name) + { + pp_string (buffer, "anon"); + if (TREE_CODE (decl) == FIELD_DECL) + pp_scalar (buffer, "%d", DECL_UID (decl)); + else + pp_scalar (buffer, "%d", TYPE_UID (TREE_TYPE (decl))); + } + else if (TREE_CODE (type_name) == IDENTIFIER_NODE) + pp_ada_tree_identifier (buffer, type_name, decl, limited_access); + } +} + +/* Dump in BUFFER a name based on both T1 and T2, followed by S. */ + +static void +dump_ada_double_name (pretty_printer *buffer, tree t1, tree t2, const char *s) +{ + if (DECL_NAME (t1)) + pp_ada_tree_identifier (buffer, DECL_NAME (t1), t1, false); + else + { + pp_string (buffer, "anon"); + pp_scalar (buffer, "%d", TYPE_UID (TREE_TYPE (t1))); + } + + pp_character (buffer, '_'); + + if (DECL_NAME (t1)) + pp_ada_tree_identifier (buffer, DECL_NAME (t2), t2, false); + else + { + pp_string (buffer, "anon"); + pp_scalar (buffer, "%d", TYPE_UID (TREE_TYPE (t2))); + } + + pp_string (buffer, s); +} + +/* Dump in BUFFER pragma Import C/CPP on a given node T. */ + +static void +dump_ada_import (pretty_printer *buffer, tree t) +{ + const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t)); + int is_stdcall = TREE_CODE (t) == FUNCTION_DECL && + lookup_attribute ("stdcall", TYPE_ATTRIBUTES (TREE_TYPE (t))); + + if (is_stdcall) + pp_string (buffer, "pragma Import (Stdcall, "); + else if (name [0] == '_' && name [1] == 'Z') + pp_string (buffer, "pragma Import (CPP, "); + else + pp_string (buffer, "pragma Import (C, "); + + dump_ada_decl_name (buffer, t, false); + pp_string (buffer, ", \""); + + if (is_stdcall) + pp_string (buffer, IDENTIFIER_POINTER (DECL_NAME (t))); + else + pp_asm_name (buffer, t); + + pp_string (buffer, "\");"); +} + +/* Check whether T and its type have different names, and append "the_" + otherwise in BUFFER. */ + +static void +check_name (pretty_printer *buffer, tree t) +{ + const char *s; + tree tmp = TREE_TYPE (t); + + while (TREE_CODE (tmp) == POINTER_TYPE && !TYPE_NAME (tmp)) + tmp = TREE_TYPE (tmp); + + if (TREE_CODE (tmp) != FUNCTION_TYPE) + { + if (TREE_CODE (tmp) == IDENTIFIER_NODE) + s = IDENTIFIER_POINTER (tmp); + else if (!TYPE_NAME (tmp)) + s = ""; + else if (TREE_CODE (TYPE_NAME (tmp)) == IDENTIFIER_NODE) + s = IDENTIFIER_POINTER (TYPE_NAME (tmp)); + else + s = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (tmp))); + + if (!strcasecmp (IDENTIFIER_POINTER (DECL_NAME (t)), s)) + pp_string (buffer, "the_"); + } +} + +/* Dump in BUFFER a function declaration FUNC with Ada syntax. + IS_METHOD indicates whether FUNC is a C++ method. + IS_CONSTRUCTOR whether FUNC is a C++ constructor. + IS_DESTRUCTOR whether FUNC is a C++ destructor. + SPC is the current indentation level. */ + +static int +dump_ada_function_declaration (pretty_printer *buffer, tree func, + int is_method, int is_constructor, + int is_destructor, int spc) +{ + tree arg; + const tree node = TREE_TYPE (func); + char buf [16]; + int num = 0, num_args = 0, have_args = true, have_ellipsis = false; + + /* Compute number of arguments. */ + arg = TYPE_ARG_TYPES (node); + + if (arg) + { + while (TREE_CHAIN (arg) && arg != error_mark_node) + { + num_args++; + arg = TREE_CHAIN (arg); + } + + if (TREE_CODE (TREE_VALUE (arg)) != VOID_TYPE) + { + num_args++; + have_ellipsis = true; + } + } + + if (is_constructor) + num_args--; + + if (is_destructor) + num_args = 1; + + if (num_args > 2) + newline_and_indent (buffer, spc + 1); + + if (num_args > 0) + { + pp_space (buffer); + pp_character (buffer, '('); + } + + if (TREE_CODE (func) == FUNCTION_DECL) + arg = DECL_ARGUMENTS (func); + else + arg = NULL_TREE; + + if (arg == NULL_TREE) + { + have_args = false; + arg = TYPE_ARG_TYPES (node); + + if (arg && TREE_CODE (TREE_VALUE (arg)) == VOID_TYPE) + arg = NULL_TREE; + } + + if (is_constructor) + arg = TREE_CHAIN (arg); + + /* Print the argument names (if available) & types. */ + + for (num = 1; num <= num_args; num++) + { + if (have_args) + { + if (DECL_NAME (arg)) + { + check_name (buffer, arg); + pp_ada_tree_identifier (buffer, DECL_NAME (arg), 0, false); + pp_string (buffer, " : "); + } + else + { + sprintf (buf, "arg%d : ", num); + pp_string (buffer, buf); + } + + dump_generic_ada_node + (buffer, TREE_TYPE (arg), node, NULL, spc, 0, true); + } + else + { + sprintf (buf, "arg%d : ", num); + pp_string (buffer, buf); + dump_generic_ada_node + (buffer, TREE_VALUE (arg), node, NULL, spc, 0, true); + } + + if (TREE_TYPE (arg) && TREE_TYPE (TREE_TYPE (arg)) + && is_tagged_type (TREE_TYPE (TREE_TYPE (arg)))) + { + if (!is_method + || (num != 1 || (!DECL_VINDEX (func) && !is_constructor))) + pp_string (buffer, "'Class"); + } + + arg = TREE_CHAIN (arg); + + if (num < num_args) + { + pp_character (buffer, ';'); + + if (num_args > 2) + newline_and_indent (buffer, spc + INDENT_INCR); + else + pp_space (buffer); + } + } + + if (have_ellipsis) + { + pp_string (buffer, " -- , ..."); + newline_and_indent (buffer, spc + INDENT_INCR); + } + + if (num_args > 0) + pp_character (buffer, ')'); + return num_args; +} + +/* Dump in BUFFER all the domains associated with an array NODE, + using Ada syntax. SPC is the current indentation level. */ + +static void +dump_ada_array_domains (pretty_printer *buffer, tree node, int spc) +{ + int first = 1; + pp_character (buffer, '('); + + for (; TREE_CODE (node) == ARRAY_TYPE; node = TREE_TYPE (node)) + { + tree domain = TYPE_DOMAIN (node); + + if (domain) + { + tree min = TYPE_MIN_VALUE (domain); + tree max = TYPE_MAX_VALUE (domain); + + if (!first) + pp_string (buffer, ", "); + first = 0; + + if (min) + dump_generic_ada_node (buffer, min, NULL_TREE, NULL, spc, 0, true); + pp_string (buffer, " .. "); + + /* If the upper bound is zero, gcc may generate a NULL_TREE + for TYPE_MAX_VALUE rather than an integer_cst. */ + if (max) + dump_generic_ada_node (buffer, max, NULL_TREE, NULL, spc, 0, true); + else + pp_string (buffer, "0"); + } + else + pp_string (buffer, "size_t"); + } + pp_character (buffer, ')'); +} + +/* Dump in BUFFER file:line:col information related to NODE. */ + +static void +dump_sloc (pretty_printer *buffer, tree node) +{ + expanded_location xloc; + + xloc.file = NULL; + + if (TREE_CODE_CLASS (TREE_CODE (node)) == tcc_declaration) + xloc = expand_location (DECL_SOURCE_LOCATION (node)); + else if (EXPR_HAS_LOCATION (node)) + xloc = expand_location (EXPR_LOCATION (node)); + + if (xloc.file) + { + pp_string (buffer, xloc.file); + pp_string (buffer, ":"); + pp_decimal_int (buffer, xloc.line); + pp_string (buffer, ":"); + pp_decimal_int (buffer, xloc.column); + } +} + +/* Return true if T designates a one dimension array of "char". */ + +static bool +is_char_array (tree t) +{ + tree tmp; + int num_dim = 0; + + /* Retrieve array's type. */ + tmp = t; + while (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE) + { + num_dim++; + tmp = TREE_TYPE (tmp); + } + + tmp = TREE_TYPE (tmp); + return num_dim == 1 && TREE_CODE (tmp) == INTEGER_TYPE + && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (tmp))), "char"); +} + +/* Dump in BUFFER an array type T in Ada syntax. Assume that the "type" + keyword and name have already been printed. SPC is the indentation + level. */ + +static void +dump_ada_array_type (pretty_printer *buffer, tree t, int spc) +{ + tree tmp; + bool char_array = is_char_array (t); + + /* Special case char arrays. */ + if (char_array) + { + pp_string (buffer, "Interfaces.C.char_array "); + } + else + pp_string (buffer, "array "); + + /* Print the dimensions. */ + dump_ada_array_domains (buffer, TREE_TYPE (t), spc); + + /* Retrieve array's type. */ + tmp = TREE_TYPE (t); + while (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE) + tmp = TREE_TYPE (tmp); + + /* Print array's type. */ + if (!char_array) + { + pp_string (buffer, " of "); + + if (TREE_CODE (TREE_TYPE (tmp)) != POINTER_TYPE) + pp_string (buffer, "aliased "); + + dump_generic_ada_node + (buffer, TREE_TYPE (tmp), TREE_TYPE (t), NULL, spc, false, true); + } +} + +/* Dump in BUFFER type names associated with a template, each prepended with + '_'. TYPES is the TREE_PURPOSE of a DECL_TEMPLATE_INSTANTIATIONS. + CPP_CHECK is used to perform C++ queries on nodes. + SPC is the indentation level. */ + +static void +dump_template_types (pretty_printer *buffer, tree types, + int (*cpp_check)(tree, cpp_operation), int spc) +{ + size_t i; + size_t len = TREE_VEC_LENGTH (types); + + for (i = 0; i < len; i++) + { + tree elem = TREE_VEC_ELT (types, i); + pp_character (buffer, '_'); + if (!dump_generic_ada_node (buffer, elem, 0, cpp_check, spc, false, true)) + { + pp_string (buffer, "unknown"); + pp_scalar (buffer, "%lu", (unsigned long) TREE_HASH (elem)); + } + } +} + +/* Dump in BUFFER the contents of all instantiations associated with a given + template T. CPP_CHECK is used to perform C++ queries on nodes. + SPC is the indentation level. */ + +static int +dump_ada_template (pretty_printer *buffer, tree t, + int (*cpp_check)(tree, cpp_operation), int spc) +{ + tree inst = DECL_VINDEX (t); + /* DECL_VINDEX is DECL_TEMPLATE_INSTANTIATIONS in this context. */ + int num_inst = 0; + + while (inst && inst != error_mark_node) + { + tree types = TREE_PURPOSE (inst); + tree instance = TREE_VALUE (inst); + + if (TREE_VEC_LENGTH (types) == 0) + break; + + if (!TYPE_METHODS (instance)) + break; + + num_inst++; + INDENT (spc); + pp_string (buffer, "package "); + package_prefix = false; + dump_generic_ada_node (buffer, instance, t, cpp_check, spc, false, true); + dump_template_types (buffer, types, cpp_check, spc); + pp_string (buffer, " is"); + spc += INDENT_INCR; + newline_and_indent (buffer, spc); + + pp_string (buffer, "type "); + dump_generic_ada_node (buffer, instance, t, cpp_check, spc, false, true); + package_prefix = true; + + if (is_tagged_type (instance)) + pp_string (buffer, " is tagged limited "); + else + pp_string (buffer, " is limited "); + + dump_generic_ada_node (buffer, instance, t, cpp_check, spc, false, false); + pp_newline (buffer); + spc -= INDENT_INCR; + newline_and_indent (buffer, spc); + + pp_string (buffer, "end;"); + newline_and_indent (buffer, spc); + pp_string (buffer, "use "); + package_prefix = false; + dump_generic_ada_node (buffer, instance, t, cpp_check, spc, false, true); + dump_template_types (buffer, types, cpp_check, spc); + package_prefix = true; + pp_semicolon (buffer); + pp_newline (buffer); + pp_newline (buffer); + + inst = TREE_CHAIN (inst); + } + + return num_inst > 0; +} + +static bool in_function = true; +static bool bitfield_used = false; + +/* Recursively dump in BUFFER Ada declarations corresponding to NODE of type + TYPE. CPP_CHECK is used to perform C++ queries on nodes. SPC is the + indentation level. LIMITED_ACCESS indicates whether NODE can be referenced + via a "limited with" clause. NAME_ONLY indicates whether we should only + dump the name of NODE, instead of its full declaration. */ + +static int +dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, + int (*cpp_check)(tree, cpp_operation), int spc, + int limited_access, bool name_only) +{ + if (node == NULL_TREE) + return 0; + + switch (TREE_CODE (node)) + { + case ERROR_MARK: + pp_string (buffer, "<<< error >>>"); + return 0; + + case IDENTIFIER_NODE: + pp_ada_tree_identifier (buffer, node, type, limited_access); + break; + + case TREE_LIST: + pp_string (buffer, "--- unexpected node: TREE_LIST"); + return 0; + + case TREE_BINFO: + dump_generic_ada_node + (buffer, BINFO_TYPE (node), type, cpp_check, + spc, limited_access, name_only); + + case TREE_VEC: + pp_string (buffer, "--- unexpected node: TREE_VEC"); + return 0; + + case VOID_TYPE: + if (package_prefix) + { + append_withs ("System", false); + pp_string (buffer, "System.Address"); + } + else + pp_string (buffer, "address"); + break; + + case VECTOR_TYPE: + pp_string (buffer, ""); + break; + + case COMPLEX_TYPE: + pp_string (buffer, ""); + break; + + case ENUMERAL_TYPE: + if (name_only) + dump_generic_ada_node + (buffer, TYPE_NAME (node), node, cpp_check, spc, 0, true); + else + { + tree value; + + pp_string (buffer, "unsigned"); + + for (value = TYPE_VALUES (node); value; value = TREE_CHAIN (value)) + { + pp_semicolon (buffer); + newline_and_indent (buffer, spc); + + pp_ada_tree_identifier + (buffer, TREE_PURPOSE (value), node, false); + pp_string (buffer, " : constant "); + + dump_generic_ada_node + (buffer, DECL_NAME (type) ? type : TYPE_NAME (node), type, + cpp_check, spc, 0, true); + + pp_string (buffer, " := "); + dump_generic_ada_node + (buffer, + TREE_CODE (TREE_VALUE (value)) == INTEGER_CST ? + TREE_VALUE (value) : DECL_INITIAL (TREE_VALUE (value)), + node, + cpp_check, spc, false, true); + } + } + break; + + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + case BOOLEAN_TYPE: + { + enum tree_code_class tclass; + + tclass = TREE_CODE_CLASS (TREE_CODE (node)); + + if (tclass == tcc_declaration) + { + if (DECL_NAME (node)) + pp_ada_tree_identifier + (buffer, DECL_NAME (node), 0, limited_access); + else + pp_string (buffer, ""); + } + else if (tclass == tcc_type) + { + if (TYPE_NAME (node)) + { + if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) + pp_ada_tree_identifier (buffer, TYPE_NAME (node), + node, limited_access); + else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (node))) + dump_ada_decl_name (buffer, TYPE_NAME (node), limited_access); + else + pp_string (buffer, ""); + } + else if (TREE_CODE (node) == INTEGER_TYPE) + { + append_withs ("Interfaces.C.Extensions", false); + bitfield_used = true; + + if (TYPE_PRECISION (node) == 1) + pp_string (buffer, "Extensions.Unsigned_1"); + else + { + pp_string (buffer, (TYPE_UNSIGNED (node) + ? "Extensions.Unsigned_" + : "Extensions.Signed_")); + pp_decimal_int (buffer, TYPE_PRECISION (node)); + } + } + else + pp_string (buffer, ""); + } + break; + } + + case POINTER_TYPE: + case REFERENCE_TYPE: + if (TREE_CODE (TREE_TYPE (node)) == FUNCTION_TYPE) + { + tree fnode = TREE_TYPE (node); + bool is_function; + bool prev_in_function = in_function; + + if (VOID_TYPE_P (TREE_TYPE (fnode))) + { + is_function = false; + pp_string (buffer, "access procedure"); + } + else + { + is_function = true; + pp_string (buffer, "access function"); + } + + in_function = is_function; + dump_ada_function_declaration + (buffer, node, false, false, false, spc + INDENT_INCR); + in_function = prev_in_function; + + if (is_function) + { + pp_string (buffer, " return "); + dump_generic_ada_node + (buffer, TREE_TYPE (fnode), type, cpp_check, spc, 0, true); + } + } + else + { + int is_access = false; + unsigned int quals = TYPE_QUALS (TREE_TYPE (node)); + + if (name_only && TYPE_NAME (node)) + dump_generic_ada_node + (buffer, TYPE_NAME (node), node, cpp_check, + spc, limited_access, true); + else if (VOID_TYPE_P (TREE_TYPE (node))) + { + if (!name_only) + pp_string (buffer, "new "); + if (package_prefix) + { + append_withs ("System", false); + pp_string (buffer, "System.Address"); + } + else + pp_string (buffer, "address"); + } + else + { + if (TREE_CODE (node) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (node)) == INTEGER_TYPE + && !strcmp + (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME + (TREE_TYPE (node)))), "char")) + { + if (!name_only) + pp_string (buffer, "new "); + + if (package_prefix) + { + pp_string (buffer, "Interfaces.C.Strings.chars_ptr"); + append_withs ("Interfaces.C.Strings", false); + } + else + pp_string (buffer, "chars_ptr"); + } + else + { + /* For now, handle all access-to-access or + access-to-unknown-structs as opaque system.address. */ + + tree typ = TYPE_NAME (TREE_TYPE (node)); + const_tree typ2 = !type || + DECL_P (type) ? type : TYPE_NAME (type); + const_tree underlying_type = + get_underlying_decl (TREE_TYPE (node)); + + if (TREE_CODE (TREE_TYPE (node)) == POINTER_TYPE + /* Pointer to pointer. */ + + || (RECORD_OR_UNION_TYPE_P (TREE_TYPE (node)) + && (!underlying_type + || !TYPE_FIELDS (TREE_TYPE (underlying_type)))) + /* Pointer to opaque structure. */ + + || (typ && typ2 + && DECL_P (underlying_type) + && DECL_P (typ2) + && decl_sloc (underlying_type, true) + > decl_sloc (typ2, true) + && DECL_SOURCE_FILE (underlying_type) + == DECL_SOURCE_FILE (typ2))) + { + if (package_prefix) + { + append_withs ("System", false); + if (!name_only) + pp_string (buffer, "new "); + pp_string (buffer, "System.Address"); + } + else + pp_string (buffer, "address"); + return spc; + } + + if (!package_prefix) + pp_string (buffer, "access"); + else if (AGGREGATE_TYPE_P (TREE_TYPE (node))) + { + if (!type || TREE_CODE (type) != FUNCTION_DECL) + { + pp_string (buffer, "access "); + is_access = true; + + if (quals & TYPE_QUAL_CONST) + pp_string (buffer, "constant "); + else if (!name_only) + pp_string (buffer, "all "); + } + else if (quals & TYPE_QUAL_CONST) + pp_string (buffer, "in "); + else if (in_function) + { + is_access = true; + pp_string (buffer, "access "); + } + else + { + is_access = true; + pp_string (buffer, "access "); + /* ??? should be configurable: access or in out. */ + } + } + else + { + is_access = true; + pp_string (buffer, "access "); + + if (!name_only) + pp_string (buffer, "all "); + } + + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (node)) + && TYPE_NAME (TREE_TYPE (node))) + { + tree name = TYPE_NAME (TREE_TYPE (node)); + tree tmp; + + if (TREE_CODE (name) == TYPE_DECL + && DECL_ORIGINAL_TYPE (name) + && TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (name))) + { + tmp = TYPE_NAME (TREE_TYPE (TYPE_STUB_DECL + (DECL_ORIGINAL_TYPE (name)))); + + if (tmp == NULL_TREE) + tmp = TYPE_NAME (TREE_TYPE (node)); + } + else + tmp = TYPE_NAME (TREE_TYPE (node)); + + dump_generic_ada_node + (buffer, tmp, + TREE_TYPE (node), cpp_check, spc, is_access, true); + } + else + dump_generic_ada_node + (buffer, TREE_TYPE (node), TREE_TYPE (node), + cpp_check, spc, 0, true); + } + } + } + break; + + case ARRAY_TYPE: + if (name_only) + dump_generic_ada_node + (buffer, TYPE_NAME (node), node, cpp_check, + spc, limited_access, true); + else + dump_ada_array_type (buffer, node, spc); + break; + + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + if (name_only) + { + if (TYPE_NAME (node)) + dump_generic_ada_node + (buffer, TYPE_NAME (node), node, cpp_check, + spc, limited_access, true); + else + { + pp_string (buffer, "anon_"); + pp_scalar (buffer, "%d", TYPE_UID (node)); + } + } + else + print_ada_struct_decl + (buffer, node, type, cpp_check, spc, true); + break; + + case INTEGER_CST: + if (TREE_CODE (TREE_TYPE (node)) == POINTER_TYPE) + { + pp_wide_integer (buffer, TREE_INT_CST_LOW (node)); + pp_string (buffer, "B"); /* pseudo-unit */ + } + else if (! host_integerp (node, 0)) + { + tree val = node; + unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (val); + HOST_WIDE_INT high = TREE_INT_CST_HIGH (val); + + if (tree_int_cst_sgn (val) < 0) + { + pp_character (buffer, '-'); + high = ~high + !low; + low = -low; + } + sprintf (pp_buffer (buffer)->digit_buffer, + HOST_WIDE_INT_PRINT_DOUBLE_HEX, + (unsigned HOST_WIDE_INT) high, low); + pp_string (buffer, pp_buffer (buffer)->digit_buffer); + } + else + pp_wide_integer (buffer, TREE_INT_CST_LOW (node)); + break; + + case REAL_CST: + case FIXED_CST: + case COMPLEX_CST: + case STRING_CST: + case VECTOR_CST: + return 0; + + case FUNCTION_DECL: + case CONST_DECL: + dump_ada_decl_name (buffer, node, limited_access); + break; + + case TYPE_DECL: + if (DECL_IS_BUILTIN (node)) + { + /* Don't print the declaration of built-in types. */ + + if (name_only) + { + /* If we're in the middle of a declaration, defaults to + System.Address. */ + if (package_prefix) + { + append_withs ("System", false); + pp_string (buffer, "System.Address"); + } + else + pp_string (buffer, "address"); + } + break; + } + + if (name_only) + dump_ada_decl_name (buffer, node, limited_access); + else + { + if (is_tagged_type (TREE_TYPE (node))) + { + tree tmp = TYPE_FIELDS (TREE_TYPE (node)); + int first = 1; + + /* Look for ancestors. */ + for (; tmp; tmp = TREE_CHAIN (tmp)) + { + if (!DECL_NAME (tmp) && is_tagged_type (TREE_TYPE (tmp))) + { + if (first) + { + pp_string (buffer, "limited new "); + first = 0; + } + else + pp_string (buffer, " and "); + + dump_ada_decl_name + (buffer, TYPE_NAME (TREE_TYPE (tmp)), false); + } + } + + pp_string (buffer, first ? "tagged limited " : " with "); + } + else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (node)) + && TYPE_METHODS (TREE_TYPE (node))) + pp_string (buffer, "limited "); + + dump_generic_ada_node + (buffer, TREE_TYPE (node), type, cpp_check, spc, false, false); + } + break; + + case VAR_DECL: + case PARM_DECL: + case FIELD_DECL: + case NAMESPACE_DECL: + dump_ada_decl_name (buffer, node, false); + break; + + default: + /* Ignore other nodes (e.g. expressions). */ + return 0; + } + + return 1; +} + +/* Dump in BUFFER NODE's methods. CPP_CHECK is used to perform C++ queries on + nodes. SPC is the indentation level. */ + +static void +print_ada_methods (pretty_printer *buffer, tree node, + int (*cpp_check)(tree, cpp_operation), int spc) +{ + tree tmp = TYPE_METHODS (node); + int res = 1; + + if (tmp) + { + pp_semicolon (buffer); + + for (; tmp; tmp = TREE_CHAIN (tmp)) + { + if (res) + { + pp_newline (buffer); + pp_newline (buffer); + } + res = print_ada_declaration (buffer, tmp, node, cpp_check, spc); + } + } +} + +/* Dump in BUFFER anonymous types nested inside T's definition. + PARENT is the parent node of T. CPP_CHECK is used to perform C++ queries on + nodes. SPC is the indentation level. */ + +static void +dump_nested_types (pretty_printer *buffer, tree t, tree parent, + int (*cpp_check)(tree, cpp_operation), int spc) +{ + tree field, outer, decl; + + /* Avoid recursing over the same tree. */ + if (TREE_VISITED (t)) + return; + + /* Find possible anonymous arrays/unions/structs recursively. */ + + outer = TREE_TYPE (t); + + if (outer == NULL_TREE) + return; + + field = TYPE_FIELDS (outer); + while (field) + { + if ((TREE_TYPE (field) != outer + || (TREE_CODE (TREE_TYPE (field)) == POINTER_TYPE + && TREE_TYPE (TREE_TYPE (field)) != outer)) + && (!TYPE_NAME (TREE_TYPE (field)) + || (TREE_CODE (field) == TYPE_DECL + && DECL_NAME (field) != DECL_NAME (t) + && TYPE_NAME (TREE_TYPE (field)) != TYPE_NAME (outer)))) + { + switch (TREE_CODE (TREE_TYPE (field))) + { + case POINTER_TYPE: + decl = TREE_TYPE (TREE_TYPE (field)); + + if (TREE_CODE (decl) == FUNCTION_TYPE) + for (decl = TREE_TYPE (decl); + decl && TREE_CODE (decl) == POINTER_TYPE; + decl = TREE_TYPE (decl)); + + decl = get_underlying_decl (decl); + + if (decl + && DECL_P (decl) + && decl_sloc (decl, true) > decl_sloc (t, true) + && DECL_SOURCE_FILE (decl) == DECL_SOURCE_FILE (t) + && !TREE_VISITED (decl) + && !DECL_IS_BUILTIN (decl) + && (!RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)) + || TYPE_FIELDS (TREE_TYPE (decl)))) + { + /* Generate forward declaration. */ + + pp_string (buffer, "type "); + dump_generic_ada_node + (buffer, decl, 0, cpp_check, spc, false, true); + pp_semicolon (buffer); + newline_and_indent (buffer, spc); + + /* Ensure we do not generate duplicate forward + declarations for this type. */ + TREE_VISITED (decl) = 1; + } + break; + + case ARRAY_TYPE: + /* Special case char arrays. */ + if (is_char_array (field)) + pp_string (buffer, "sub"); + + pp_string (buffer, "type "); + dump_ada_double_name (buffer, parent, field, "_array is "); + dump_ada_array_type (buffer, field, spc); + pp_semicolon (buffer); + newline_and_indent (buffer, spc); + break; + + case UNION_TYPE: + TREE_VISITED (t) = 1; + dump_nested_types (buffer, field, t, cpp_check, spc); + + pp_string (buffer, "type "); + + if (TYPE_NAME (TREE_TYPE (field))) + { + dump_generic_ada_node + (buffer, TYPE_NAME (TREE_TYPE (field)), 0, cpp_check, + spc, false, true); + pp_string (buffer, " (discr : unsigned := 0) is "); + print_ada_struct_decl + (buffer, TREE_TYPE (field), t, cpp_check, spc, false); + + pp_string (buffer, "pragma Convention (C_Pass_By_Copy, "); + dump_generic_ada_node + (buffer, TREE_TYPE (field), 0, cpp_check, + spc, false, true); + pp_string (buffer, ");"); + newline_and_indent (buffer, spc); + + pp_string (buffer, "pragma Unchecked_Union ("); + dump_generic_ada_node + (buffer, TREE_TYPE (field), 0, cpp_check, + spc, false, true); + pp_string (buffer, ");"); + } + else + { + dump_ada_double_name + (buffer, parent, field, + "_union (discr : unsigned := 0) is "); + print_ada_struct_decl + (buffer, TREE_TYPE (field), t, cpp_check, spc, false); + pp_string (buffer, "pragma Convention (C_Pass_By_Copy, "); + dump_ada_double_name (buffer, parent, field, "_union);"); + newline_and_indent (buffer, spc); + + pp_string (buffer, "pragma Unchecked_Union ("); + dump_ada_double_name (buffer, parent, field, "_union);"); + } + + newline_and_indent (buffer, spc); + break; + + case RECORD_TYPE: + if (TYPE_NAME (TREE_TYPE (t)) && !TREE_VISITED (t)) + { + pp_string (buffer, "type "); + dump_generic_ada_node + (buffer, t, parent, 0, spc, false, true); + pp_semicolon (buffer); + newline_and_indent (buffer, spc); + } + + TREE_VISITED (t) = 1; + dump_nested_types (buffer, field, t, cpp_check, spc); + pp_string (buffer, "type "); + + if (TYPE_NAME (TREE_TYPE (field))) + { + dump_generic_ada_node + (buffer, TREE_TYPE (field), 0, cpp_check, + spc, false, true); + pp_string (buffer, " is "); + print_ada_struct_decl + (buffer, TREE_TYPE (field), t, cpp_check, spc, false); + pp_string (buffer, "pragma Convention (C_Pass_By_Copy, "); + dump_generic_ada_node + (buffer, TREE_TYPE (field), 0, cpp_check, + spc, false, true); + pp_string (buffer, ");"); + } + else + { + dump_ada_double_name + (buffer, parent, field, "_struct is "); + print_ada_struct_decl + (buffer, TREE_TYPE (field), t, cpp_check, spc, false); + pp_string (buffer, "pragma Convention (C_Pass_By_Copy, "); + dump_ada_double_name (buffer, parent, field, "_struct);"); + } + + newline_and_indent (buffer, spc); + break; + + default: + break; + } + } + field = TREE_CHAIN (field); + } +} + +/* Dump in BUFFER destructor spec corresponding to T. */ + +static void +print_destructor (pretty_printer *buffer, tree t) +{ + const char *s = IDENTIFIER_POINTER (DECL_NAME (t)); + + if (*s == '_') + for (s += 2; *s != ' '; s++) + pp_character (buffer, *s); + else + { + pp_string (buffer, "Delete_"); + pp_ada_tree_identifier (buffer, DECL_NAME (t), t, false); + } +} + +/* Return the name of type T. */ + +static const char * +type_name (tree t) +{ + tree n = TYPE_NAME (t); + + if (TREE_CODE (n) == IDENTIFIER_NODE) + return IDENTIFIER_POINTER (n); + else + return IDENTIFIER_POINTER (DECL_NAME (n)); +} + +/* Print in BUFFER the declaration of a variable T of type TYPE in Ada syntax. + CPP_CHECK is used to perform C++ queries on nodes. SPC is the indentation + level. Return 1 if a declaration was printed, 0 otherwise. */ + +static int +print_ada_declaration (pretty_printer *buffer, tree t, tree type, + int (*cpp_check)(tree, cpp_operation), int spc) +{ + int is_var = 0, need_indent = 0; + int is_class = false; + tree name = TYPE_NAME (TREE_TYPE (t)); + tree decl_name = DECL_NAME (t); + bool dump_internal = get_dump_file_info (TDI_ada)->flags & TDF_RAW; + tree orig = NULL_TREE; + + if (cpp_check && cpp_check (t, IS_TEMPLATE)) + return dump_ada_template (buffer, t, cpp_check, spc); + + if (TREE_CODE (t) == CONST_DECL && TREE_CODE (TREE_TYPE (t)) == ENUMERAL_TYPE) + /* Skip enumeral values: will be handled as part of the type itself. */ + return 0; + + if (TREE_CODE (t) == TYPE_DECL) + { + orig = DECL_ORIGINAL_TYPE (t); + + if (orig && TYPE_STUB_DECL (orig)) + { + tree typ = TREE_TYPE (TYPE_STUB_DECL (orig)); + + if (TYPE_NAME (typ)) + { + /* If types have same representation, and same name (ignoring + casing), then ignore the second type. */ + if (type_name (typ) == type_name (TREE_TYPE (t)) + || !strcasecmp (type_name (typ), type_name (TREE_TYPE (t)))) + return 0; + + INDENT (spc); + + if (RECORD_OR_UNION_TYPE_P (typ) && !TYPE_FIELDS (typ)) + { + pp_string (buffer, "-- skipped empty struct "); + dump_generic_ada_node (buffer, t, type, 0, spc, false, true); + } + else + { + pp_string (buffer, "subtype "); + dump_generic_ada_node (buffer, t, type, 0, spc, false, true); + pp_string (buffer, " is "); + dump_generic_ada_node + (buffer, typ, type, 0, spc, false, true); + pp_semicolon (buffer); + } + return 1; + } + } + + /* Skip unnamed or anonymous structs/unions/enum types. */ + if (!orig && !decl_name && !name) + { + tree tmp; + location_t sloc; + + if (cpp_check || TREE_CODE (TREE_TYPE (t)) == ENUMERAL_TYPE) + return 0; + + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))) + { + /* Search next items until finding a named type decl. */ + sloc = decl_sloc_common (t, true, true); + + for (tmp = TREE_CHAIN (t); tmp; tmp = TREE_CHAIN (tmp)) + { + if (TREE_CODE (tmp) == TYPE_DECL + && (DECL_NAME (tmp) || TYPE_NAME (TREE_TYPE (tmp)))) + { + /* If same sloc, it means we can ignore the anonymous + struct. */ + if (decl_sloc_common (tmp, true, true) == sloc) + return 0; + else + break; + } + } + if (tmp == NULL) + return 0; + } + } + + if (!orig + && TREE_CODE (TREE_TYPE (t)) == ENUMERAL_TYPE + && decl_name + && (*IDENTIFIER_POINTER (decl_name) == '.' + || *IDENTIFIER_POINTER (decl_name) == '$')) + /* Skip anonymous enum types (duplicates of real types). */ + return 0; + + INDENT (spc); + + switch (TREE_CODE (TREE_TYPE (t))) + { + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + /* Skip empty structs (typically forward references to real + structs). */ + if (!TYPE_FIELDS (TREE_TYPE (t))) + { + pp_string (buffer, "-- skipped empty struct "); + dump_generic_ada_node (buffer, t, type, 0, spc, false, true); + return 1; + } + + if (decl_name + && (*IDENTIFIER_POINTER (decl_name) == '.' + || *IDENTIFIER_POINTER (decl_name) == '$')) + { + pp_string (buffer, "-- skipped anonymous struct "); + dump_generic_ada_node (buffer, t, type, 0, spc, false, true); + return 1; + } + + if (orig && TYPE_NAME (orig) && orig != TREE_TYPE (t)) + pp_string (buffer, "subtype "); + else + { + dump_nested_types (buffer, t, t, cpp_check, spc); + + if (TYPE_METHODS (TREE_TYPE (t)) + || has_static_fields (TREE_TYPE (t))) + { + is_class = true; + pp_string (buffer, "package Class_"); + dump_generic_ada_node + (buffer, t, type, 0, spc, false, true); + pp_string (buffer, " is"); + spc += INDENT_INCR; + newline_and_indent (buffer, spc); + } + + pp_string (buffer, "type "); + } + break; + + case ARRAY_TYPE: + case POINTER_TYPE: + case REFERENCE_TYPE: + if ((orig && TYPE_NAME (orig) && orig != TREE_TYPE (t)) + || is_char_array (t)) + pp_string (buffer, "subtype "); + else + pp_string (buffer, "type "); + break; + + case FUNCTION_TYPE: + pp_string (buffer, "-- skipped function type "); + dump_generic_ada_node (buffer, t, type, 0, spc, false, true); + return 1; + break; + + default: + pp_string (buffer, "subtype "); + } + } + else + { + if (!dump_internal + && TREE_CODE (t) == VAR_DECL + && decl_name + && *IDENTIFIER_POINTER (decl_name) == '_') + return 0; + + need_indent = 1; + } + + /* Print the type and name. */ + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + { + if (need_indent) + INDENT (spc); + + /* Print variable's name. */ + dump_generic_ada_node (buffer, t, type, cpp_check, spc, false, true); + + if (TREE_CODE (t) == TYPE_DECL) + { + pp_string (buffer, " is "); + + if (orig && TYPE_NAME (orig) && orig != TREE_TYPE (t)) + dump_generic_ada_node + (buffer, TYPE_NAME (orig), type, + cpp_check, spc, false, true); + else + dump_ada_array_type (buffer, t, spc); + } + else + { + tree tmp = TYPE_NAME (TREE_TYPE (t)); + + if (spc == INDENT_INCR || TREE_STATIC (t)) + is_var = 1; + + pp_string (buffer, " : "); + + if (tmp) + { + if (TREE_CODE (TREE_TYPE (tmp)) != POINTER_TYPE + && TREE_CODE (tmp) != INTEGER_TYPE) + pp_string (buffer, "aliased "); + + dump_generic_ada_node (buffer, tmp, type, 0, spc, false, true); + } + else + { + pp_string (buffer, "aliased "); + + if (!type) + dump_ada_array_type (buffer, t, spc); + else + dump_ada_double_name (buffer, type, t, "_array"); + } + } + } + else if (TREE_CODE (t) == FUNCTION_DECL) + { + bool is_function = true, is_method, is_abstract_class = false; + tree decl_name = DECL_NAME (t); + int prev_in_function = in_function; + bool is_abstract = false; + bool is_constructor = false; + bool is_destructor = false; + bool is_copy_constructor = false; + + if (!decl_name) + return 0; + + if (cpp_check) + { + is_abstract = cpp_check (t, IS_ABSTRACT); + is_constructor = cpp_check (t, IS_CONSTRUCTOR); + is_destructor = cpp_check (t, IS_DESTRUCTOR); + is_copy_constructor = cpp_check (t, IS_COPY_CONSTRUCTOR); + } + + /* Skip __comp_dtor destructor which is redundant with the '~class()' + destructor. */ + if (is_destructor + && !strncmp (IDENTIFIER_POINTER (decl_name), "__comp", 6)) + return 0; + + /* Skip copy constructors: some are internal only, and those that are + not cannot be called easily from Ada anyway. */ + if (is_copy_constructor) + return 0; + + /* If this function has an entry in the dispatch table, we cannot + omit it. */ + if (!dump_internal && !DECL_VINDEX (t) + && *IDENTIFIER_POINTER (decl_name) == '_') + { + if (IDENTIFIER_POINTER (decl_name)[1] == '_') + return 0; + + INDENT (spc); + pp_string (buffer, "-- skipped func "); + pp_string (buffer, IDENTIFIER_POINTER (decl_name)); + return 1; + } + + if (need_indent) + INDENT (spc); + + if (is_constructor) + pp_string (buffer, "function New_"); + else if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (t)))) + { + is_function = false; + pp_string (buffer, "procedure "); + } + else + pp_string (buffer, "function "); + + in_function = is_function; + is_method = TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE; + + if (is_destructor) + print_destructor (buffer, t); + else + dump_ada_decl_name (buffer, t, false); + + dump_ada_function_declaration + (buffer, t, is_method, is_constructor, is_destructor, spc); + in_function = prev_in_function; + + if (is_function) + { + pp_string (buffer, " return "); + + if (is_constructor) + { + dump_ada_decl_name (buffer, t, false); + } + else + { + dump_generic_ada_node + (buffer, TREE_TYPE (TREE_TYPE (t)), type, cpp_check, + spc, false, true); + } + } + + if (is_constructor && cpp_check && type + && AGGREGATE_TYPE_P (type) + && TYPE_METHODS (type)) + { + tree tmp = TYPE_METHODS (type); + + for (; tmp; tmp = TREE_CHAIN (tmp)) + if (cpp_check (tmp, IS_ABSTRACT)) + { + is_abstract_class = 1; + break; + } + } + + if (is_abstract || is_abstract_class) + pp_string (buffer, " is abstract"); + + pp_semicolon (buffer); + pp_string (buffer, " -- "); + dump_sloc (buffer, t); + + if (is_abstract) + return 1; + + newline_and_indent (buffer, spc); + + if (is_constructor) + { + pp_string (buffer, "pragma CPP_Constructor (New_"); + dump_ada_decl_name (buffer, t, false); + pp_string (buffer, ", \""); + pp_asm_name (buffer, t); + pp_string (buffer, "\");"); + } + else if (is_destructor) + { + pp_string (buffer, "pragma Import (CPP, "); + print_destructor (buffer, t); + pp_string (buffer, ", \""); + pp_asm_name (buffer, t); + pp_string (buffer, "\");"); + } + else + { + dump_ada_import (buffer, t); + } + + return 1; + } + else if (TREE_CODE (t) == TYPE_DECL && !DECL_ORIGINAL_TYPE (t)) + { + int is_interface = 0; + int is_abstract_record = 0; + + if (need_indent) + INDENT (spc); + + /* Anonymous structs/unions */ + dump_generic_ada_node + (buffer, TREE_TYPE (t), t, cpp_check, spc, false, true); + + if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (t)) == QUAL_UNION_TYPE) + { + pp_string (buffer, " (discr : unsigned := 0)"); + } + + pp_string (buffer, " is "); + + /* Check whether we have an Ada interface compatible class. */ + if (cpp_check && AGGREGATE_TYPE_P (TREE_TYPE (t)) + && TYPE_METHODS (TREE_TYPE (t))) + { + int num_fields = 0; + tree tmp = TYPE_FIELDS (TREE_TYPE (t)); + + /* Check that there are no fields other than the virtual table. */ + for (; tmp; tmp = TREE_CHAIN (tmp)) + { + if (TREE_CODE (tmp) == TYPE_DECL) + continue; + num_fields++; + } + + if (num_fields == 1) + is_interface = 1; + + /* Also check that there are only virtual methods. */ + for (tmp = TYPE_METHODS (TREE_TYPE (t)); tmp; tmp = TREE_CHAIN (tmp)) + { + if (cpp_check (tmp, IS_ABSTRACT)) + is_abstract_record = 1; + else + is_interface = 0; + } + } + + if (is_interface) + { + pp_string (buffer, "limited interface; -- "); + dump_sloc (buffer, t); + newline_and_indent (buffer, spc); + pp_string (buffer, "pragma Import (CPP, "); + dump_generic_ada_node + (buffer, TYPE_NAME (TREE_TYPE (t)), type, cpp_check, + spc, false, true); + pp_character (buffer, ')'); + + print_ada_methods (buffer, TREE_TYPE (t), cpp_check, spc); + } + else + { + if (is_abstract_record) + pp_string (buffer, "abstract "); + dump_generic_ada_node (buffer, t, t, cpp_check, spc, false, false); + } + } + else + { + if (need_indent) + INDENT (spc); + + if (TREE_CODE (t) == FIELD_DECL && DECL_NAME (t)) + check_name (buffer, t); + + /* Print variable/type's name. */ + dump_generic_ada_node (buffer, t, t, cpp_check, spc, false, true); + + if (TREE_CODE (t) == TYPE_DECL) + { + tree orig = DECL_ORIGINAL_TYPE (t); + int is_subtype = orig && TYPE_NAME (orig) && orig != TREE_TYPE (t); + + if (!is_subtype + && (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (t)) == QUAL_UNION_TYPE)) + pp_string (buffer, " (discr : unsigned := 0)"); + + pp_string (buffer, " is "); + + dump_generic_ada_node + (buffer, orig, t, cpp_check, spc, false, is_subtype); + } + else + { + if (spc == INDENT_INCR || TREE_STATIC (t)) + is_var = 1; + + pp_string (buffer, " : "); + + /* Print type declaration. */ + + if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE + && !TYPE_NAME (TREE_TYPE (t))) + { + dump_ada_double_name (buffer, type, t, "_union"); + } + else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))) + { + if (TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE) + pp_string (buffer, "aliased "); + + dump_generic_ada_node + (buffer, TREE_TYPE (t), t, cpp_check, spc, false, true); + } + else + { + if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE + && (TYPE_NAME (TREE_TYPE (t)) + || TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE)) + pp_string (buffer, "aliased "); + + dump_generic_ada_node + (buffer, TREE_TYPE (t), TREE_TYPE (t), cpp_check, + spc, false, true); + } + } + } + + if (is_class) + { + spc -= 3; + newline_and_indent (buffer, spc); + pp_string (buffer, "end;"); + newline_and_indent (buffer, spc); + pp_string (buffer, "use Class_"); + dump_generic_ada_node (buffer, t, type, 0, spc, false, true); + pp_semicolon (buffer); + pp_newline (buffer); + + /* All needed indentation/newline performed already, so return 0. */ + return 0; + } + else + { + pp_string (buffer, "; -- "); + dump_sloc (buffer, t); + } + + if (is_var) + { + newline_and_indent (buffer, spc); + dump_ada_import (buffer, t); + } + + return 1; +} + +/* Prints in BUFFER a structure NODE of type TYPE: name, fields, and methods + with Ada syntax. CPP_CHECK is used to perform C++ queries on nodes. SPC + is the indentation level. If DISPLAY_CONVENTION is true, also print the + pragma Convention for NODE. */ + +static void +print_ada_struct_decl (pretty_printer *buffer, tree node, tree type, + int (*cpp_check)(tree, cpp_operation), int spc, + bool display_convention) +{ + tree tmp; + int is_union = + TREE_CODE (node) == UNION_TYPE || TREE_CODE (node) == QUAL_UNION_TYPE; + char buf [16]; + int field_num = 0; + int field_spc = spc + INDENT_INCR; + int need_semicolon; + + bitfield_used = false; + + if (!TYPE_FIELDS (node)) + pp_string (buffer, "null record;"); + else + { + pp_string (buffer, "record"); + + /* Print the contents of the structure. */ + + if (is_union) + { + newline_and_indent (buffer, spc + INDENT_INCR); + pp_string (buffer, "case discr is"); + field_spc = spc + INDENT_INCR * 3; + } + + pp_newline (buffer); + + /* Print the non-static fields of the structure. */ + for (tmp = TYPE_FIELDS (node); tmp; tmp = TREE_CHAIN (tmp)) + { + /* Add parent field if needed. */ + if (!DECL_NAME (tmp)) + { + if (!is_tagged_type (TREE_TYPE (tmp))) + { + if (!TYPE_NAME (TREE_TYPE (tmp))) + print_ada_declaration + (buffer, tmp, type, cpp_check, field_spc); + else + { + INDENT (field_spc); + + if (field_num == 0) + pp_string (buffer, "parent : "); + else + { + sprintf (buf, "field_%d : ", field_num + 1); + pp_string (buffer, buf); + } + dump_ada_decl_name + (buffer, TYPE_NAME (TREE_TYPE (tmp)), false); + pp_semicolon (buffer); + } + pp_newline (buffer); + field_num++; + } + } + /* Avoid printing the structure recursively. */ + else if ((TREE_TYPE (tmp) != node + || (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE + && TREE_TYPE (TREE_TYPE (tmp)) != node)) + && TREE_CODE (tmp) != TYPE_DECL + && !TREE_STATIC (tmp)) + { + /* Skip internal virtual table field. */ + if (strncmp (IDENTIFIER_POINTER (DECL_NAME (tmp)), "_vptr", 5)) + { + if (is_union) + { + if (TREE_CHAIN (tmp) + && TREE_TYPE (TREE_CHAIN (tmp)) != node + && TREE_CODE (TREE_CHAIN (tmp)) != TYPE_DECL) + sprintf (buf, "when %d =>", field_num); + else + sprintf (buf, "when others =>"); + + INDENT (spc + INDENT_INCR * 2); + pp_string (buffer, buf); + pp_newline (buffer); + } + + if (print_ada_declaration (buffer, + tmp, type, cpp_check, field_spc)) + { + pp_newline (buffer); + field_num++; + } + } + } + } + + if (is_union) + { + INDENT (spc + INDENT_INCR); + pp_string (buffer, "end case;"); + pp_newline (buffer); + } + + if (field_num == 0) + { + INDENT (spc + INDENT_INCR); + pp_string (buffer, "null;"); + pp_newline (buffer); + } + + INDENT (spc); + pp_string (buffer, "end record;"); + } + + newline_and_indent (buffer, spc); + + if (!display_convention) + return; + + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))) + { + if (TYPE_METHODS (TREE_TYPE (type))) + pp_string (buffer, "pragma Import (CPP, "); + else + pp_string (buffer, "pragma Convention (C_Pass_By_Copy, "); + } + else + pp_string (buffer, "pragma Convention (C, "); + + package_prefix = false; + dump_generic_ada_node + (buffer, TREE_TYPE (type), type, cpp_check, spc, false, true); + package_prefix = true; + pp_character (buffer, ')'); + + if (is_union) + { + pp_semicolon (buffer); + newline_and_indent (buffer, spc); + pp_string (buffer, "pragma Unchecked_Union ("); + + dump_generic_ada_node + (buffer, TREE_TYPE (type), type, cpp_check, spc, false, true); + pp_character (buffer, ')'); + } + + if (bitfield_used) + { + pp_semicolon (buffer); + newline_and_indent (buffer, spc); + pp_string (buffer, "pragma Pack ("); + dump_generic_ada_node + (buffer, TREE_TYPE (type), type, cpp_check, spc, false, true); + pp_character (buffer, ')'); + bitfield_used = false; + } + + print_ada_methods (buffer, node, cpp_check, spc); + + /* Print the static fields of the structure, if any. */ + need_semicolon = TYPE_METHODS (node) == NULL_TREE; + for (tmp = TYPE_FIELDS (node); tmp; tmp = TREE_CHAIN (tmp)) + { + if (DECL_NAME (tmp) && TREE_STATIC (tmp)) + { + if (need_semicolon) + { + need_semicolon = false; + pp_semicolon (buffer); + } + pp_newline (buffer); + pp_newline (buffer); + print_ada_declaration (buffer, tmp, type, cpp_check, spc); + } + } +} + +/* Dump all the declarations in SOURCE_FILE to an Ada spec. + COLLECT_ALL_REFS is a front-end callback used to collect all relevant + nodes for SOURCE_FILE. CPP_CHECK is used to perform C++ queries on + nodes. */ + +static void +dump_ads (const char *source_file, + void (*collect_all_refs)(const char *), + int (*cpp_check)(tree, cpp_operation)) +{ + char *ads_name; + char *pkg_name; + char *s; + FILE *f; + + pkg_name = get_ada_package (source_file); + + /* Construct the the .ads filename and package name. */ + ads_name = xstrdup (pkg_name); + + for (s = ads_name; *s; s++) + *s = TOLOWER (*s); + + ads_name = reconcat (ads_name, ads_name, ".ads", NULL); + + /* Write out the .ads file. */ + f = fopen (ads_name, "w"); + if (f) + { + pretty_printer pp; + + pp_construct (&pp, NULL, 0); + pp_needs_newline (&pp) = true; + pp.buffer->stream = f; + + /* Dump all relevant macros. */ + dump_ada_macros (&pp, source_file); + + /* Reset the table of withs for this file. */ + reset_ada_withs (); + + (*collect_all_refs) (source_file); + + /* Dump all references. */ + dump_ada_nodes (&pp, source_file, cpp_check); + + /* Dump withs. */ + dump_ada_withs (f); + + fprintf (f, "\npackage %s is\n\n", pkg_name); + pp_write_text_to_stream (&pp); + /* ??? need to free pp */ + fprintf (f, "end %s;\n", pkg_name); + fclose (f); + } + + free (ads_name); + free (pkg_name); +} + +static const char **source_refs = NULL; +static int source_refs_used = 0; +static int source_refs_allocd = 0; + +/* Add an entry for FILENAME to the table SOURCE_REFS. */ + +void +collect_source_ref (const char *filename) +{ + int i; + + if (!filename) + return; + + if (source_refs_allocd == 0) + { + source_refs_allocd = 1024; + source_refs = XNEWVEC (const char *, source_refs_allocd); + } + + for (i = 0; i < source_refs_used; i++) + if (filename == source_refs [i]) + return; + + if (source_refs_used == source_refs_allocd) + { + source_refs_allocd *= 2; + source_refs = XRESIZEVEC (const char *, source_refs, source_refs_allocd); + } + + source_refs [source_refs_used++] = filename; +} + +/* Main entry point: dump all Ada specs corresponding to SOURCE_REFS + using callbacks COLLECT_ALL_REFS and CPP_CHECK. + COLLECT_ALL_REFS is a front-end callback used to collect all relevant + nodes for a given source file. + CPP_CHECK is used to perform C++ queries on nodes, or NULL for the C + front-end. */ + +void +dump_ada_specs (void (*collect_all_refs)(const char *), + int (*cpp_check)(tree, cpp_operation)) +{ + int i; + + /* Iterate over the list of files to dump specs for */ + for (i = 0; i < source_refs_used; i++) + dump_ads (source_refs [i], collect_all_refs, cpp_check); + + /* Free files table. */ + free (source_refs); +} diff --git a/gcc/c-family/c-ada-spec.h b/gcc/c-family/c-ada-spec.h new file mode 100644 index 0000000..8aed158 --- /dev/null +++ b/gcc/c-family/c-ada-spec.h @@ -0,0 +1,41 @@ +/* Interface for -fdump-ada-spec capability. + Copyright (C) 2010, 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 +. */ + +#ifndef C_ADA_SPEC_H +#define C_ADA_SPEC_H + +#include "pretty-print.h" + +/* In c-ada-spec.c */ + +typedef enum { + IS_ABSTRACT, + IS_CONSTRUCTOR, + IS_DESTRUCTOR, + IS_COPY_CONSTRUCTOR, + IS_TEMPLATE +} cpp_operation; + +extern location_t decl_sloc (const_tree, bool); +extern void collect_ada_nodes (tree, const char *); +extern void collect_source_ref (const char *); +extern void dump_ada_specs (void (*)(const char *), + int (*)(tree, cpp_operation)); + +#endif /* ! C_ADA_SPEC_H */ diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c new file mode 100644 index 0000000..1053c2b --- /dev/null +++ b/gcc/c-family/c-common.c @@ -0,0 +1,9466 @@ +/* Subroutines shared by all languages that are variants of C. + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + 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 +. */ + +/* FIXME: Still need to include rtl.h here (via expr.h) in a front-end file. + Pretend this is a back-end file. */ +#undef IN_GCC_FRONTEND + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "intl.h" +#include "tree.h" +#include "flags.h" +#include "output.h" +#include "c-pragma.h" +#include "ggc.h" +#include "c-common.h" +#include "tm_p.h" +#include "obstack.h" +#include "cpplib.h" +#include "target.h" +#include "langhooks.h" +#include "tree-inline.h" +#include "toplev.h" +#include "diagnostic.h" +#include "tree-iterator.h" +#include "hashtab.h" +#include "tree-mudflap.h" +#include "opts.h" +#include "cgraph.h" +#include "target-def.h" +#include "libfuncs.h" + +#include "expr.h" /* For vector_mode_valid_p */ + +cpp_reader *parse_in; /* Declared in c-pragma.h. */ + +/* The following symbols are subsumed in the c_global_trees array, and + listed here individually for documentation purposes. + + INTEGER_TYPE and REAL_TYPE nodes for the standard data types. + + tree short_integer_type_node; + tree long_integer_type_node; + tree long_long_integer_type_node; + tree int128_integer_type_node; + + tree short_unsigned_type_node; + tree long_unsigned_type_node; + tree long_long_unsigned_type_node; + tree int128_unsigned_type_node; + + tree truthvalue_type_node; + tree truthvalue_false_node; + tree truthvalue_true_node; + + tree ptrdiff_type_node; + + tree unsigned_char_type_node; + tree signed_char_type_node; + tree wchar_type_node; + + tree char16_type_node; + tree char32_type_node; + + tree float_type_node; + tree double_type_node; + tree long_double_type_node; + + tree complex_integer_type_node; + tree complex_float_type_node; + tree complex_double_type_node; + tree complex_long_double_type_node; + + tree dfloat32_type_node; + tree dfloat64_type_node; + tree_dfloat128_type_node; + + tree intQI_type_node; + tree intHI_type_node; + tree intSI_type_node; + tree intDI_type_node; + tree intTI_type_node; + + tree unsigned_intQI_type_node; + tree unsigned_intHI_type_node; + tree unsigned_intSI_type_node; + tree unsigned_intDI_type_node; + tree unsigned_intTI_type_node; + + tree widest_integer_literal_type_node; + tree widest_unsigned_literal_type_node; + + Nodes for types `void *' and `const void *'. + + tree ptr_type_node, const_ptr_type_node; + + Nodes for types `char *' and `const char *'. + + tree string_type_node, const_string_type_node; + + Type `char[SOMENUMBER]'. + Used when an array of char is needed and the size is irrelevant. + + tree char_array_type_node; + + Type `int[SOMENUMBER]' or something like it. + Used when an array of int needed and the size is irrelevant. + + tree int_array_type_node; + + Type `wchar_t[SOMENUMBER]' or something like it. + Used when a wide string literal is created. + + tree wchar_array_type_node; + + Type `char16_t[SOMENUMBER]' or something like it. + Used when a UTF-16 string literal is created. + + tree char16_array_type_node; + + Type `char32_t[SOMENUMBER]' or something like it. + Used when a UTF-32 string literal is created. + + tree char32_array_type_node; + + Type `int ()' -- used for implicit declaration of functions. + + tree default_function_type; + + A VOID_TYPE node, packaged in a TREE_LIST. + + tree void_list_node; + + The lazily created VAR_DECLs for __FUNCTION__, __PRETTY_FUNCTION__, + and __func__. (C doesn't generate __FUNCTION__ and__PRETTY_FUNCTION__ + VAR_DECLS, but C++ does.) + + tree function_name_decl_node; + tree pretty_function_name_decl_node; + tree c99_function_name_decl_node; + + Stack of nested function name VAR_DECLs. + + tree saved_function_name_decls; + +*/ + +tree c_global_trees[CTI_MAX]; + +/* Switches common to the C front ends. */ + +/* Nonzero if preprocessing only. */ + +int flag_preprocess_only; + +/* Nonzero means don't output line number information. */ + +char flag_no_line_commands; + +/* Nonzero causes -E output not to be done, but directives such as + #define that have side effects are still obeyed. */ + +char flag_no_output; + +/* Nonzero means dump macros in some fashion. */ + +char flag_dump_macros; + +/* Nonzero means pass #include lines through to the output. */ + +char flag_dump_includes; + +/* Nonzero means process PCH files while preprocessing. */ + +bool flag_pch_preprocess; + +/* The file name to which we should write a precompiled header, or + NULL if no header will be written in this compile. */ + +const char *pch_file; + +/* Nonzero if an ISO standard was selected. It rejects macros in the + user's namespace. */ +int flag_iso; + +/* Nonzero if -undef was given. It suppresses target built-in macros + and assertions. */ +int flag_undef; + +/* Nonzero means don't recognize the non-ANSI builtin functions. */ + +int flag_no_builtin; + +/* Nonzero means don't recognize the non-ANSI builtin functions. + -ansi sets this. */ + +int flag_no_nonansi_builtin; + +/* Nonzero means give `double' the same size as `float'. */ + +int flag_short_double; + +/* Nonzero means give `wchar_t' the same size as `short'. */ + +int flag_short_wchar; + +/* Nonzero means allow implicit conversions between vectors with + differing numbers of subparts and/or differing element types. */ +int flag_lax_vector_conversions; + +/* Nonzero means allow Microsoft extensions without warnings or errors. */ +int flag_ms_extensions; + +/* Nonzero means don't recognize the keyword `asm'. */ + +int flag_no_asm; + +/* Nonzero means to treat bitfields as signed unless they say `unsigned'. */ + +int flag_signed_bitfields = 1; + +/* Warn about #pragma directives that are not recognized. */ + +int warn_unknown_pragmas; /* Tri state variable. */ + +/* Warn about format/argument anomalies in calls to formatted I/O functions + (*printf, *scanf, strftime, strfmon, etc.). */ + +int warn_format; + +/* Warn about using __null (as NULL in C++) as sentinel. For code compiled + with GCC this doesn't matter as __null is guaranteed to have the right + size. */ + +int warn_strict_null_sentinel; + +/* Zero means that faster, ...NonNil variants of objc_msgSend... + calls will be used in ObjC; passing nil receivers to such calls + will most likely result in crashes. */ +int flag_nil_receivers = 1; + +/* Nonzero means that code generation will be altered to support + "zero-link" execution. This currently affects ObjC only, but may + affect other languages in the future. */ +int flag_zero_link = 0; + +/* Nonzero means emit an '__OBJC, __image_info' for the current translation + unit. It will inform the ObjC runtime that class definition(s) herein + contained are to replace one(s) previously loaded. */ +int flag_replace_objc_classes = 0; + +/* C/ObjC language option variables. */ + + +/* Nonzero means allow type mismatches in conditional expressions; + just make their values `void'. */ + +int flag_cond_mismatch; + +/* Nonzero means enable C89 Amendment 1 features. */ + +int flag_isoc94; + +/* Nonzero means use the ISO C99 (or C1X) dialect of C. */ + +int flag_isoc99; + +/* Nonzero means use the ISO C1X dialect of C. */ + +int flag_isoc1x; + +/* Nonzero means that we have builtin functions, and main is an int. */ + +int flag_hosted = 1; + + +/* ObjC language option variables. */ + + +/* Open and close the file for outputting class declarations, if + requested (ObjC). */ + +int flag_gen_declaration; + +/* Tells the compiler that this is a special run. Do not perform any + compiling, instead we are to test some platform dependent features + and output a C header file with appropriate definitions. */ + +int print_struct_values; + +/* Tells the compiler what is the constant string class for ObjC. */ + +const char *constant_string_class_name; + + +/* C++ language option variables. */ + + +/* Nonzero means don't recognize any extension keywords. */ + +int flag_no_gnu_keywords; + +/* Nonzero means do emit exported implementations of functions even if + they can be inlined. */ + +int flag_implement_inlines = 1; + +/* Nonzero means that implicit instantiations will be emitted if needed. */ + +int flag_implicit_templates = 1; + +/* Nonzero means that implicit instantiations of inline templates will be + emitted if needed, even if instantiations of non-inline templates + aren't. */ + +int flag_implicit_inline_templates = 1; + +/* Nonzero means generate separate instantiation control files and + juggle them at link time. */ + +int flag_use_repository; + +/* Nonzero if we want to issue diagnostics that the standard says are not + required. */ + +int flag_optional_diags = 1; + +/* Nonzero means we should attempt to elide constructors when possible. */ + +int flag_elide_constructors = 1; + +/* Nonzero means that member functions defined in class scope are + inline by default. */ + +int flag_default_inline = 1; + +/* Controls whether compiler generates 'type descriptor' that give + run-time type information. */ + +int flag_rtti = 1; + +/* Nonzero if we want to conserve space in the .o files. We do this + by putting uninitialized data and runtime initialized data into + .common instead of .data at the expense of not flagging multiple + definitions. */ + +int flag_conserve_space; + +/* Nonzero if we want to obey access control semantics. */ + +int flag_access_control = 1; + +/* Nonzero if we want to check the return value of new and avoid calling + constructors if it is a null pointer. */ + +int flag_check_new; + +/* The C++ dialect being used. C++98 is the default. */ + +enum cxx_dialect cxx_dialect = cxx98; + +/* Nonzero if we want the new ISO rules for pushing a new scope for `for' + initialization variables. + 0: Old rules, set by -fno-for-scope. + 2: New ISO rules, set by -ffor-scope. + 1: Try to implement new ISO rules, but with backup compatibility + (and warnings). This is the default, for now. */ + +int flag_new_for_scope = 1; + +/* Nonzero if we want to emit defined symbols with common-like linkage as + weak symbols where possible, in order to conform to C++ semantics. + Otherwise, emit them as local symbols. */ + +int flag_weak = 1; + +/* 0 means we want the preprocessor to not emit line directives for + the current working directory. 1 means we want it to do it. -1 + means we should decide depending on whether debugging information + is being emitted or not. */ + +int flag_working_directory = -1; + +/* Nonzero to use __cxa_atexit, rather than atexit, to register + destructors for local statics and global objects. '2' means it has been + set nonzero as a default, not by a command-line flag. */ + +int flag_use_cxa_atexit = DEFAULT_USE_CXA_ATEXIT; + +/* Nonzero to use __cxa_get_exception_ptr in C++ exception-handling + code. '2' means it has not been set explicitly on the command line. */ + +int flag_use_cxa_get_exception_ptr = 2; + +/* Nonzero means to implement standard semantics for exception + specifications, calling unexpected if an exception is thrown that + doesn't match the specification. Zero means to treat them as + assertions and optimize accordingly, but not check them. */ + +int flag_enforce_eh_specs = 1; + +/* Nonzero means to generate thread-safe code for initializing local + statics. */ + +int flag_threadsafe_statics = 1; + +/* Nonzero if we want to pretty-print template specializations as the + template signature followed by the arguments. */ + +int flag_pretty_templates = 1; + +/* Maximum template instantiation depth. This limit exists to limit the + time it takes to notice infinite template instantiations; the default + value of 1024 is likely to be in the next C++ standard. */ + +int max_tinst_depth = 1024; + + + +/* The elements of `ridpointers' are identifier nodes for the reserved + type names and storage classes. It is indexed by a RID_... value. */ +tree *ridpointers; + +tree (*make_fname_decl) (location_t, tree, int); + +/* Nonzero means don't warn about problems that occur when the code is + executed. */ +int c_inhibit_evaluation_warnings; + +/* Whether lexing has been completed, so subsequent preprocessor + errors should use the compiler's input_location. */ +bool done_lexing = false; + +/* Information about how a function name is generated. */ +struct fname_var_t +{ + tree *const decl; /* pointer to the VAR_DECL. */ + const unsigned rid; /* RID number for the identifier. */ + const int pretty; /* How pretty is it? */ +}; + +/* The three ways of getting then name of the current function. */ + +const struct fname_var_t fname_vars[] = +{ + /* C99 compliant __func__, must be first. */ + {&c99_function_name_decl_node, RID_C99_FUNCTION_NAME, 0}, + /* GCC __FUNCTION__ compliant. */ + {&function_name_decl_node, RID_FUNCTION_NAME, 0}, + /* GCC __PRETTY_FUNCTION__ compliant. */ + {&pretty_function_name_decl_node, RID_PRETTY_FUNCTION_NAME, 1}, + {NULL, 0, 0}, +}; + +static tree c_fully_fold_internal (tree expr, bool, bool *, bool *); +static tree check_case_value (tree); +static bool check_case_bounds (tree, tree, tree *, tree *); + +static tree handle_packed_attribute (tree *, tree, tree, int, bool *); +static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *); +static tree handle_common_attribute (tree *, tree, tree, int, bool *); +static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); +static tree handle_hot_attribute (tree *, tree, tree, int, bool *); +static tree handle_cold_attribute (tree *, tree, tree, int, bool *); +static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); +static tree handle_noclone_attribute (tree *, tree, tree, int, bool *); +static tree handle_always_inline_attribute (tree *, tree, tree, int, + bool *); +static tree handle_gnu_inline_attribute (tree *, tree, tree, int, bool *); +static tree handle_artificial_attribute (tree *, tree, tree, int, bool *); +static tree handle_flatten_attribute (tree *, tree, tree, int, bool *); +static tree handle_error_attribute (tree *, tree, tree, int, bool *); +static tree handle_used_attribute (tree *, tree, tree, int, bool *); +static tree handle_unused_attribute (tree *, tree, tree, int, bool *); +static tree handle_externally_visible_attribute (tree *, tree, tree, int, + bool *); +static tree handle_const_attribute (tree *, tree, tree, int, bool *); +static tree handle_transparent_union_attribute (tree *, tree, tree, + int, bool *); +static tree handle_constructor_attribute (tree *, tree, tree, int, bool *); +static tree handle_destructor_attribute (tree *, tree, tree, int, bool *); +static tree handle_mode_attribute (tree *, tree, tree, int, bool *); +static tree handle_section_attribute (tree *, tree, tree, int, bool *); +static tree handle_aligned_attribute (tree *, tree, tree, int, bool *); +static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ; +static tree handle_alias_attribute (tree *, tree, tree, int, bool *); +static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ; +static tree handle_visibility_attribute (tree *, tree, tree, int, + bool *); +static tree handle_tls_model_attribute (tree *, tree, tree, int, + bool *); +static tree handle_no_instrument_function_attribute (tree *, tree, + tree, int, bool *); +static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); +static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); +static tree handle_no_limit_stack_attribute (tree *, tree, tree, int, + bool *); +static tree handle_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_novops_attribute (tree *, tree, tree, int, bool *); +static tree handle_deprecated_attribute (tree *, tree, tree, int, + bool *); +static tree handle_vector_size_attribute (tree *, tree, tree, int, + bool *); +static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); +static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); +static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *); +static tree handle_warn_unused_result_attribute (tree *, tree, tree, int, + bool *); +static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); +static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); +static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *); +static tree handle_target_attribute (tree *, tree, tree, int, bool *); +static tree handle_optimize_attribute (tree *, tree, tree, int, bool *); +static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); + +static void check_function_nonnull (tree, int, tree *); +static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); +static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT); +static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *); +static int resort_field_decl_cmp (const void *, const void *); + +/* Reserved words. The third field is a mask: keywords are disabled + if they match the mask. + + Masks for languages: + C --std=c89: D_C99 | D_CXXONLY | D_OBJC | D_CXX_OBJC + C --std=c99: D_CXXONLY | D_OBJC + ObjC is like C except that D_OBJC and D_CXX_OBJC are not set + C++ --std=c98: D_CONLY | D_CXXOX | D_OBJC + C++ --std=c0x: D_CONLY | D_OBJC + ObjC++ is like C++ except that D_OBJC is not set + + If -fno-asm is used, D_ASM is added to the mask. If + -fno-gnu-keywords is used, D_EXT is added. If -fno-asm and C in + C89 mode, D_EXT89 is added for both -fno-asm and -fno-gnu-keywords. + In C with -Wc++-compat, we warn if D_CXXWARN is set. */ + +const struct c_common_resword c_common_reswords[] = +{ + { "_Bool", RID_BOOL, D_CONLY }, + { "_Complex", RID_COMPLEX, 0 }, + { "_Imaginary", RID_IMAGINARY, D_CONLY }, + { "_Decimal32", RID_DFLOAT32, D_CONLY | D_EXT }, + { "_Decimal64", RID_DFLOAT64, D_CONLY | D_EXT }, + { "_Decimal128", RID_DFLOAT128, D_CONLY | D_EXT }, + { "_Fract", RID_FRACT, D_CONLY | D_EXT }, + { "_Accum", RID_ACCUM, D_CONLY | D_EXT }, + { "_Sat", RID_SAT, D_CONLY | D_EXT }, + { "_Static_assert", RID_STATIC_ASSERT, D_CONLY }, + { "__FUNCTION__", RID_FUNCTION_NAME, 0 }, + { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 }, + { "__alignof", RID_ALIGNOF, 0 }, + { "__alignof__", RID_ALIGNOF, 0 }, + { "__asm", RID_ASM, 0 }, + { "__asm__", RID_ASM, 0 }, + { "__attribute", RID_ATTRIBUTE, 0 }, + { "__attribute__", RID_ATTRIBUTE, 0 }, + { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY }, + { "__builtin_offsetof", RID_OFFSETOF, 0 }, + { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY }, + { "__builtin_va_arg", RID_VA_ARG, 0 }, + { "__complex", RID_COMPLEX, 0 }, + { "__complex__", RID_COMPLEX, 0 }, + { "__const", RID_CONST, 0 }, + { "__const__", RID_CONST, 0 }, + { "__decltype", RID_DECLTYPE, D_CXXONLY }, + { "__extension__", RID_EXTENSION, 0 }, + { "__func__", RID_C99_FUNCTION_NAME, 0 }, + { "__has_nothrow_assign", RID_HAS_NOTHROW_ASSIGN, D_CXXONLY }, + { "__has_nothrow_constructor", RID_HAS_NOTHROW_CONSTRUCTOR, D_CXXONLY }, + { "__has_nothrow_copy", RID_HAS_NOTHROW_COPY, D_CXXONLY }, + { "__has_trivial_assign", RID_HAS_TRIVIAL_ASSIGN, D_CXXONLY }, + { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY }, + { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY }, + { "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY }, + { "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY }, + { "__int128", RID_INT128, 0 }, + { "__is_abstract", RID_IS_ABSTRACT, D_CXXONLY }, + { "__is_base_of", RID_IS_BASE_OF, D_CXXONLY }, + { "__is_class", RID_IS_CLASS, D_CXXONLY }, + { "__is_convertible_to", RID_IS_CONVERTIBLE_TO, D_CXXONLY }, + { "__is_empty", RID_IS_EMPTY, D_CXXONLY }, + { "__is_enum", RID_IS_ENUM, D_CXXONLY }, + { "__is_pod", RID_IS_POD, D_CXXONLY }, + { "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY }, + { "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY }, + { "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY }, + { "__is_union", RID_IS_UNION, D_CXXONLY }, + { "__imag", RID_IMAGPART, 0 }, + { "__imag__", RID_IMAGPART, 0 }, + { "__inline", RID_INLINE, 0 }, + { "__inline__", RID_INLINE, 0 }, + { "__label__", RID_LABEL, 0 }, + { "__null", RID_NULL, 0 }, + { "__real", RID_REALPART, 0 }, + { "__real__", RID_REALPART, 0 }, + { "__restrict", RID_RESTRICT, 0 }, + { "__restrict__", RID_RESTRICT, 0 }, + { "__signed", RID_SIGNED, 0 }, + { "__signed__", RID_SIGNED, 0 }, + { "__thread", RID_THREAD, 0 }, + { "__typeof", RID_TYPEOF, 0 }, + { "__typeof__", RID_TYPEOF, 0 }, + { "__volatile", RID_VOLATILE, 0 }, + { "__volatile__", RID_VOLATILE, 0 }, + { "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX0X | D_CXXWARN }, + { "asm", RID_ASM, D_ASM }, + { "auto", RID_AUTO, 0 }, + { "bool", RID_BOOL, D_CXXONLY | D_CXXWARN }, + { "break", RID_BREAK, 0 }, + { "case", RID_CASE, 0 }, + { "catch", RID_CATCH, D_CXX_OBJC | D_CXXWARN }, + { "char", RID_CHAR, 0 }, + { "char16_t", RID_CHAR16, D_CXXONLY | D_CXX0X | D_CXXWARN }, + { "char32_t", RID_CHAR32, D_CXXONLY | D_CXX0X | D_CXXWARN }, + { "class", RID_CLASS, D_CXX_OBJC | D_CXXWARN }, + { "const", RID_CONST, 0 }, + { "constexpr", RID_CONSTEXPR, D_CXXONLY | D_CXX0X | D_CXXWARN }, + { "const_cast", RID_CONSTCAST, D_CXXONLY | D_CXXWARN }, + { "continue", RID_CONTINUE, 0 }, + { "decltype", RID_DECLTYPE, D_CXXONLY | D_CXX0X | D_CXXWARN }, + { "default", RID_DEFAULT, 0 }, + { "delete", RID_DELETE, D_CXXONLY | D_CXXWARN }, + { "do", RID_DO, 0 }, + { "double", RID_DOUBLE, 0 }, + { "dynamic_cast", RID_DYNCAST, D_CXXONLY | D_CXXWARN }, + { "else", RID_ELSE, 0 }, + { "enum", RID_ENUM, 0 }, + { "explicit", RID_EXPLICIT, D_CXXONLY | D_CXXWARN }, + { "export", RID_EXPORT, D_CXXONLY | D_CXXWARN }, + { "extern", RID_EXTERN, 0 }, + { "false", RID_FALSE, D_CXXONLY | D_CXXWARN }, + { "float", RID_FLOAT, 0 }, + { "for", RID_FOR, 0 }, + { "friend", RID_FRIEND, D_CXXONLY | D_CXXWARN }, + { "goto", RID_GOTO, 0 }, + { "if", RID_IF, 0 }, + { "inline", RID_INLINE, D_EXT89 }, + { "int", RID_INT, 0 }, + { "long", RID_LONG, 0 }, + { "mutable", RID_MUTABLE, D_CXXONLY | D_CXXWARN }, + { "namespace", RID_NAMESPACE, D_CXXONLY | D_CXXWARN }, + { "new", RID_NEW, D_CXXONLY | D_CXXWARN }, + { "noexcept", RID_NOEXCEPT, D_CXXONLY | D_CXX0X | D_CXXWARN }, + { "nullptr", RID_NULLPTR, D_CXXONLY | D_CXX0X | D_CXXWARN }, + { "operator", RID_OPERATOR, D_CXXONLY | D_CXXWARN }, + { "private", RID_PRIVATE, D_CXX_OBJC | D_CXXWARN }, + { "protected", RID_PROTECTED, D_CXX_OBJC | D_CXXWARN }, + { "public", RID_PUBLIC, D_CXX_OBJC | D_CXXWARN }, + { "register", RID_REGISTER, 0 }, + { "reinterpret_cast", RID_REINTCAST, D_CXXONLY | D_CXXWARN }, + { "restrict", RID_RESTRICT, D_CONLY | D_C99 }, + { "return", RID_RETURN, 0 }, + { "short", RID_SHORT, 0 }, + { "signed", RID_SIGNED, 0 }, + { "sizeof", RID_SIZEOF, 0 }, + { "static", RID_STATIC, 0 }, + { "static_assert", RID_STATIC_ASSERT, D_CXXONLY | D_CXX0X | D_CXXWARN }, + { "static_cast", RID_STATCAST, D_CXXONLY | D_CXXWARN }, + { "struct", RID_STRUCT, 0 }, + { "switch", RID_SWITCH, 0 }, + { "template", RID_TEMPLATE, D_CXXONLY | D_CXXWARN }, + { "this", RID_THIS, D_CXXONLY | D_CXXWARN }, + { "throw", RID_THROW, D_CXX_OBJC | D_CXXWARN }, + { "true", RID_TRUE, D_CXXONLY | D_CXXWARN }, + { "try", RID_TRY, D_CXX_OBJC | D_CXXWARN }, + { "typedef", RID_TYPEDEF, 0 }, + { "typename", RID_TYPENAME, D_CXXONLY | D_CXXWARN }, + { "typeid", RID_TYPEID, D_CXXONLY | D_CXXWARN }, + { "typeof", RID_TYPEOF, D_ASM | D_EXT }, + { "union", RID_UNION, 0 }, + { "unsigned", RID_UNSIGNED, 0 }, + { "using", RID_USING, D_CXXONLY | D_CXXWARN }, + { "virtual", RID_VIRTUAL, D_CXXONLY | D_CXXWARN }, + { "void", RID_VOID, 0 }, + { "volatile", RID_VOLATILE, 0 }, + { "wchar_t", RID_WCHAR, D_CXXONLY }, + { "while", RID_WHILE, 0 }, + /* These Objective-C keywords are recognized only immediately after + an '@'. */ + { "compatibility_alias", RID_AT_ALIAS, D_OBJC }, + { "defs", RID_AT_DEFS, D_OBJC }, + { "encode", RID_AT_ENCODE, D_OBJC }, + { "end", RID_AT_END, D_OBJC }, + { "implementation", RID_AT_IMPLEMENTATION, D_OBJC }, + { "interface", RID_AT_INTERFACE, D_OBJC }, + { "protocol", RID_AT_PROTOCOL, D_OBJC }, + { "selector", RID_AT_SELECTOR, D_OBJC }, + { "finally", RID_AT_FINALLY, D_OBJC }, + { "synchronized", RID_AT_SYNCHRONIZED, D_OBJC }, + /* These are recognized only in protocol-qualifier context + (see above) */ + { "bycopy", RID_BYCOPY, D_OBJC }, + { "byref", RID_BYREF, D_OBJC }, + { "in", RID_IN, D_OBJC }, + { "inout", RID_INOUT, D_OBJC }, + { "oneway", RID_ONEWAY, D_OBJC }, + { "out", RID_OUT, D_OBJC }, +}; + +const unsigned int num_c_common_reswords = + sizeof c_common_reswords / sizeof (struct c_common_resword); + +/* Table of machine-independent attributes common to all C-like languages. */ +const struct attribute_spec c_common_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "packed", 0, 0, false, false, false, + handle_packed_attribute }, + { "nocommon", 0, 0, true, false, false, + handle_nocommon_attribute }, + { "common", 0, 0, true, false, false, + handle_common_attribute }, + /* FIXME: logically, noreturn attributes should be listed as + "false, true, true" and apply to function types. But implementing this + would require all the places in the compiler that use TREE_THIS_VOLATILE + on a decl to identify non-returning functions to be located and fixed + to check the function type instead. */ + { "noreturn", 0, 0, true, false, false, + handle_noreturn_attribute }, + { "volatile", 0, 0, true, false, false, + handle_noreturn_attribute }, + { "noinline", 0, 0, true, false, false, + handle_noinline_attribute }, + { "noclone", 0, 0, true, false, false, + handle_noclone_attribute }, + { "always_inline", 0, 0, true, false, false, + handle_always_inline_attribute }, + { "gnu_inline", 0, 0, true, false, false, + handle_gnu_inline_attribute }, + { "artificial", 0, 0, true, false, false, + handle_artificial_attribute }, + { "flatten", 0, 0, true, false, false, + handle_flatten_attribute }, + { "used", 0, 0, true, false, false, + handle_used_attribute }, + { "unused", 0, 0, false, false, false, + handle_unused_attribute }, + { "externally_visible", 0, 0, true, false, false, + handle_externally_visible_attribute }, + /* The same comments as for noreturn attributes apply to const ones. */ + { "const", 0, 0, true, false, false, + handle_const_attribute }, + { "transparent_union", 0, 0, false, false, false, + handle_transparent_union_attribute }, + { "constructor", 0, 1, true, false, false, + handle_constructor_attribute }, + { "destructor", 0, 1, true, false, false, + handle_destructor_attribute }, + { "mode", 1, 1, false, true, false, + handle_mode_attribute }, + { "section", 1, 1, true, false, false, + handle_section_attribute }, + { "aligned", 0, 1, false, false, false, + handle_aligned_attribute }, + { "weak", 0, 0, true, false, false, + handle_weak_attribute }, + { "alias", 1, 1, true, false, false, + handle_alias_attribute }, + { "weakref", 0, 1, true, false, false, + handle_weakref_attribute }, + { "no_instrument_function", 0, 0, true, false, false, + handle_no_instrument_function_attribute }, + { "malloc", 0, 0, true, false, false, + handle_malloc_attribute }, + { "returns_twice", 0, 0, true, false, false, + handle_returns_twice_attribute }, + { "no_stack_limit", 0, 0, true, false, false, + handle_no_limit_stack_attribute }, + { "pure", 0, 0, true, false, false, + handle_pure_attribute }, + /* For internal use (marking of builtins) only. The name contains space + to prevent its usage in source code. */ + { "no vops", 0, 0, true, false, false, + handle_novops_attribute }, + { "deprecated", 0, 1, false, false, false, + handle_deprecated_attribute }, + { "vector_size", 1, 1, false, true, false, + handle_vector_size_attribute }, + { "visibility", 1, 1, false, false, false, + handle_visibility_attribute }, + { "tls_model", 1, 1, true, false, false, + handle_tls_model_attribute }, + { "nonnull", 0, -1, false, true, true, + handle_nonnull_attribute }, + { "nothrow", 0, 0, true, false, false, + handle_nothrow_attribute }, + { "may_alias", 0, 0, false, true, false, NULL }, + { "cleanup", 1, 1, true, false, false, + handle_cleanup_attribute }, + { "warn_unused_result", 0, 0, false, true, true, + handle_warn_unused_result_attribute }, + { "sentinel", 0, 1, false, true, true, + handle_sentinel_attribute }, + /* For internal use (marking of builtins) only. The name contains space + to prevent its usage in source code. */ + { "type generic", 0, 0, false, true, true, + handle_type_generic_attribute }, + { "alloc_size", 1, 2, false, true, true, + handle_alloc_size_attribute }, + { "cold", 0, 0, true, false, false, + handle_cold_attribute }, + { "hot", 0, 0, true, false, false, + handle_hot_attribute }, + { "warning", 1, 1, true, false, false, + handle_error_attribute }, + { "error", 1, 1, true, false, false, + handle_error_attribute }, + { "target", 1, -1, true, false, false, + handle_target_attribute }, + { "optimize", 1, -1, true, false, false, + handle_optimize_attribute }, + /* For internal use (marking of builtins and runtime functions) only. + The name contains space to prevent its usage in source code. */ + { "fn spec", 1, 1, false, true, true, + handle_fnspec_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +/* Give the specifications for the format attributes, used by C and all + descendants. */ + +const struct attribute_spec c_common_format_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "format", 3, 3, false, true, true, + handle_format_attribute }, + { "format_arg", 1, 1, false, true, true, + handle_format_arg_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +/* Return identifier for address space AS. */ + +const char * +c_addr_space_name (addr_space_t as) +{ + int rid = RID_FIRST_ADDR_SPACE + as; + gcc_assert (ridpointers [rid]); + return IDENTIFIER_POINTER (ridpointers [rid]); +} + +/* Push current bindings for the function name VAR_DECLS. */ + +void +start_fname_decls (void) +{ + unsigned ix; + tree saved = NULL_TREE; + + for (ix = 0; fname_vars[ix].decl; ix++) + { + tree decl = *fname_vars[ix].decl; + + if (decl) + { + saved = tree_cons (decl, build_int_cst (NULL_TREE, ix), saved); + *fname_vars[ix].decl = NULL_TREE; + } + } + if (saved || saved_function_name_decls) + /* Normally they'll have been NULL, so only push if we've got a + stack, or they are non-NULL. */ + saved_function_name_decls = tree_cons (saved, NULL_TREE, + saved_function_name_decls); +} + +/* Finish up the current bindings, adding them into the current function's + statement tree. This must be done _before_ finish_stmt_tree is called. + If there is no current function, we must be at file scope and no statements + are involved. Pop the previous bindings. */ + +void +finish_fname_decls (void) +{ + unsigned ix; + tree stmts = NULL_TREE; + tree stack = saved_function_name_decls; + + for (; stack && TREE_VALUE (stack); stack = TREE_CHAIN (stack)) + append_to_statement_list (TREE_VALUE (stack), &stmts); + + if (stmts) + { + tree *bodyp = &DECL_SAVED_TREE (current_function_decl); + + if (TREE_CODE (*bodyp) == BIND_EXPR) + bodyp = &BIND_EXPR_BODY (*bodyp); + + append_to_statement_list_force (*bodyp, &stmts); + *bodyp = stmts; + } + + for (ix = 0; fname_vars[ix].decl; ix++) + *fname_vars[ix].decl = NULL_TREE; + + if (stack) + { + /* We had saved values, restore them. */ + tree saved; + + for (saved = TREE_PURPOSE (stack); saved; saved = TREE_CHAIN (saved)) + { + tree decl = TREE_PURPOSE (saved); + unsigned ix = TREE_INT_CST_LOW (TREE_VALUE (saved)); + + *fname_vars[ix].decl = decl; + } + stack = TREE_CHAIN (stack); + } + saved_function_name_decls = stack; +} + +/* Return the text name of the current function, suitably prettified + by PRETTY_P. Return string must be freed by caller. */ + +const char * +fname_as_string (int pretty_p) +{ + const char *name = "top level"; + char *namep; + int vrb = 2, len; + cpp_string cstr = { 0, 0 }, strname; + + if (!pretty_p) + { + name = ""; + vrb = 0; + } + + if (current_function_decl) + name = lang_hooks.decl_printable_name (current_function_decl, vrb); + + len = strlen (name) + 3; /* Two for '"'s. One for NULL. */ + + namep = XNEWVEC (char, len); + snprintf (namep, len, "\"%s\"", name); + strname.text = (unsigned char *) namep; + strname.len = len - 1; + + if (cpp_interpret_string (parse_in, &strname, 1, &cstr, CPP_STRING)) + { + XDELETEVEC (namep); + return (const char *) cstr.text; + } + + return namep; +} + +/* Return the VAR_DECL for a const char array naming the current + function. If the VAR_DECL has not yet been created, create it + now. RID indicates how it should be formatted and IDENTIFIER_NODE + ID is its name (unfortunately C and C++ hold the RID values of + keywords in different places, so we can't derive RID from ID in + this language independent code. LOC is the location of the + function. */ + +tree +fname_decl (location_t loc, unsigned int rid, tree id) +{ + unsigned ix; + tree decl = NULL_TREE; + + for (ix = 0; fname_vars[ix].decl; ix++) + if (fname_vars[ix].rid == rid) + break; + + decl = *fname_vars[ix].decl; + if (!decl) + { + /* If a tree is built here, it would normally have the lineno of + the current statement. Later this tree will be moved to the + beginning of the function and this line number will be wrong. + To avoid this problem set the lineno to 0 here; that prevents + it from appearing in the RTL. */ + tree stmts; + location_t saved_location = input_location; + input_location = UNKNOWN_LOCATION; + + stmts = push_stmt_list (); + decl = (*make_fname_decl) (loc, id, fname_vars[ix].pretty); + stmts = pop_stmt_list (stmts); + if (!IS_EMPTY_STMT (stmts)) + saved_function_name_decls + = tree_cons (decl, stmts, saved_function_name_decls); + *fname_vars[ix].decl = decl; + input_location = saved_location; + } + if (!ix && !current_function_decl) + pedwarn (loc, 0, "%qD is not defined outside of function scope", decl); + + return decl; +} + +/* Given a STRING_CST, give it a suitable array-of-chars data type. */ + +tree +fix_string_type (tree value) +{ + int length = TREE_STRING_LENGTH (value); + int nchars; + tree e_type, i_type, a_type; + + /* Compute the number of elements, for the array type. */ + if (TREE_TYPE (value) == char_array_type_node || !TREE_TYPE (value)) + { + nchars = length; + e_type = char_type_node; + } + else if (TREE_TYPE (value) == char16_array_type_node) + { + nchars = length / (TYPE_PRECISION (char16_type_node) / BITS_PER_UNIT); + e_type = char16_type_node; + } + else if (TREE_TYPE (value) == char32_array_type_node) + { + nchars = length / (TYPE_PRECISION (char32_type_node) / BITS_PER_UNIT); + e_type = char32_type_node; + } + else + { + nchars = length / (TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT); + e_type = wchar_type_node; + } + + /* C89 2.2.4.1, C99 5.2.4.1 (Translation limits). The analogous + limit in C++98 Annex B is very large (65536) and is not normative, + so we do not diagnose it (warn_overlength_strings is forced off + in c_common_post_options). */ + if (warn_overlength_strings) + { + const int nchars_max = flag_isoc99 ? 4095 : 509; + const int relevant_std = flag_isoc99 ? 99 : 90; + if (nchars - 1 > nchars_max) + /* Translators: The %d after 'ISO C' will be 90 or 99. Do not + separate the %d from the 'C'. 'ISO' should not be + translated, but it may be moved after 'C%d' in languages + where modifiers follow nouns. */ + pedwarn (input_location, OPT_Woverlength_strings, + "string length %qd is greater than the length %qd " + "ISO C%d compilers are required to support", + nchars - 1, nchars_max, relevant_std); + } + + /* Create the array type for the string constant. The ISO C++ + standard says that a string literal has type `const char[N]' or + `const wchar_t[N]'. We use the same logic when invoked as a C + front-end with -Wwrite-strings. + ??? We should change the type of an expression depending on the + state of a warning flag. We should just be warning -- see how + this is handled in the C++ front-end for the deprecated implicit + conversion from string literals to `char*' or `wchar_t*'. + + The C++ front end relies on TYPE_MAIN_VARIANT of a cv-qualified + array type being the unqualified version of that type. + Therefore, if we are constructing an array of const char, we must + construct the matching unqualified array type first. The C front + end does not require this, but it does no harm, so we do it + unconditionally. */ + i_type = build_index_type (build_int_cst (NULL_TREE, nchars - 1)); + a_type = build_array_type (e_type, i_type); + if (c_dialect_cxx() || warn_write_strings) + a_type = c_build_qualified_type (a_type, TYPE_QUAL_CONST); + + TREE_TYPE (value) = a_type; + TREE_CONSTANT (value) = 1; + TREE_READONLY (value) = 1; + TREE_STATIC (value) = 1; + return value; +} + +/* 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. */ + +tree +c_fully_fold (tree expr, bool in_init, bool *maybe_const) +{ + tree ret; + tree eptype = NULL_TREE; + bool dummy = true; + bool maybe_const_itself = true; + location_t loc = EXPR_LOCATION (expr); + + /* This function is not relevant to C++ because C++ folds while + parsing, and may need changes to be correct for C++ when C++ + stops folding while parsing. */ + if (c_dialect_cxx ()) + gcc_unreachable (); + + 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); + 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). */ + +static tree +c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, + bool *maybe_const_itself) +{ + 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 = TREE_NO_WARNING (expr); + int unused_p; + + /* This function is not relevant to C++ because C++ folds while + parsing, and may need changes to be correct for C++ when C++ + stops folding while parsing. */ + if (c_dialect_cxx ()) + gcc_unreachable (); + + /* Constants, declarations, statements, errors, SAVE_EXPRs 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 + || code == SAVE_EXPR) + return 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; + 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); + 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); + } + 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); + STRIP_TYPE_NOPS (op0); + op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, + maybe_const_itself); + STRIP_TYPE_NOPS (op1); + op1 = decl_constant_value_for_optimization (op1); + 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); + } + ret = fold (ret); + goto out; + + case COMPOUND_EXPR: + case MODIFY_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case POINTER_PLUS_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: + /* 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); + STRIP_TYPE_NOPS (op0); + if (code != MODIFY_EXPR + && code != PREDECREMENT_EXPR + && code != PREINCREMENT_EXPR + && code != POSTDECREMENT_EXPR + && code != POSTINCREMENT_EXPR) + op0 = decl_constant_value_for_optimization (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); + STRIP_TYPE_NOPS (op1); + op1 = decl_constant_value_for_optimization (op1); + 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) + && !TREE_OVERFLOW_P (op1)) + overflow_warning (EXPR_LOCATION (expr), ret); + goto out; + + case INDIRECT_REF: + case FIX_TRUNC_EXPR: + case FLOAT_EXPR: + CASE_CONVERT: + case NON_LVALUE_EXPR: + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case ADDR_EXPR: + case CONJ_EXPR: + case REALPART_EXPR: + case IMAGPART_EXPR: + /* Unary operations. */ + orig_op0 = op0 = TREE_OPERAND (expr, 0); + op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, + maybe_const_itself); + STRIP_TYPE_NOPS (op0); + if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR) + op0 = decl_constant_value_for_optimization (op0); + 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 + && TREE_CODE (ret) == INDIRECT_REF) + { + 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); + 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); + STRIP_TYPE_NOPS (op0); + + unused_p = (op0 == (code == TRUTH_ANDIF_EXPR + ? truthvalue_false_node + : truthvalue_true_node)); + c_inhibit_evaluation_warnings += unused_p; + op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self); + STRIP_TYPE_NOPS (op1); + c_inhibit_evaluation_warnings -= unused_p; + + 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); + + STRIP_TYPE_NOPS (op0); + c_inhibit_evaluation_warnings += (op0 == truthvalue_false_node); + op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self); + STRIP_TYPE_NOPS (op1); + c_inhibit_evaluation_warnings -= (op0 == truthvalue_false_node); + + c_inhibit_evaluation_warnings += (op0 == truthvalue_true_node); + op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self); + STRIP_TYPE_NOPS (op2); + c_inhibit_evaluation_warnings -= (op0 == truthvalue_true_node); + + 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 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 (); + + 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 |= TREE_NO_WARNING (ret); + STRIP_TYPE_NOPS (ret); + if (nowarning && !TREE_NO_WARNING (ret)) + { + if (!CAN_HAVE_LOCATION_P (ret)) + ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret); + TREE_NO_WARNING (ret) = 1; + } + if (ret != expr) + protected_set_expr_location (ret, loc); + return ret; +} + +/* If not optimizing, EXP is not a VAR_DECL, or EXP has array type, + return EXP. Otherwise, return either EXP or its known constant + value (if it has one), but return EXP if EXP has mode BLKmode. ??? + Is the BLKmode test appropriate? */ + +tree +decl_constant_value_for_optimization (tree exp) +{ + tree ret; + + /* This function is only used by C, for c_fully_fold and other + optimization, and may not be correct for C++. */ + if (c_dialect_cxx ()) + gcc_unreachable (); + + if (!optimize + || TREE_CODE (exp) != VAR_DECL + || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE + || DECL_MODE (exp) == BLKmode) + return exp; + + ret = decl_constant_value (exp); + /* 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 != exp && TREE_STATIC (exp)) + ret = unshare_expr (ret); + return ret; +} + +/* Print a warning if a constant expression had overflow in folding. + Invoke this function on every expression that the language + requires to be a constant expression. + Note the ANSI C standard says it is erroneous for a + constant expression to overflow. */ + +void +constant_expression_warning (tree value) +{ + if (warn_overflow && pedantic + && (TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST + || TREE_CODE (value) == FIXED_CST + || TREE_CODE (value) == VECTOR_CST + || TREE_CODE (value) == COMPLEX_CST) + && TREE_OVERFLOW (value)) + pedwarn (input_location, OPT_Woverflow, "overflow in constant expression"); +} + +/* The same as above but print an unconditional error. */ +void +constant_expression_error (tree value) +{ + if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST + || TREE_CODE (value) == FIXED_CST + || TREE_CODE (value) == VECTOR_CST + || TREE_CODE (value) == COMPLEX_CST) + && TREE_OVERFLOW (value)) + error ("overflow in constant expression"); +} + +/* Print a warning if an expression had overflow in folding and its + operands hadn't. + + Invoke this function on every expression that + (1) appears in the source code, and + (2) is a constant expression that overflowed, and + (3) is not already checked by convert_and_check; + however, do not invoke this function on operands of explicit casts + or when the expression is the result of an operator and any operand + already overflowed. */ + +void +overflow_warning (location_t loc, tree value) +{ + if (c_inhibit_evaluation_warnings != 0) + return; + + switch (TREE_CODE (value)) + { + case INTEGER_CST: + warning_at (loc, OPT_Woverflow, "integer overflow in expression"); + break; + + case REAL_CST: + warning_at (loc, OPT_Woverflow, + "floating point overflow in expression"); + break; + + case FIXED_CST: + warning_at (loc, OPT_Woverflow, "fixed-point overflow in expression"); + break; + + case VECTOR_CST: + warning_at (loc, OPT_Woverflow, "vector overflow in expression"); + break; + + case COMPLEX_CST: + if (TREE_CODE (TREE_REALPART (value)) == INTEGER_CST) + warning_at (loc, OPT_Woverflow, + "complex integer overflow in expression"); + else if (TREE_CODE (TREE_REALPART (value)) == REAL_CST) + warning_at (loc, OPT_Woverflow, + "complex floating point overflow in expression"); + break; + + default: + break; + } +} + +/* Warn about uses of logical || / && operator in a context where it + is likely that the bitwise equivalent was intended by the + programmer. We have seen an expression in which CODE is a binary + operator used to combine expressions OP_LEFT and OP_RIGHT, which before folding + had CODE_LEFT and CODE_RIGHT, into an expression of type TYPE. */ +void +warn_logical_operator (location_t location, enum tree_code code, tree type, + enum tree_code code_left, tree op_left, + enum tree_code ARG_UNUSED (code_right), tree op_right) +{ + int or_op = (code == TRUTH_ORIF_EXPR || code == TRUTH_OR_EXPR); + int in0_p, in1_p, in_p; + tree low0, low1, low, high0, high1, high, lhs, rhs, tem; + bool strict_overflow_p = false; + + if (code != TRUTH_ANDIF_EXPR + && code != TRUTH_AND_EXPR + && code != TRUTH_ORIF_EXPR + && code != TRUTH_OR_EXPR) + return; + + /* Warn if &&/|| are being used in a context where it is + likely that the bitwise equivalent was intended by the + programmer. That is, an expression such as op && MASK + where op should not be any boolean expression, nor a + constant, and mask seems to be a non-boolean integer constant. */ + if (!truth_value_p (code_left) + && INTEGRAL_TYPE_P (TREE_TYPE (op_left)) + && !CONSTANT_CLASS_P (op_left) + && !TREE_NO_WARNING (op_left) + && TREE_CODE (op_right) == INTEGER_CST + && !integer_zerop (op_right) + && !integer_onep (op_right)) + { + if (or_op) + warning_at (location, OPT_Wlogical_op, "logical %" + " applied to non-boolean constant"); + else + warning_at (location, OPT_Wlogical_op, "logical %" + " applied to non-boolean constant"); + TREE_NO_WARNING (op_left) = true; + return; + } + + /* We do not warn for constants because they are typical of macro + expansions that test for features. */ + if (CONSTANT_CLASS_P (op_left) || CONSTANT_CLASS_P (op_right)) + return; + + /* This warning only makes sense with logical operands. */ + if (!(truth_value_p (TREE_CODE (op_left)) + || INTEGRAL_TYPE_P (TREE_TYPE (op_left))) + || !(truth_value_p (TREE_CODE (op_right)) + || INTEGRAL_TYPE_P (TREE_TYPE (op_right)))) + return; + + lhs = make_range (op_left, &in0_p, &low0, &high0, &strict_overflow_p); + rhs = make_range (op_right, &in1_p, &low1, &high1, &strict_overflow_p); + + if (lhs && TREE_CODE (lhs) == C_MAYBE_CONST_EXPR) + lhs = C_MAYBE_CONST_EXPR_EXPR (lhs); + + if (rhs && TREE_CODE (rhs) == C_MAYBE_CONST_EXPR) + rhs = C_MAYBE_CONST_EXPR_EXPR (rhs); + + /* If this is an OR operation, invert both sides; we will invert + again at the end. */ + if (or_op) + in0_p = !in0_p, in1_p = !in1_p; + + /* If both expressions are the same, if we can merge the ranges, and we + can build the range test, return it or it inverted. */ + if (lhs && rhs && operand_equal_p (lhs, rhs, 0) + && merge_ranges (&in_p, &low, &high, in0_p, low0, high0, + in1_p, low1, high1) + && 0 != (tem = build_range_check (UNKNOWN_LOCATION, + type, lhs, in_p, low, high))) + { + if (TREE_CODE (tem) != INTEGER_CST) + return; + + if (or_op) + warning_at (location, OPT_Wlogical_op, + "logical % " + "of collectively exhaustive tests is always true"); + else + warning_at (location, OPT_Wlogical_op, + "logical % " + "of mutually exclusive tests is always false"); + } +} + + +/* Print a warning about casts that might indicate violation + of strict aliasing rules if -Wstrict-aliasing is used and + strict aliasing mode is in effect. OTYPE is the original + TREE_TYPE of EXPR, and TYPE the type we're casting to. */ + +bool +strict_aliasing_warning (tree otype, tree type, tree expr) +{ + /* Strip pointer conversion chains and get to the correct original type. */ + STRIP_NOPS (expr); + otype = TREE_TYPE (expr); + + if (!(flag_strict_aliasing + && POINTER_TYPE_P (type) + && POINTER_TYPE_P (otype) + && !VOID_TYPE_P (TREE_TYPE (type))) + /* If the type we are casting to is a ref-all pointer + dereferencing it is always valid. */ + || TYPE_REF_CAN_ALIAS_ALL (type)) + return false; + + if ((warn_strict_aliasing > 1) && TREE_CODE (expr) == ADDR_EXPR + && (DECL_P (TREE_OPERAND (expr, 0)) + || handled_component_p (TREE_OPERAND (expr, 0)))) + { + /* Casting the address of an object to non void pointer. Warn + if the cast breaks type based aliasing. */ + if (!COMPLETE_TYPE_P (TREE_TYPE (type)) && warn_strict_aliasing == 2) + { + warning (OPT_Wstrict_aliasing, "type-punning to incomplete type " + "might break strict-aliasing rules"); + return true; + } + else + { + /* warn_strict_aliasing >= 3. This includes the default (3). + Only warn if the cast is dereferenced immediately. */ + alias_set_type set1 = + get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0))); + alias_set_type set2 = get_alias_set (TREE_TYPE (type)); + + if (set1 != set2 && set2 != 0 + && (set1 == 0 || !alias_sets_conflict_p (set1, set2))) + { + warning (OPT_Wstrict_aliasing, "dereferencing type-punned " + "pointer will break strict-aliasing rules"); + return true; + } + else if (warn_strict_aliasing == 2 + && !alias_sets_must_conflict_p (set1, set2)) + { + warning (OPT_Wstrict_aliasing, "dereferencing type-punned " + "pointer might break strict-aliasing rules"); + return true; + } + } + } + else + if ((warn_strict_aliasing == 1) && !VOID_TYPE_P (TREE_TYPE (otype))) + { + /* At this level, warn for any conversions, even if an address is + not taken in the same statement. This will likely produce many + false positives, but could be useful to pinpoint problems that + are not revealed at higher levels. */ + alias_set_type set1 = get_alias_set (TREE_TYPE (otype)); + alias_set_type set2 = get_alias_set (TREE_TYPE (type)); + if (!COMPLETE_TYPE_P (type) + || !alias_sets_must_conflict_p (set1, set2)) + { + warning (OPT_Wstrict_aliasing, "dereferencing type-punned " + "pointer might break strict-aliasing rules"); + return true; + } + } + + return false; +} + +/* Warn for unlikely, improbable, or stupid DECL declarations + of `main'. */ + +void +check_main_parameter_types (tree decl) +{ + tree args; + int argct = 0; + + for (args = TYPE_ARG_TYPES (TREE_TYPE (decl)); args; + args = TREE_CHAIN (args)) + { + tree type = args ? TREE_VALUE (args) : 0; + + if (type == void_type_node || type == error_mark_node ) + break; + + ++argct; + switch (argct) + { + case 1: + if (TYPE_MAIN_VARIANT (type) != integer_type_node) + pedwarn (input_location, OPT_Wmain, "first argument of %q+D should be %", + decl); + break; + + case 2: + if (TREE_CODE (type) != POINTER_TYPE + || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) + != char_type_node)) + pedwarn (input_location, OPT_Wmain, "second argument of %q+D should be %", + decl); + break; + + case 3: + if (TREE_CODE (type) != POINTER_TYPE + || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) + != char_type_node)) + pedwarn (input_location, OPT_Wmain, "third argument of %q+D should probably be " + "%", decl); + break; + } + } + + /* It is intentional that this message does not mention the third + argument because it's only mentioned in an appendix of the + standard. */ + if (argct > 0 && (argct < 2 || argct > 3)) + pedwarn (input_location, OPT_Wmain, "%q+D takes only zero or two arguments", decl); +} + +/* True if pointers to distinct types T1 and T2 can be converted to + each other without an explicit cast. Only returns true for opaque + vector types. */ +bool +vector_targets_convertible_p (const_tree t1, const_tree t2) +{ + if (TREE_CODE (t1) == VECTOR_TYPE && TREE_CODE (t2) == VECTOR_TYPE + && (TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2)) + && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))) + return true; + + return false; +} + +/* True if vector types T1 and T2 can be converted to each other + without an explicit cast. If EMIT_LAX_NOTE is true, and T1 and T2 + can only be converted with -flax-vector-conversions yet that is not + in effect, emit a note telling the user about that option if such + a note has not previously been emitted. */ +bool +vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note) +{ + static bool emitted_lax_note = false; + bool convertible_lax; + + if ((TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2)) + && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))) + return true; + + convertible_lax = + (tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)) + && (TREE_CODE (TREE_TYPE (t1)) != REAL_TYPE || + TYPE_PRECISION (t1) == TYPE_PRECISION (t2)) + && (INTEGRAL_TYPE_P (TREE_TYPE (t1)) + == INTEGRAL_TYPE_P (TREE_TYPE (t2)))); + + if (!convertible_lax || flag_lax_vector_conversions) + return convertible_lax; + + if (TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2) + && lang_hooks.types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))) + return true; + + if (emit_lax_note && !emitted_lax_note) + { + emitted_lax_note = true; + inform (input_location, "use -flax-vector-conversions to permit " + "conversions between vectors with differing " + "element types or numbers of subparts"); + } + + return false; +} + +/* This is a helper function of build_binary_op. + + For certain operations if both args were extended from the same + smaller type, do the arithmetic in that type and then extend. + + BITWISE 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. +*/ +tree shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise) +{ + int unsigned0, unsigned1; + tree arg0, arg1; + int uns; + tree type; + + /* Cast OP0 and OP1 to RESULT_TYPE. Doing so prevents + excessive narrowing when we call get_narrower below. For + example, suppose that OP0 is of unsigned int extended + from signed char and that RESULT_TYPE is long long int. + If we explicitly cast OP0 to RESULT_TYPE, OP0 would look + like + + (long long int) (unsigned int) signed_char + + which get_narrower would narrow down to + + (unsigned int) signed char + + If we do not cast OP0 first, get_narrower would return + signed_char, which is inconsistent with the case of the + explicit cast. */ + op0 = convert (result_type, op0); + op1 = convert (result_type, op1); + + arg0 = get_narrower (op0, &unsigned0); + arg1 = get_narrower (op1, &unsigned1); + + /* UNS is 1 if the operation to be done is an unsigned one. */ + uns = TYPE_UNSIGNED (result_type); + + /* Handle the case that OP0 (or OP1) does not *contain* a conversion + but it *requires* conversion to FINAL_TYPE. */ + + if ((TYPE_PRECISION (TREE_TYPE (op0)) + == TYPE_PRECISION (TREE_TYPE (arg0))) + && TREE_TYPE (op0) != result_type) + unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0)); + if ((TYPE_PRECISION (TREE_TYPE (op1)) + == TYPE_PRECISION (TREE_TYPE (arg1))) + && TREE_TYPE (op1) != result_type) + unsigned1 = TYPE_UNSIGNED (TREE_TYPE (op1)); + + /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */ + + /* For bitwise operations, signedness of nominal type + does not matter. Consider only how operands were extended. */ + if (bitwise) + uns = unsigned0; + + /* Note that in all three cases below we refrain from optimizing + an unsigned operation on sign-extended args. + That would not be valid. */ + + /* Both args variable: if both extended in same way + from same width, do it in that width. + Do it unsigned if args were zero-extended. */ + if ((TYPE_PRECISION (TREE_TYPE (arg0)) + < TYPE_PRECISION (result_type)) + && (TYPE_PRECISION (TREE_TYPE (arg1)) + == TYPE_PRECISION (TREE_TYPE (arg0))) + && unsigned0 == unsigned1 + && (unsigned0 || !uns)) + return c_common_signed_or_unsigned_type + (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1))); + + else if (TREE_CODE (arg0) == INTEGER_CST + && (unsigned1 || !uns) + && (TYPE_PRECISION (TREE_TYPE (arg1)) + < TYPE_PRECISION (result_type)) + && (type + = c_common_signed_or_unsigned_type (unsigned1, + TREE_TYPE (arg1))) + && !POINTER_TYPE_P (type) + && int_fits_type_p (arg0, type)) + return type; + + else if (TREE_CODE (arg1) == INTEGER_CST + && (unsigned0 || !uns) + && (TYPE_PRECISION (TREE_TYPE (arg0)) + < TYPE_PRECISION (result_type)) + && (type + = c_common_signed_or_unsigned_type (unsigned0, + TREE_TYPE (arg0))) + && !POINTER_TYPE_P (type) + && int_fits_type_p (arg1, type)) + return type; + + return result_type; +} + +/* Warns if the conversion of EXPR to TYPE may alter a value. + This is a helper function for warnings_for_convert_and_check. */ + +static void +conversion_warning (tree type, tree expr) +{ + bool give_warning = false; + + int i; + const int expr_num_operands = TREE_OPERAND_LENGTH (expr); + tree expr_type = TREE_TYPE (expr); + + if (!warn_conversion && !warn_sign_conversion) + return; + + /* If any operand is artificial, then this expression was generated + by the compiler and we do not warn. */ + for (i = 0; i < expr_num_operands; i++) + { + tree op = TREE_OPERAND (expr, i); + if (op && DECL_P (op) && DECL_ARTIFICIAL (op)) + return; + } + + switch (TREE_CODE (expr)) + { + case EQ_EXPR: + case NE_EXPR: + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case TRUTH_NOT_EXPR: + /* Conversion from boolean to a signed:1 bit-field (which only + can hold the values 0 and -1) doesn't lose information - but + it does change the value. */ + if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type)) + warning (OPT_Wconversion, + "conversion to %qT from boolean expression", type); + return; + + case REAL_CST: + case INTEGER_CST: + + /* Warn for real constant that is not an exact integer converted + to integer type. */ + if (TREE_CODE (expr_type) == REAL_TYPE + && TREE_CODE (type) == INTEGER_TYPE) + { + if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type))) + give_warning = true; + } + /* Warn for an integer constant that does not fit into integer type. */ + else if (TREE_CODE (expr_type) == INTEGER_TYPE + && TREE_CODE (type) == INTEGER_TYPE + && !int_fits_type_p (expr, type)) + { + if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type) + && tree_int_cst_sgn (expr) < 0) + warning (OPT_Wsign_conversion, + "negative integer implicitly converted to unsigned type"); + else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type)) + warning (OPT_Wsign_conversion, "conversion of unsigned constant " + "value to negative integer"); + else + give_warning = true; + } + else if (TREE_CODE (type) == REAL_TYPE) + { + /* Warn for an integer constant that does not fit into real type. */ + if (TREE_CODE (expr_type) == INTEGER_TYPE) + { + REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr); + if (!exact_real_truncate (TYPE_MODE (type), &a)) + give_warning = true; + } + /* Warn for a real constant that does not fit into a smaller + real type. */ + else if (TREE_CODE (expr_type) == REAL_TYPE + && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) + { + REAL_VALUE_TYPE a = TREE_REAL_CST (expr); + if (!exact_real_truncate (TYPE_MODE (type), &a)) + give_warning = true; + } + } + + if (give_warning) + warning (OPT_Wconversion, + "conversion to %qT alters %qT constant value", + type, expr_type); + + return; + + case COND_EXPR: + { + /* In case of COND_EXPR, if both operands are constants or + COND_EXPR, then we do not care about the type of COND_EXPR, + only about the conversion of each operand. */ + tree op1 = TREE_OPERAND (expr, 1); + tree op2 = TREE_OPERAND (expr, 2); + + if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST + || TREE_CODE (op1) == COND_EXPR) + && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST + || TREE_CODE (op2) == COND_EXPR)) + { + conversion_warning (type, op1); + conversion_warning (type, op2); + return; + } + /* Fall through. */ + } + + default: /* 'expr' is not a constant. */ + + /* Warn for real types converted to integer types. */ + if (TREE_CODE (expr_type) == REAL_TYPE + && TREE_CODE (type) == INTEGER_TYPE) + give_warning = true; + + else if (TREE_CODE (expr_type) == INTEGER_TYPE + && TREE_CODE (type) == INTEGER_TYPE) + { + /* Don't warn about unsigned char y = 0xff, x = (int) y; */ + expr = get_unwidened (expr, 0); + expr_type = TREE_TYPE (expr); + + /* Don't warn for short y; short x = ((int)y & 0xff); */ + if (TREE_CODE (expr) == BIT_AND_EXPR + || TREE_CODE (expr) == BIT_IOR_EXPR + || TREE_CODE (expr) == BIT_XOR_EXPR) + { + /* If both args were extended from a shortest type, + use that type if that is safe. */ + expr_type = shorten_binary_op (expr_type, + TREE_OPERAND (expr, 0), + TREE_OPERAND (expr, 1), + /* bitwise */1); + + if (TREE_CODE (expr) == BIT_AND_EXPR) + { + tree op0 = TREE_OPERAND (expr, 0); + tree op1 = TREE_OPERAND (expr, 1); + bool unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0)); + bool unsigned1 = TYPE_UNSIGNED (TREE_TYPE (op1)); + + /* If one of the operands is a non-negative constant + that fits in the target type, then the type of the + other operand does not matter. */ + if ((TREE_CODE (op0) == INTEGER_CST + && int_fits_type_p (op0, c_common_signed_type (type)) + && int_fits_type_p (op0, c_common_unsigned_type (type))) + || (TREE_CODE (op1) == INTEGER_CST + && int_fits_type_p (op1, c_common_signed_type (type)) + && int_fits_type_p (op1, + c_common_unsigned_type (type)))) + return; + /* If constant is unsigned and fits in the target + type, then the result will also fit. */ + else if ((TREE_CODE (op0) == INTEGER_CST + && unsigned0 + && int_fits_type_p (op0, type)) + || (TREE_CODE (op1) == INTEGER_CST + && unsigned1 + && int_fits_type_p (op1, type))) + return; + } + } + /* Warn for integer types converted to smaller integer types. */ + if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) + give_warning = true; + + /* When they are the same width but different signedness, + then the value may change. */ + else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type) + && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type)) + /* Even when converted to a bigger type, if the type is + unsigned but expr is signed, then negative values + will be changed. */ + || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type))) + warning (OPT_Wsign_conversion, "conversion to %qT from %qT " + "may change the sign of the result", + type, expr_type); + } + + /* Warn for integer types converted to real types if and only if + all the range of values of the integer type cannot be + represented by the real type. */ + else if (TREE_CODE (expr_type) == INTEGER_TYPE + && TREE_CODE (type) == REAL_TYPE) + { + tree type_low_bound, type_high_bound; + REAL_VALUE_TYPE real_low_bound, real_high_bound; + + /* Don't warn about char y = 0xff; float x = (int) y; */ + expr = get_unwidened (expr, 0); + expr_type = TREE_TYPE (expr); + + type_low_bound = TYPE_MIN_VALUE (expr_type); + type_high_bound = TYPE_MAX_VALUE (expr_type); + real_low_bound = real_value_from_int_cst (0, type_low_bound); + real_high_bound = real_value_from_int_cst (0, type_high_bound); + + if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound) + || !exact_real_truncate (TYPE_MODE (type), &real_high_bound)) + give_warning = true; + } + + /* Warn for real types converted to smaller real types. */ + else if (TREE_CODE (expr_type) == REAL_TYPE + && TREE_CODE (type) == REAL_TYPE + && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) + give_warning = true; + + + if (give_warning) + warning (OPT_Wconversion, + "conversion to %qT from %qT may alter its value", + type, expr_type); + } +} + +/* Produce warnings after a conversion. RESULT is the result of + converting EXPR to TYPE. This is a helper function for + convert_and_check and cp_convert_and_check. */ + +void +warnings_for_convert_and_check (tree type, tree expr, tree result) +{ + if (TREE_CODE (expr) == INTEGER_CST + && (TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && !int_fits_type_p (expr, type)) + { + /* Do not diagnose overflow in a constant expression merely + because a conversion overflowed. */ + if (TREE_OVERFLOW (result)) + TREE_OVERFLOW (result) = TREE_OVERFLOW (expr); + + if (TYPE_UNSIGNED (type)) + { + /* This detects cases like converting -129 or 256 to + unsigned char. */ + if (!int_fits_type_p (expr, c_common_signed_type (type))) + warning (OPT_Woverflow, + "large integer implicitly truncated to unsigned type"); + else + conversion_warning (type, expr); + } + else if (!int_fits_type_p (expr, c_common_unsigned_type (type))) + warning (OPT_Woverflow, + "overflow in implicit constant conversion"); + /* No warning for converting 0x80000000 to int. */ + else if (pedantic + && (TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE + || TYPE_PRECISION (TREE_TYPE (expr)) + != TYPE_PRECISION (type))) + warning (OPT_Woverflow, + "overflow in implicit constant conversion"); + + else + conversion_warning (type, expr); + } + else if ((TREE_CODE (result) == INTEGER_CST + || TREE_CODE (result) == FIXED_CST) && TREE_OVERFLOW (result)) + warning (OPT_Woverflow, + "overflow in implicit constant conversion"); + else + conversion_warning (type, expr); +} + + +/* Convert EXPR to TYPE, warning about conversion problems with constants. + Invoke this function on every expression that is converted implicitly, + i.e. because of language rules and not because of an explicit cast. */ + +tree +convert_and_check (tree type, tree expr) +{ + tree result; + tree expr_for_warning; + + /* Convert from a value with possible excess precision rather than + via the semantic type, but do not warn about values not fitting + exactly in the semantic type. */ + if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) + { + tree orig_type = TREE_TYPE (expr); + expr = TREE_OPERAND (expr, 0); + expr_for_warning = convert (orig_type, expr); + if (orig_type == type) + return expr_for_warning; + } + else + expr_for_warning = expr; + + if (TREE_TYPE (expr) == type) + return expr; + + result = convert (type, expr); + + if (c_inhibit_evaluation_warnings == 0 + && !TREE_OVERFLOW_P (expr) + && result != error_mark_node) + warnings_for_convert_and_check (type, expr_for_warning, result); + + return result; +} + +/* A node in a list that describes references to variables (EXPR), which are + either read accesses if WRITER is zero, or write accesses, in which case + WRITER is the parent of EXPR. */ +struct tlist +{ + struct tlist *next; + tree expr, writer; +}; + +/* Used to implement a cache the results of a call to verify_tree. We only + use this for SAVE_EXPRs. */ +struct tlist_cache +{ + struct tlist_cache *next; + struct tlist *cache_before_sp; + struct tlist *cache_after_sp; + tree expr; +}; + +/* Obstack to use when allocating tlist structures, and corresponding + firstobj. */ +static struct obstack tlist_obstack; +static char *tlist_firstobj = 0; + +/* Keep track of the identifiers we've warned about, so we can avoid duplicate + warnings. */ +static struct tlist *warned_ids; +/* SAVE_EXPRs need special treatment. We process them only once and then + cache the results. */ +static struct tlist_cache *save_expr_cache; + +static void add_tlist (struct tlist **, struct tlist *, tree, int); +static void merge_tlist (struct tlist **, struct tlist *, int); +static void verify_tree (tree, struct tlist **, struct tlist **, tree); +static int warning_candidate_p (tree); +static bool candidate_equal_p (const_tree, const_tree); +static void warn_for_collisions (struct tlist *); +static void warn_for_collisions_1 (tree, tree, struct tlist *, int); +static struct tlist *new_tlist (struct tlist *, tree, tree); + +/* Create a new struct tlist and fill in its fields. */ +static struct tlist * +new_tlist (struct tlist *next, tree t, tree writer) +{ + struct tlist *l; + l = XOBNEW (&tlist_obstack, struct tlist); + l->next = next; + l->expr = t; + l->writer = writer; + return l; +} + +/* Add duplicates of the nodes found in ADD to the list *TO. If EXCLUDE_WRITER + is nonnull, we ignore any node we find which has a writer equal to it. */ + +static void +add_tlist (struct tlist **to, struct tlist *add, tree exclude_writer, int copy) +{ + while (add) + { + struct tlist *next = add->next; + if (!copy) + add->next = *to; + if (!exclude_writer || !candidate_equal_p (add->writer, exclude_writer)) + *to = copy ? new_tlist (*to, add->expr, add->writer) : add; + add = next; + } +} + +/* Merge the nodes of ADD into TO. This merging process is done so that for + each variable that already exists in TO, no new node is added; however if + there is a write access recorded in ADD, and an occurrence on TO is only + a read access, then the occurrence in TO will be modified to record the + write. */ + +static void +merge_tlist (struct tlist **to, struct tlist *add, int copy) +{ + struct tlist **end = to; + + while (*end) + end = &(*end)->next; + + while (add) + { + int found = 0; + struct tlist *tmp2; + struct tlist *next = add->next; + + for (tmp2 = *to; tmp2; tmp2 = tmp2->next) + if (candidate_equal_p (tmp2->expr, add->expr)) + { + found = 1; + if (!tmp2->writer) + tmp2->writer = add->writer; + } + if (!found) + { + *end = copy ? add : new_tlist (NULL, add->expr, add->writer); + end = &(*end)->next; + *end = 0; + } + add = next; + } +} + +/* WRITTEN is a variable, WRITER is its parent. Warn if any of the variable + references in list LIST conflict with it, excluding reads if ONLY writers + is nonzero. */ + +static void +warn_for_collisions_1 (tree written, tree writer, struct tlist *list, + int only_writes) +{ + struct tlist *tmp; + + /* Avoid duplicate warnings. */ + for (tmp = warned_ids; tmp; tmp = tmp->next) + if (candidate_equal_p (tmp->expr, written)) + return; + + while (list) + { + if (candidate_equal_p (list->expr, written) + && !candidate_equal_p (list->writer, writer) + && (!only_writes || list->writer)) + { + warned_ids = new_tlist (warned_ids, written, NULL_TREE); + warning_at (EXPR_HAS_LOCATION (writer) + ? EXPR_LOCATION (writer) : input_location, + OPT_Wsequence_point, "operation on %qE may be undefined", + list->expr); + } + list = list->next; + } +} + +/* Given a list LIST of references to variables, find whether any of these + can cause conflicts due to missing sequence points. */ + +static void +warn_for_collisions (struct tlist *list) +{ + struct tlist *tmp; + + for (tmp = list; tmp; tmp = tmp->next) + { + if (tmp->writer) + warn_for_collisions_1 (tmp->expr, tmp->writer, list, 0); + } +} + +/* Return nonzero if X is a tree that can be verified by the sequence point + warnings. */ +static int +warning_candidate_p (tree x) +{ + /* !VOID_TYPE_P (TREE_TYPE (x)) is workaround for cp/tree.c + (lvalue_p) crash on TRY/CATCH. */ + return !(DECL_P (x) && DECL_ARTIFICIAL (x)) + && TREE_TYPE (x) && !VOID_TYPE_P (TREE_TYPE (x)) && lvalue_p (x); +} + +/* Return nonzero if X and Y appear to be the same candidate (or NULL) */ +static bool +candidate_equal_p (const_tree x, const_tree y) +{ + return (x == y) || (x && y && operand_equal_p (x, y, 0)); +} + +/* Walk the tree X, and record accesses to variables. If X is written by the + parent tree, WRITER is the parent. + We store accesses in one of the two lists: PBEFORE_SP, and PNO_SP. If this + expression or its only operand forces a sequence point, then everything up + to the sequence point is stored in PBEFORE_SP. Everything else gets stored + in PNO_SP. + Once we return, we will have emitted warnings if any subexpression before + such a sequence point could be undefined. On a higher level, however, the + sequence point may not be relevant, and we'll merge the two lists. + + Example: (b++, a) + b; + The call that processes the COMPOUND_EXPR will store the increment of B + in PBEFORE_SP, and the use of A in PNO_SP. The higher-level call that + processes the PLUS_EXPR will need to merge the two lists so that + eventually, all accesses end up on the same list (and we'll warn about the + unordered subexpressions b++ and b. + + A note on merging. If we modify the former example so that our expression + becomes + (b++, b) + a + care must be taken not simply to add all three expressions into the final + PNO_SP list. The function merge_tlist takes care of that by merging the + before-SP list of the COMPOUND_EXPR into its after-SP list in a special + way, so that no more than one access to B is recorded. */ + +static void +verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp, + tree writer) +{ + struct tlist *tmp_before, *tmp_nosp, *tmp_list2, *tmp_list3; + enum tree_code code; + enum tree_code_class cl; + + /* X may be NULL if it is the operand of an empty statement expression + ({ }). */ + if (x == NULL) + return; + + restart: + code = TREE_CODE (x); + cl = TREE_CODE_CLASS (code); + + if (warning_candidate_p (x)) + *pno_sp = new_tlist (*pno_sp, x, writer); + + switch (code) + { + case CONSTRUCTOR: + return; + + case COMPOUND_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + tmp_before = tmp_nosp = tmp_list3 = 0; + verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE); + warn_for_collisions (tmp_nosp); + merge_tlist (pbefore_sp, tmp_before, 0); + merge_tlist (pbefore_sp, tmp_nosp, 0); + verify_tree (TREE_OPERAND (x, 1), &tmp_list3, pno_sp, NULL_TREE); + merge_tlist (pbefore_sp, tmp_list3, 0); + return; + + case COND_EXPR: + tmp_before = tmp_list2 = 0; + verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_list2, NULL_TREE); + warn_for_collisions (tmp_list2); + merge_tlist (pbefore_sp, tmp_before, 0); + merge_tlist (pbefore_sp, tmp_list2, 1); + + tmp_list3 = tmp_nosp = 0; + verify_tree (TREE_OPERAND (x, 1), &tmp_list3, &tmp_nosp, NULL_TREE); + warn_for_collisions (tmp_nosp); + merge_tlist (pbefore_sp, tmp_list3, 0); + + tmp_list3 = tmp_list2 = 0; + verify_tree (TREE_OPERAND (x, 2), &tmp_list3, &tmp_list2, NULL_TREE); + warn_for_collisions (tmp_list2); + merge_tlist (pbefore_sp, tmp_list3, 0); + /* Rather than add both tmp_nosp and tmp_list2, we have to merge the + two first, to avoid warning for (a ? b++ : b++). */ + merge_tlist (&tmp_nosp, tmp_list2, 0); + add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0); + return; + + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + verify_tree (TREE_OPERAND (x, 0), pno_sp, pno_sp, x); + return; + + case MODIFY_EXPR: + tmp_before = tmp_nosp = tmp_list3 = 0; + verify_tree (TREE_OPERAND (x, 1), &tmp_before, &tmp_nosp, NULL_TREE); + verify_tree (TREE_OPERAND (x, 0), &tmp_list3, &tmp_list3, x); + /* Expressions inside the LHS are not ordered wrt. the sequence points + in the RHS. Example: + *a = (a++, 2) + Despite the fact that the modification of "a" is in the before_sp + list (tmp_before), it conflicts with the use of "a" in the LHS. + We can handle this by adding the contents of tmp_list3 + to those of tmp_before, and redoing the collision warnings for that + list. */ + add_tlist (&tmp_before, tmp_list3, x, 1); + warn_for_collisions (tmp_before); + /* Exclude the LHS itself here; we first have to merge it into the + tmp_nosp list. This is done to avoid warning for "a = a"; if we + didn't exclude the LHS, we'd get it twice, once as a read and once + as a write. */ + add_tlist (pno_sp, tmp_list3, x, 0); + warn_for_collisions_1 (TREE_OPERAND (x, 0), x, tmp_nosp, 1); + + merge_tlist (pbefore_sp, tmp_before, 0); + if (warning_candidate_p (TREE_OPERAND (x, 0))) + merge_tlist (&tmp_nosp, new_tlist (NULL, TREE_OPERAND (x, 0), x), 0); + add_tlist (pno_sp, tmp_nosp, NULL_TREE, 1); + return; + + case CALL_EXPR: + /* We need to warn about conflicts among arguments and conflicts between + args and the function address. Side effects of the function address, + however, are not ordered by the sequence point of the call. */ + { + call_expr_arg_iterator iter; + tree arg; + tmp_before = tmp_nosp = 0; + verify_tree (CALL_EXPR_FN (x), &tmp_before, &tmp_nosp, NULL_TREE); + FOR_EACH_CALL_EXPR_ARG (arg, iter, x) + { + tmp_list2 = tmp_list3 = 0; + verify_tree (arg, &tmp_list2, &tmp_list3, NULL_TREE); + merge_tlist (&tmp_list3, tmp_list2, 0); + add_tlist (&tmp_before, tmp_list3, NULL_TREE, 0); + } + add_tlist (&tmp_before, tmp_nosp, NULL_TREE, 0); + warn_for_collisions (tmp_before); + add_tlist (pbefore_sp, tmp_before, NULL_TREE, 0); + return; + } + + case TREE_LIST: + /* Scan all the list, e.g. indices of multi dimensional array. */ + while (x) + { + tmp_before = tmp_nosp = 0; + verify_tree (TREE_VALUE (x), &tmp_before, &tmp_nosp, NULL_TREE); + merge_tlist (&tmp_nosp, tmp_before, 0); + add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0); + x = TREE_CHAIN (x); + } + return; + + case SAVE_EXPR: + { + struct tlist_cache *t; + for (t = save_expr_cache; t; t = t->next) + if (candidate_equal_p (t->expr, x)) + break; + + if (!t) + { + t = XOBNEW (&tlist_obstack, struct tlist_cache); + t->next = save_expr_cache; + t->expr = x; + save_expr_cache = t; + + tmp_before = tmp_nosp = 0; + verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE); + warn_for_collisions (tmp_nosp); + + tmp_list3 = 0; + while (tmp_nosp) + { + struct tlist *t = tmp_nosp; + tmp_nosp = t->next; + merge_tlist (&tmp_list3, t, 0); + } + t->cache_before_sp = tmp_before; + t->cache_after_sp = tmp_list3; + } + merge_tlist (pbefore_sp, t->cache_before_sp, 1); + add_tlist (pno_sp, t->cache_after_sp, NULL_TREE, 1); + return; + } + + case ADDR_EXPR: + x = TREE_OPERAND (x, 0); + if (DECL_P (x)) + return; + writer = 0; + goto restart; + + default: + /* For other expressions, simply recurse on their operands. + Manual tail recursion for unary expressions. + Other non-expressions need not be processed. */ + if (cl == tcc_unary) + { + x = TREE_OPERAND (x, 0); + writer = 0; + goto restart; + } + else if (IS_EXPR_CODE_CLASS (cl)) + { + int lp; + int max = TREE_OPERAND_LENGTH (x); + for (lp = 0; lp < max; lp++) + { + tmp_before = tmp_nosp = 0; + verify_tree (TREE_OPERAND (x, lp), &tmp_before, &tmp_nosp, 0); + merge_tlist (&tmp_nosp, tmp_before, 0); + add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0); + } + } + return; + } +} + +/* Try to warn for undefined behavior in EXPR due to missing sequence + points. */ + +DEBUG_FUNCTION void +verify_sequence_points (tree expr) +{ + struct tlist *before_sp = 0, *after_sp = 0; + + warned_ids = 0; + save_expr_cache = 0; + if (tlist_firstobj == 0) + { + gcc_obstack_init (&tlist_obstack); + tlist_firstobj = (char *) obstack_alloc (&tlist_obstack, 0); + } + + verify_tree (expr, &before_sp, &after_sp, 0); + warn_for_collisions (after_sp); + obstack_free (&tlist_obstack, tlist_firstobj); +} + +/* Validate the expression after `case' and apply default promotions. */ + +static tree +check_case_value (tree value) +{ + if (value == NULL_TREE) + return value; + + /* ??? Can we ever get nops here for a valid case value? We + shouldn't for C. */ + STRIP_TYPE_NOPS (value); + /* In C++, the following is allowed: + + const int i = 3; + switch (...) { case i: ... } + + So, we try to reduce the VALUE to a constant that way. */ + if (c_dialect_cxx ()) + { + value = decl_constant_value (value); + STRIP_TYPE_NOPS (value); + value = fold (value); + } + + if (TREE_CODE (value) == INTEGER_CST) + /* Promote char or short to int. */ + value = perform_integral_promotions (value); + else if (value != error_mark_node) + { + error ("case label does not reduce to an integer constant"); + value = error_mark_node; + } + + constant_expression_warning (value); + + return value; +} + +/* See if the case values LOW and HIGH are in the range of the original + type (i.e. before the default conversion to int) of the switch testing + expression. + TYPE is the promoted type of the testing expression, and ORIG_TYPE is + the type before promoting it. CASE_LOW_P is a pointer to the lower + bound of the case label, and CASE_HIGH_P is the upper bound or NULL + if the case is not a case range. + The caller has to make sure that we are not called with NULL for + CASE_LOW_P (i.e. the default case). + Returns true if the case label is in range of ORIG_TYPE (saturated or + untouched) or false if the label is out of range. */ + +static bool +check_case_bounds (tree type, tree orig_type, + tree *case_low_p, tree *case_high_p) +{ + tree min_value, max_value; + tree case_low = *case_low_p; + tree case_high = case_high_p ? *case_high_p : case_low; + + /* If there was a problem with the original type, do nothing. */ + if (orig_type == error_mark_node) + return true; + + min_value = TYPE_MIN_VALUE (orig_type); + max_value = TYPE_MAX_VALUE (orig_type); + + /* Case label is less than minimum for type. */ + if (tree_int_cst_compare (case_low, min_value) < 0 + && tree_int_cst_compare (case_high, min_value) < 0) + { + warning (0, "case label value is less than minimum value for type"); + return false; + } + + /* Case value is greater than maximum for type. */ + if (tree_int_cst_compare (case_low, max_value) > 0 + && tree_int_cst_compare (case_high, max_value) > 0) + { + warning (0, "case label value exceeds maximum value for type"); + return false; + } + + /* Saturate lower case label value to minimum. */ + if (tree_int_cst_compare (case_high, min_value) >= 0 + && tree_int_cst_compare (case_low, min_value) < 0) + { + warning (0, "lower value in case label range" + " less than minimum value for type"); + case_low = min_value; + } + + /* Saturate upper case label value to maximum. */ + if (tree_int_cst_compare (case_low, max_value) <= 0 + && tree_int_cst_compare (case_high, max_value) > 0) + { + warning (0, "upper value in case label range" + " exceeds maximum value for type"); + case_high = max_value; + } + + if (*case_low_p != case_low) + *case_low_p = convert (type, case_low); + if (case_high_p && *case_high_p != case_high) + *case_high_p = convert (type, case_high); + + return true; +} + +/* Return an integer type with BITS bits of precision, + that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ + +tree +c_common_type_for_size (unsigned int bits, int unsignedp) +{ + if (bits == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (bits == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + + if (bits == TYPE_PRECISION (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + + if (bits == TYPE_PRECISION (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (bits == TYPE_PRECISION (long_long_integer_type_node)) + return (unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node); + + if (int128_integer_type_node + && bits == TYPE_PRECISION (int128_integer_type_node)) + return (unsignedp ? int128_unsigned_type_node + : int128_integer_type_node); + + if (bits == TYPE_PRECISION (widest_integer_literal_type_node)) + return (unsignedp ? widest_unsigned_literal_type_node + : widest_integer_literal_type_node); + + if (bits <= TYPE_PRECISION (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + if (bits <= TYPE_PRECISION (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + + if (bits <= TYPE_PRECISION (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + + if (bits <= TYPE_PRECISION (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + + return 0; +} + +/* Return a fixed-point type that has at least IBIT ibits and FBIT fbits + that is unsigned if UNSIGNEDP is nonzero, otherwise signed; + and saturating if SATP is nonzero, otherwise not saturating. */ + +tree +c_common_fixed_point_type_for_size (unsigned int ibit, unsigned int fbit, + int unsignedp, int satp) +{ + enum machine_mode mode; + if (ibit == 0) + mode = unsignedp ? UQQmode : QQmode; + else + mode = unsignedp ? UHAmode : HAmode; + + for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) + if (GET_MODE_IBIT (mode) >= ibit && GET_MODE_FBIT (mode) >= fbit) + break; + + if (mode == VOIDmode || !targetm.scalar_mode_supported_p (mode)) + { + sorry ("GCC cannot support operators with integer types and " + "fixed-point types that have too many integral and " + "fractional bits together"); + return 0; + } + + return c_common_type_for_mode (mode, satp); +} + +/* Used for communication between c_common_type_for_mode and + c_register_builtin_type. */ +static GTY(()) tree registered_builtin_types; + +/* Return a data type that has machine mode MODE. + If the mode is an integer, + then UNSIGNEDP selects between signed and unsigned types. + If the mode is a fixed-point mode, + then UNSIGNEDP selects between saturating and nonsaturating types. */ + +tree +c_common_type_for_mode (enum machine_mode mode, int unsignedp) +{ + tree t; + + if (mode == TYPE_MODE (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (mode == TYPE_MODE (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + + if (mode == TYPE_MODE (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + + if (mode == TYPE_MODE (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (mode == TYPE_MODE (long_long_integer_type_node)) + return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node; + + if (int128_integer_type_node + && mode == TYPE_MODE (int128_integer_type_node)) + return unsignedp ? int128_unsigned_type_node : int128_integer_type_node; + + if (mode == TYPE_MODE (widest_integer_literal_type_node)) + return unsignedp ? widest_unsigned_literal_type_node + : widest_integer_literal_type_node; + + if (mode == QImode) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + if (mode == HImode) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + + if (mode == SImode) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + + if (mode == DImode) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + +#if HOST_BITS_PER_WIDE_INT >= 64 + if (mode == TYPE_MODE (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + + if (mode == TYPE_MODE (float_type_node)) + return float_type_node; + + if (mode == TYPE_MODE (double_type_node)) + return double_type_node; + + if (mode == TYPE_MODE (long_double_type_node)) + return long_double_type_node; + + if (mode == TYPE_MODE (void_type_node)) + return void_type_node; + + if (mode == TYPE_MODE (build_pointer_type (char_type_node))) + return (unsignedp + ? make_unsigned_type (GET_MODE_PRECISION (mode)) + : make_signed_type (GET_MODE_PRECISION (mode))); + + if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) + return (unsignedp + ? make_unsigned_type (GET_MODE_PRECISION (mode)) + : make_signed_type (GET_MODE_PRECISION (mode))); + + if (COMPLEX_MODE_P (mode)) + { + enum machine_mode inner_mode; + tree inner_type; + + if (mode == TYPE_MODE (complex_float_type_node)) + return complex_float_type_node; + if (mode == TYPE_MODE (complex_double_type_node)) + return complex_double_type_node; + if (mode == TYPE_MODE (complex_long_double_type_node)) + return complex_long_double_type_node; + + if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp) + return complex_integer_type_node; + + inner_mode = GET_MODE_INNER (mode); + inner_type = c_common_type_for_mode (inner_mode, unsignedp); + if (inner_type != NULL_TREE) + return build_complex_type (inner_type); + } + else if (VECTOR_MODE_P (mode)) + { + enum machine_mode inner_mode = GET_MODE_INNER (mode); + tree inner_type = c_common_type_for_mode (inner_mode, unsignedp); + if (inner_type != NULL_TREE) + return build_vector_type_for_mode (inner_type, mode); + } + + if (mode == TYPE_MODE (dfloat32_type_node)) + return dfloat32_type_node; + if (mode == TYPE_MODE (dfloat64_type_node)) + return dfloat64_type_node; + if (mode == TYPE_MODE (dfloat128_type_node)) + return dfloat128_type_node; + + if (ALL_SCALAR_FIXED_POINT_MODE_P (mode)) + { + if (mode == TYPE_MODE (short_fract_type_node)) + return unsignedp ? sat_short_fract_type_node : short_fract_type_node; + if (mode == TYPE_MODE (fract_type_node)) + return unsignedp ? sat_fract_type_node : fract_type_node; + if (mode == TYPE_MODE (long_fract_type_node)) + return unsignedp ? sat_long_fract_type_node : long_fract_type_node; + if (mode == TYPE_MODE (long_long_fract_type_node)) + return unsignedp ? sat_long_long_fract_type_node + : long_long_fract_type_node; + + if (mode == TYPE_MODE (unsigned_short_fract_type_node)) + return unsignedp ? sat_unsigned_short_fract_type_node + : unsigned_short_fract_type_node; + if (mode == TYPE_MODE (unsigned_fract_type_node)) + return unsignedp ? sat_unsigned_fract_type_node + : unsigned_fract_type_node; + if (mode == TYPE_MODE (unsigned_long_fract_type_node)) + return unsignedp ? sat_unsigned_long_fract_type_node + : unsigned_long_fract_type_node; + if (mode == TYPE_MODE (unsigned_long_long_fract_type_node)) + return unsignedp ? sat_unsigned_long_long_fract_type_node + : unsigned_long_long_fract_type_node; + + if (mode == TYPE_MODE (short_accum_type_node)) + return unsignedp ? sat_short_accum_type_node : short_accum_type_node; + if (mode == TYPE_MODE (accum_type_node)) + return unsignedp ? sat_accum_type_node : accum_type_node; + if (mode == TYPE_MODE (long_accum_type_node)) + return unsignedp ? sat_long_accum_type_node : long_accum_type_node; + if (mode == TYPE_MODE (long_long_accum_type_node)) + return unsignedp ? sat_long_long_accum_type_node + : long_long_accum_type_node; + + if (mode == TYPE_MODE (unsigned_short_accum_type_node)) + return unsignedp ? sat_unsigned_short_accum_type_node + : unsigned_short_accum_type_node; + if (mode == TYPE_MODE (unsigned_accum_type_node)) + return unsignedp ? sat_unsigned_accum_type_node + : unsigned_accum_type_node; + if (mode == TYPE_MODE (unsigned_long_accum_type_node)) + return unsignedp ? sat_unsigned_long_accum_type_node + : unsigned_long_accum_type_node; + if (mode == TYPE_MODE (unsigned_long_long_accum_type_node)) + return unsignedp ? sat_unsigned_long_long_accum_type_node + : unsigned_long_long_accum_type_node; + + if (mode == QQmode) + return unsignedp ? sat_qq_type_node : qq_type_node; + if (mode == HQmode) + return unsignedp ? sat_hq_type_node : hq_type_node; + if (mode == SQmode) + return unsignedp ? sat_sq_type_node : sq_type_node; + if (mode == DQmode) + return unsignedp ? sat_dq_type_node : dq_type_node; + if (mode == TQmode) + return unsignedp ? sat_tq_type_node : tq_type_node; + + if (mode == UQQmode) + return unsignedp ? sat_uqq_type_node : uqq_type_node; + if (mode == UHQmode) + return unsignedp ? sat_uhq_type_node : uhq_type_node; + if (mode == USQmode) + return unsignedp ? sat_usq_type_node : usq_type_node; + if (mode == UDQmode) + return unsignedp ? sat_udq_type_node : udq_type_node; + if (mode == UTQmode) + return unsignedp ? sat_utq_type_node : utq_type_node; + + if (mode == HAmode) + return unsignedp ? sat_ha_type_node : ha_type_node; + if (mode == SAmode) + return unsignedp ? sat_sa_type_node : sa_type_node; + if (mode == DAmode) + return unsignedp ? sat_da_type_node : da_type_node; + if (mode == TAmode) + return unsignedp ? sat_ta_type_node : ta_type_node; + + if (mode == UHAmode) + return unsignedp ? sat_uha_type_node : uha_type_node; + if (mode == USAmode) + return unsignedp ? sat_usa_type_node : usa_type_node; + if (mode == UDAmode) + return unsignedp ? sat_uda_type_node : uda_type_node; + if (mode == UTAmode) + return unsignedp ? sat_uta_type_node : uta_type_node; + } + + for (t = registered_builtin_types; t; t = TREE_CHAIN (t)) + if (TYPE_MODE (TREE_VALUE (t)) == mode) + return TREE_VALUE (t); + + return 0; +} + +tree +c_common_unsigned_type (tree type) +{ + return c_common_signed_or_unsigned_type (1, type); +} + +/* Return a signed type the same as TYPE in other respects. */ + +tree +c_common_signed_type (tree type) +{ + return c_common_signed_or_unsigned_type (0, type); +} + +/* Return a type the same as TYPE except unsigned or + signed according to UNSIGNEDP. */ + +tree +c_common_signed_or_unsigned_type (int unsignedp, tree type) +{ + tree type1; + + /* This block of code emulates the behavior of the old + c_common_unsigned_type. In particular, it returns + long_unsigned_type_node if passed a long, even when a int would + have the same size. This is necessary for warnings to work + correctly in archs where sizeof(int) == sizeof(long) */ + + type1 = TYPE_MAIN_VARIANT (type); + if (type1 == signed_char_type_node || type1 == char_type_node || type1 == unsigned_char_type_node) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (type1 == integer_type_node || type1 == unsigned_type_node) + return unsignedp ? unsigned_type_node : integer_type_node; + if (type1 == short_integer_type_node || type1 == short_unsigned_type_node) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + if (type1 == long_integer_type_node || type1 == long_unsigned_type_node) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + if (type1 == long_long_integer_type_node || type1 == long_long_unsigned_type_node) + return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node; + if (int128_integer_type_node + && (type1 == int128_integer_type_node + || type1 == int128_unsigned_type_node)) + return unsignedp ? int128_unsigned_type_node : int128_integer_type_node; + if (type1 == widest_integer_literal_type_node || type1 == widest_unsigned_literal_type_node) + return unsignedp ? widest_unsigned_literal_type_node : widest_integer_literal_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 + if (type1 == intTI_type_node || type1 == unsigned_intTI_type_node) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + if (type1 == intDI_type_node || type1 == unsigned_intDI_type_node) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (type1 == intSI_type_node || type1 == unsigned_intSI_type_node) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + if (type1 == intHI_type_node || type1 == unsigned_intHI_type_node) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + if (type1 == intQI_type_node || type1 == unsigned_intQI_type_node) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + +#define C_COMMON_FIXED_TYPES(NAME) \ + if (type1 == short_ ## NAME ## _type_node \ + || type1 == unsigned_short_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_short_ ## NAME ## _type_node \ + : short_ ## NAME ## _type_node; \ + if (type1 == NAME ## _type_node \ + || type1 == unsigned_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_ ## NAME ## _type_node \ + : NAME ## _type_node; \ + if (type1 == long_ ## NAME ## _type_node \ + || type1 == unsigned_long_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_long_ ## NAME ## _type_node \ + : long_ ## NAME ## _type_node; \ + if (type1 == long_long_ ## NAME ## _type_node \ + || type1 == unsigned_long_long_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_long_long_ ## NAME ## _type_node \ + : long_long_ ## NAME ## _type_node; + +#define C_COMMON_FIXED_MODE_TYPES(NAME) \ + if (type1 == NAME ## _type_node \ + || type1 == u ## NAME ## _type_node) \ + return unsignedp ? u ## NAME ## _type_node \ + : NAME ## _type_node; + +#define C_COMMON_FIXED_TYPES_SAT(NAME) \ + if (type1 == sat_ ## short_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_short_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_short_ ## NAME ## _type_node \ + : sat_ ## short_ ## NAME ## _type_node; \ + if (type1 == sat_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_ ## NAME ## _type_node \ + : sat_ ## NAME ## _type_node; \ + if (type1 == sat_ ## long_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_long_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_long_ ## NAME ## _type_node \ + : sat_ ## long_ ## NAME ## _type_node; \ + if (type1 == sat_ ## long_long_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_long_long_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_long_long_ ## NAME ## _type_node \ + : sat_ ## long_long_ ## NAME ## _type_node; + +#define C_COMMON_FIXED_MODE_TYPES_SAT(NAME) \ + if (type1 == sat_ ## NAME ## _type_node \ + || type1 == sat_ ## u ## NAME ## _type_node) \ + return unsignedp ? sat_ ## u ## NAME ## _type_node \ + : sat_ ## NAME ## _type_node; + + C_COMMON_FIXED_TYPES (fract); + C_COMMON_FIXED_TYPES_SAT (fract); + C_COMMON_FIXED_TYPES (accum); + C_COMMON_FIXED_TYPES_SAT (accum); + + C_COMMON_FIXED_MODE_TYPES (qq); + C_COMMON_FIXED_MODE_TYPES (hq); + C_COMMON_FIXED_MODE_TYPES (sq); + C_COMMON_FIXED_MODE_TYPES (dq); + C_COMMON_FIXED_MODE_TYPES (tq); + C_COMMON_FIXED_MODE_TYPES_SAT (qq); + C_COMMON_FIXED_MODE_TYPES_SAT (hq); + C_COMMON_FIXED_MODE_TYPES_SAT (sq); + C_COMMON_FIXED_MODE_TYPES_SAT (dq); + C_COMMON_FIXED_MODE_TYPES_SAT (tq); + C_COMMON_FIXED_MODE_TYPES (ha); + C_COMMON_FIXED_MODE_TYPES (sa); + C_COMMON_FIXED_MODE_TYPES (da); + C_COMMON_FIXED_MODE_TYPES (ta); + C_COMMON_FIXED_MODE_TYPES_SAT (ha); + C_COMMON_FIXED_MODE_TYPES_SAT (sa); + C_COMMON_FIXED_MODE_TYPES_SAT (da); + C_COMMON_FIXED_MODE_TYPES_SAT (ta); + + /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not + the precision; they have precision set to match their range, but + may use a wider mode to match an ABI. If we change modes, we may + wind up with bad conversions. For INTEGER_TYPEs in C, must check + the precision as well, so as to yield correct results for + bit-field types. C++ does not have these separate bit-field + types, and producing a signed or unsigned variant of an + ENUMERAL_TYPE may cause other problems as well. */ + + if (!INTEGRAL_TYPE_P (type) + || TYPE_UNSIGNED (type) == unsignedp) + return type; + +#define TYPE_OK(node) \ + (TYPE_MODE (type) == TYPE_MODE (node) \ + && TYPE_PRECISION (type) == TYPE_PRECISION (node)) + if (TYPE_OK (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (TYPE_OK (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + if (TYPE_OK (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + if (TYPE_OK (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + if (TYPE_OK (long_long_integer_type_node)) + return (unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node); + if (int128_integer_type_node && TYPE_OK (int128_integer_type_node)) + return (unsignedp ? int128_unsigned_type_node + : int128_integer_type_node); + if (TYPE_OK (widest_integer_literal_type_node)) + return (unsignedp ? widest_unsigned_literal_type_node + : widest_integer_literal_type_node); + +#if HOST_BITS_PER_WIDE_INT >= 64 + if (TYPE_OK (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + if (TYPE_OK (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (TYPE_OK (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + if (TYPE_OK (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + if (TYPE_OK (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; +#undef TYPE_OK + + return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp); +} + +/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP. */ + +tree +c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp) +{ + /* Extended integer types of the same width as a standard type have + lesser rank, so those of the same width as int promote to int or + unsigned int and are valid for printf formats expecting int or + unsigned int. To avoid such special cases, avoid creating + extended integer types for bit-fields if a standard integer type + is available. */ + if (width == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + if (width == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (width == TYPE_PRECISION (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + if (width == TYPE_PRECISION (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + if (width == TYPE_PRECISION (long_long_integer_type_node)) + return (unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node); + if (int128_integer_type_node + && width == TYPE_PRECISION (int128_integer_type_node)) + return (unsignedp ? int128_unsigned_type_node + : int128_integer_type_node); + return build_nonstandard_integer_type (width, unsignedp); +} + +/* The C version of the register_builtin_type langhook. */ + +void +c_register_builtin_type (tree type, const char* name) +{ + tree decl; + + decl = build_decl (UNKNOWN_LOCATION, + TYPE_DECL, get_identifier (name), type); + DECL_ARTIFICIAL (decl) = 1; + if (!TYPE_NAME (type)) + TYPE_NAME (type) = decl; + pushdecl (decl); + + registered_builtin_types = tree_cons (0, type, registered_builtin_types); +} + +/* Print an error message for invalid operands to arith operation + CODE with TYPE0 for operand 0, and TYPE1 for operand 1. + LOCATION is the location of the message. */ + +void +binary_op_error (location_t location, enum tree_code code, + tree type0, tree type1) +{ + const char *opname; + + switch (code) + { + case PLUS_EXPR: + opname = "+"; break; + case MINUS_EXPR: + opname = "-"; break; + case MULT_EXPR: + opname = "*"; break; + case MAX_EXPR: + opname = "max"; break; + case MIN_EXPR: + opname = "min"; break; + case EQ_EXPR: + opname = "=="; break; + case NE_EXPR: + opname = "!="; break; + case LE_EXPR: + opname = "<="; break; + case GE_EXPR: + opname = ">="; break; + case LT_EXPR: + opname = "<"; break; + case GT_EXPR: + opname = ">"; break; + case LSHIFT_EXPR: + opname = "<<"; break; + case RSHIFT_EXPR: + opname = ">>"; break; + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: + opname = "%"; break; + case TRUNC_DIV_EXPR: + case FLOOR_DIV_EXPR: + opname = "/"; break; + case BIT_AND_EXPR: + opname = "&"; break; + case BIT_IOR_EXPR: + opname = "|"; break; + case TRUTH_ANDIF_EXPR: + opname = "&&"; break; + case TRUTH_ORIF_EXPR: + opname = "||"; break; + case BIT_XOR_EXPR: + opname = "^"; break; + default: + gcc_unreachable (); + } + error_at (location, + "invalid operands to binary %s (have %qT and %qT)", opname, + type0, type1); +} + +/* Subroutine of build_binary_op, used for comparison operations. + See if the operands have both been converted from subword integer types + and, if so, perhaps change them both back to their original type. + This function is also responsible for converting the two operands + to the proper common type for comparison. + + The arguments of this function are all pointers to local variables + of build_binary_op: OP0_PTR is &OP0, OP1_PTR is &OP1, + RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE. + + If this function returns nonzero, it means that the comparison has + a constant value. What this function returns is an expression for + that value. */ + +tree +shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, + enum tree_code *rescode_ptr) +{ + tree type; + tree op0 = *op0_ptr; + tree op1 = *op1_ptr; + int unsignedp0, unsignedp1; + int real1, real2; + tree primop0, primop1; + enum tree_code code = *rescode_ptr; + + /* Throw away any conversions to wider types + already present in the operands. */ + + primop0 = get_narrower (op0, &unsignedp0); + primop1 = get_narrower (op1, &unsignedp1); + + /* Handle the case that OP0 does not *contain* a conversion + but it *requires* conversion to FINAL_TYPE. */ + + if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr) + unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (op0)); + if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr) + unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (op1)); + + /* If one of the operands must be floated, we cannot optimize. */ + real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE; + real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE; + + /* If first arg is constant, swap the args (changing operation + so value is preserved), for canonicalization. Don't do this if + the second arg is 0. */ + + if (TREE_CONSTANT (primop0) + && !integer_zerop (primop1) && !real_zerop (primop1) + && !fixed_zerop (primop1)) + { + tree tem = primop0; + int temi = unsignedp0; + primop0 = primop1; + primop1 = tem; + tem = op0; + op0 = op1; + op1 = tem; + *op0_ptr = op0; + *op1_ptr = op1; + unsignedp0 = unsignedp1; + unsignedp1 = temi; + temi = real1; + real1 = real2; + real2 = temi; + + switch (code) + { + case LT_EXPR: + code = GT_EXPR; + break; + case GT_EXPR: + code = LT_EXPR; + break; + case LE_EXPR: + code = GE_EXPR; + break; + case GE_EXPR: + code = LE_EXPR; + break; + default: + break; + } + *rescode_ptr = code; + } + + /* If comparing an integer against a constant more bits wide, + maybe we can deduce a value of 1 or 0 independent of the data. + Or else truncate the constant now + rather than extend the variable at run time. + + This is only interesting if the constant is the wider arg. + Also, it is not safe if the constant is unsigned and the + variable arg is signed, since in this case the variable + would be sign-extended and then regarded as unsigned. + Our technique fails in this case because the lowest/highest + possible unsigned results don't follow naturally from the + lowest/highest possible values of the variable operand. + For just EQ_EXPR and NE_EXPR there is another technique that + could be used: see if the constant can be faithfully represented + in the other operand's type, by truncating it and reextending it + and see if that preserves the constant's value. */ + + if (!real1 && !real2 + && TREE_CODE (TREE_TYPE (primop0)) != FIXED_POINT_TYPE + && TREE_CODE (primop1) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)) + { + int min_gt, max_gt, min_lt, max_lt; + tree maxval, minval; + /* 1 if comparison is nominally unsigned. */ + int unsignedp = TYPE_UNSIGNED (*restype_ptr); + tree val; + + type = c_common_signed_or_unsigned_type (unsignedp0, + TREE_TYPE (primop0)); + + maxval = TYPE_MAX_VALUE (type); + minval = TYPE_MIN_VALUE (type); + + if (unsignedp && !unsignedp0) + *restype_ptr = c_common_signed_type (*restype_ptr); + + if (TREE_TYPE (primop1) != *restype_ptr) + { + /* Convert primop1 to target type, but do not introduce + additional overflow. We know primop1 is an int_cst. */ + primop1 = force_fit_type_double (*restype_ptr, + TREE_INT_CST_LOW (primop1), + TREE_INT_CST_HIGH (primop1), 0, + TREE_OVERFLOW (primop1)); + } + if (type != *restype_ptr) + { + minval = convert (*restype_ptr, minval); + maxval = convert (*restype_ptr, maxval); + } + + if (unsignedp && unsignedp0) + { + min_gt = INT_CST_LT_UNSIGNED (primop1, minval); + max_gt = INT_CST_LT_UNSIGNED (primop1, maxval); + min_lt = INT_CST_LT_UNSIGNED (minval, primop1); + max_lt = INT_CST_LT_UNSIGNED (maxval, primop1); + } + else + { + min_gt = INT_CST_LT (primop1, minval); + max_gt = INT_CST_LT (primop1, maxval); + min_lt = INT_CST_LT (minval, primop1); + max_lt = INT_CST_LT (maxval, primop1); + } + + val = 0; + /* This used to be a switch, but Genix compiler can't handle that. */ + if (code == NE_EXPR) + { + if (max_lt || min_gt) + val = truthvalue_true_node; + } + else if (code == EQ_EXPR) + { + if (max_lt || min_gt) + val = truthvalue_false_node; + } + else if (code == LT_EXPR) + { + if (max_lt) + val = truthvalue_true_node; + if (!min_lt) + val = truthvalue_false_node; + } + else if (code == GT_EXPR) + { + if (min_gt) + val = truthvalue_true_node; + if (!max_gt) + val = truthvalue_false_node; + } + else if (code == LE_EXPR) + { + if (!max_gt) + val = truthvalue_true_node; + if (min_gt) + val = truthvalue_false_node; + } + else if (code == GE_EXPR) + { + if (!min_lt) + val = truthvalue_true_node; + if (max_lt) + val = truthvalue_false_node; + } + + /* If primop0 was sign-extended and unsigned comparison specd, + we did a signed comparison above using the signed type bounds. + But the comparison we output must be unsigned. + + Also, for inequalities, VAL is no good; but if the signed + comparison had *any* fixed result, it follows that the + unsigned comparison just tests the sign in reverse + (positive values are LE, negative ones GE). + So we can generate an unsigned comparison + against an extreme value of the signed type. */ + + if (unsignedp && !unsignedp0) + { + if (val != 0) + switch (code) + { + case LT_EXPR: + case GE_EXPR: + primop1 = TYPE_MIN_VALUE (type); + val = 0; + break; + + case LE_EXPR: + case GT_EXPR: + primop1 = TYPE_MAX_VALUE (type); + val = 0; + break; + + default: + break; + } + type = c_common_unsigned_type (type); + } + + if (TREE_CODE (primop0) != INTEGER_CST) + { + if (val == truthvalue_false_node) + warning (OPT_Wtype_limits, "comparison is always false due to limited range of data type"); + if (val == truthvalue_true_node) + warning (OPT_Wtype_limits, "comparison is always true due to limited range of data type"); + } + + if (val != 0) + { + /* Don't forget to evaluate PRIMOP0 if it has side effects. */ + if (TREE_SIDE_EFFECTS (primop0)) + return build2 (COMPOUND_EXPR, TREE_TYPE (val), primop0, val); + return val; + } + + /* Value is not predetermined, but do the comparison + in the type of the operand that is not constant. + TYPE is already properly set. */ + } + + /* If either arg is decimal float and the other is float, find the + proper common type to use for comparison. */ + else if (real1 && real2 + && (DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (primop0))) + || DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (primop1))))) + type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)); + + else if (real1 && real2 + && (TYPE_PRECISION (TREE_TYPE (primop0)) + == TYPE_PRECISION (TREE_TYPE (primop1)))) + type = TREE_TYPE (primop0); + + /* If args' natural types are both narrower than nominal type + and both extend in the same manner, compare them + in the type of the wider arg. + Otherwise must actually extend both to the nominal + common type lest different ways of extending + alter the result. + (eg, (short)-1 == (unsigned short)-1 should be 0.) */ + + else if (unsignedp0 == unsignedp1 && real1 == real2 + && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr) + && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)) + { + type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)); + type = c_common_signed_or_unsigned_type (unsignedp0 + || TYPE_UNSIGNED (*restype_ptr), + type); + /* Make sure shorter operand is extended the right way + to match the longer operand. */ + primop0 + = convert (c_common_signed_or_unsigned_type (unsignedp0, + TREE_TYPE (primop0)), + primop0); + primop1 + = convert (c_common_signed_or_unsigned_type (unsignedp1, + TREE_TYPE (primop1)), + primop1); + } + else + { + /* Here we must do the comparison on the nominal type + using the args exactly as we received them. */ + type = *restype_ptr; + primop0 = op0; + primop1 = op1; + + if (!real1 && !real2 && integer_zerop (primop1) + && TYPE_UNSIGNED (*restype_ptr)) + { + tree value = 0; + switch (code) + { + case GE_EXPR: + /* All unsigned values are >= 0, so we warn. However, + if OP0 is a constant that is >= 0, the signedness of + the comparison isn't an issue, so suppress the + warning. */ + if (warn_type_limits && !in_system_header + && !(TREE_CODE (primop0) == INTEGER_CST + && !TREE_OVERFLOW (convert (c_common_signed_type (type), + primop0)))) + warning (OPT_Wtype_limits, + "comparison of unsigned expression >= 0 is always true"); + value = truthvalue_true_node; + break; + + case LT_EXPR: + if (warn_type_limits && !in_system_header + && !(TREE_CODE (primop0) == INTEGER_CST + && !TREE_OVERFLOW (convert (c_common_signed_type (type), + primop0)))) + warning (OPT_Wtype_limits, + "comparison of unsigned expression < 0 is always false"); + value = truthvalue_false_node; + break; + + default: + break; + } + + if (value != 0) + { + /* Don't forget to evaluate PRIMOP0 if it has side effects. */ + if (TREE_SIDE_EFFECTS (primop0)) + return build2 (COMPOUND_EXPR, TREE_TYPE (value), + primop0, value); + return value; + } + } + } + + *op0_ptr = convert (type, primop0); + *op1_ptr = convert (type, primop1); + + *restype_ptr = truthvalue_type_node; + + return 0; +} + +/* Return a tree for the sum or difference (RESULTCODE says which) + of pointer PTROP and integer INTOP. */ + +tree +pointer_int_sum (location_t loc, enum tree_code resultcode, + tree ptrop, tree intop) +{ + tree size_exp, ret; + + /* The result is a pointer of the same type that is being added. */ + tree result_type = TREE_TYPE (ptrop); + + if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) + { + pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + "pointer of type % used in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE) + { + pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + "pointer to a function used in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE) + { + pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + "pointer to member function used in arithmetic"); + size_exp = integer_one_node; + } + else + size_exp = size_in_bytes (TREE_TYPE (result_type)); + + /* We are manipulating pointer values, so we don't need to warn + about relying on undefined signed overflow. We disable the + warning here because we use integer types so fold won't know that + they are really pointers. */ + fold_defer_overflow_warnings (); + + /* If what we are about to multiply by the size of the elements + contains a constant term, apply distributive law + and multiply that constant term separately. + This helps produce common subexpressions. */ + if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR) + && !TREE_CONSTANT (intop) + && TREE_CONSTANT (TREE_OPERAND (intop, 1)) + && TREE_CONSTANT (size_exp) + /* If the constant comes from pointer subtraction, + skip this optimization--it would cause an error. */ + && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE + /* If the constant is unsigned, and smaller than the pointer size, + then we must skip this optimization. This is because it could cause + an overflow error if the constant is negative but INTOP is not. */ + && (!TYPE_UNSIGNED (TREE_TYPE (intop)) + || (TYPE_PRECISION (TREE_TYPE (intop)) + == TYPE_PRECISION (TREE_TYPE (ptrop))))) + { + enum tree_code subcode = resultcode; + tree int_type = TREE_TYPE (intop); + if (TREE_CODE (intop) == MINUS_EXPR) + subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); + /* Convert both subexpression types to the type of intop, + because weird cases involving pointer arithmetic + can result in a sum or difference with different type args. */ + ptrop = build_binary_op (EXPR_LOCATION (TREE_OPERAND (intop, 1)), + subcode, ptrop, + convert (int_type, TREE_OPERAND (intop, 1)), 1); + intop = convert (int_type, TREE_OPERAND (intop, 0)); + } + + /* Convert the integer argument to a type the same size as sizetype + so the multiply won't overflow spuriously. */ + if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype) + || TYPE_UNSIGNED (TREE_TYPE (intop)) != TYPE_UNSIGNED (sizetype)) + intop = convert (c_common_type_for_size (TYPE_PRECISION (sizetype), + TYPE_UNSIGNED (sizetype)), intop); + + /* Replace the integer argument with a suitable product by the object size. + Do this multiplication as signed, then convert to the appropriate type + for the pointer operation and disregard an overflow that occured only + because of the sign-extension change in the latter conversion. */ + { + tree t = build_binary_op (loc, + MULT_EXPR, intop, + convert (TREE_TYPE (intop), size_exp), 1); + intop = convert (sizetype, t); + if (TREE_OVERFLOW_P (intop) && !TREE_OVERFLOW (t)) + intop = build_int_cst_wide (TREE_TYPE (intop), TREE_INT_CST_LOW (intop), + TREE_INT_CST_HIGH (intop)); + } + + /* Create the sum or difference. */ + if (resultcode == MINUS_EXPR) + intop = fold_build1_loc (loc, NEGATE_EXPR, sizetype, intop); + + ret = fold_build2_loc (loc, POINTER_PLUS_EXPR, result_type, ptrop, intop); + + fold_undefer_and_ignore_overflow_warnings (); + + return ret; +} + +/* Wrap a C_MAYBE_CONST_EXPR around an expression that is fully folded + and if NON_CONST is known not to be permitted in an evaluated part + of a constant expression. */ + +tree +c_wrap_maybe_const (tree expr, bool non_const) +{ + bool nowarning = TREE_NO_WARNING (expr); + location_t loc = EXPR_LOCATION (expr); + + /* This should never be called for C++. */ + if (c_dialect_cxx ()) + gcc_unreachable (); + + /* The result of folding may have a NOP_EXPR to set TREE_NO_WARNING. */ + STRIP_TYPE_NOPS (expr); + expr = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL, expr); + C_MAYBE_CONST_EXPR_NON_CONST (expr) = non_const; + if (nowarning) + TREE_NO_WARNING (expr) = 1; + protected_set_expr_location (expr, loc); + + return expr; +} + +/* Wrap a SAVE_EXPR around EXPR, if appropriate. Like save_expr, but + for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR + around the SAVE_EXPR if needed so that c_fully_fold does not need + to look inside SAVE_EXPRs. */ + +tree +c_save_expr (tree expr) +{ + bool maybe_const = true; + if (c_dialect_cxx ()) + return save_expr (expr); + expr = c_fully_fold (expr, false, &maybe_const); + expr = save_expr (expr); + if (!maybe_const) + expr = c_wrap_maybe_const (expr, true); + return expr; +} + +/* Return whether EXPR is a declaration whose address can never be + NULL. */ + +bool +decl_with_nonnull_addr_p (const_tree expr) +{ + return (DECL_P (expr) + && (TREE_CODE (expr) == PARM_DECL + || TREE_CODE (expr) == LABEL_DECL + || !DECL_WEAK (expr))); +} + +/* Prepare expr to be an argument of a TRUTH_NOT_EXPR, + or for an `if' or `while' statement or ?..: exp. It should already + have been validated to be of suitable type; otherwise, a bad + diagnostic may result. + + The EXPR is located at LOCATION. + + This preparation consists of taking the ordinary + representation of an expression expr and producing a valid tree + boolean expression describing whether expr is nonzero. We could + simply always do build_binary_op (NE_EXPR, expr, truthvalue_false_node, 1), + but we optimize comparisons, &&, ||, and !. + + The resulting type should always be `truthvalue_type_node'. */ + +tree +c_common_truthvalue_conversion (location_t location, tree expr) +{ + switch (TREE_CODE (expr)) + { + case EQ_EXPR: case NE_EXPR: case UNEQ_EXPR: case LTGT_EXPR: + case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: + case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR: + case ORDERED_EXPR: case UNORDERED_EXPR: + if (TREE_TYPE (expr) == truthvalue_type_node) + return expr; + expr = build2 (TREE_CODE (expr), truthvalue_type_node, + TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1)); + goto ret; + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + if (TREE_TYPE (expr) == truthvalue_type_node) + return expr; + expr = build2 (TREE_CODE (expr), truthvalue_type_node, + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 0)), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 1))); + goto ret; + + case TRUTH_NOT_EXPR: + if (TREE_TYPE (expr) == truthvalue_type_node) + return expr; + expr = build1 (TREE_CODE (expr), truthvalue_type_node, + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 0))); + goto ret; + + case ERROR_MARK: + return expr; + + case INTEGER_CST: + return integer_zerop (expr) ? truthvalue_false_node + : truthvalue_true_node; + + case REAL_CST: + return real_compare (NE_EXPR, &TREE_REAL_CST (expr), &dconst0) + ? truthvalue_true_node + : truthvalue_false_node; + + case FIXED_CST: + return fixed_compare (NE_EXPR, &TREE_FIXED_CST (expr), + &FCONST0 (TYPE_MODE (TREE_TYPE (expr)))) + ? truthvalue_true_node + : truthvalue_false_node; + + case FUNCTION_DECL: + expr = build_unary_op (location, ADDR_EXPR, expr, 0); + /* Fall through. */ + + case ADDR_EXPR: + { + tree inner = TREE_OPERAND (expr, 0); + if (decl_with_nonnull_addr_p (inner)) + { + /* Common Ada/Pascal programmer's mistake. */ + warning_at (location, + OPT_Waddress, + "the address of %qD will always evaluate as %", + inner); + return truthvalue_true_node; + } + + /* If we still have a decl, it is possible for its address to + be NULL, so we cannot optimize. */ + if (DECL_P (inner)) + { + gcc_assert (DECL_WEAK (inner)); + break; + } + + if (TREE_SIDE_EFFECTS (inner)) + { + expr = build2 (COMPOUND_EXPR, truthvalue_type_node, + inner, truthvalue_true_node); + goto ret; + } + else + return truthvalue_true_node; + } + + case COMPLEX_EXPR: + expr = build_binary_op (EXPR_LOCATION (expr), + (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)) + ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 0)), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 1)), + 0); + goto ret; + + case NEGATE_EXPR: + case ABS_EXPR: + case FLOAT_EXPR: + case EXCESS_PRECISION_EXPR: + /* These don't change whether an object is nonzero or zero. */ + return c_common_truthvalue_conversion (location, TREE_OPERAND (expr, 0)); + + case LROTATE_EXPR: + case RROTATE_EXPR: + /* These don't change whether an object is zero or nonzero, but + we can't ignore them if their second arg has side-effects. */ + if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))) + { + expr = build2 (COMPOUND_EXPR, truthvalue_type_node, + TREE_OPERAND (expr, 1), + c_common_truthvalue_conversion + (location, TREE_OPERAND (expr, 0))); + goto ret; + } + else + return c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 0)); + + case COND_EXPR: + /* Distribute the conversion into the arms of a COND_EXPR. */ + if (c_dialect_cxx ()) + { + expr = fold_build3_loc (location, COND_EXPR, truthvalue_type_node, + TREE_OPERAND (expr, 0), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, + 1)), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, + 2))); + goto ret; + } + else + { + /* Folding will happen later for C. */ + expr = build3 (COND_EXPR, truthvalue_type_node, + TREE_OPERAND (expr, 0), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 1)), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 2))); + goto ret; + } + + CASE_CONVERT: + /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE, + since that affects how `default_conversion' will behave. */ + if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE + || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE) + break; + /* If this is widening the argument, we can ignore it. */ + if (TYPE_PRECISION (TREE_TYPE (expr)) + >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) + return c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 0)); + break; + + case MODIFY_EXPR: + if (!TREE_NO_WARNING (expr) + && warn_parentheses) + { + warning (OPT_Wparentheses, + "suggest parentheses around assignment used as truth value"); + TREE_NO_WARNING (expr) = 1; + } + break; + + default: + break; + } + + if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) + { + tree t = c_save_expr (expr); + expr = (build_binary_op + (EXPR_LOCATION (expr), + (TREE_SIDE_EFFECTS (expr) + ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), + c_common_truthvalue_conversion + (location, + build_unary_op (location, REALPART_EXPR, t, 0)), + c_common_truthvalue_conversion + (location, + build_unary_op (location, IMAGPART_EXPR, t, 0)), + 0)); + goto ret; + } + + if (TREE_CODE (TREE_TYPE (expr)) == FIXED_POINT_TYPE) + { + tree fixed_zero_node = build_fixed (TREE_TYPE (expr), + FCONST0 (TYPE_MODE + (TREE_TYPE (expr)))); + return build_binary_op (location, NE_EXPR, expr, fixed_zero_node, 1); + } + else + return build_binary_op (location, NE_EXPR, expr, integer_zero_node, 1); + + ret: + protected_set_expr_location (expr, location); + return expr; +} + +static void def_builtin_1 (enum built_in_function fncode, + const char *name, + enum built_in_class fnclass, + tree fntype, tree libtype, + bool both_p, bool fallback_p, bool nonansi_p, + tree fnattrs, bool implicit_p); + + +/* Apply the TYPE_QUALS to the new DECL. */ + +void +c_apply_type_quals_to_decl (int type_quals, tree decl) +{ + tree type = TREE_TYPE (decl); + + if (type == error_mark_node) + return; + + if (((type_quals & TYPE_QUAL_CONST) + || (type && TREE_CODE (type) == REFERENCE_TYPE)) + /* An object declared 'const' is only readonly after it is + initialized. We don't have any way of expressing this currently, + so we need to be conservative and unset TREE_READONLY for types + with constructors. Otherwise aliasing code will ignore stores in + an inline constructor. */ + && !(type && TYPE_NEEDS_CONSTRUCTING (type))) + TREE_READONLY (decl) = 1; + if (type_quals & TYPE_QUAL_VOLATILE) + { + TREE_SIDE_EFFECTS (decl) = 1; + TREE_THIS_VOLATILE (decl) = 1; + } + if (type_quals & TYPE_QUAL_RESTRICT) + { + while (type && TREE_CODE (type) == ARRAY_TYPE) + /* Allow 'restrict' on arrays of pointers. + FIXME currently we just ignore it. */ + type = TREE_TYPE (type); + if (!type + || !POINTER_TYPE_P (type) + || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type))) + error ("invalid use of %"); + } +} + +/* Hash function for the problem of multiple type definitions in + different files. This must hash all types that will compare + equal via comptypes to the same value. In practice it hashes + on some of the simple stuff and leaves the details to comptypes. */ + +static hashval_t +c_type_hash (const void *p) +{ + int i = 0; + int shift, size; + const_tree const t = (const_tree) p; + tree t2; + switch (TREE_CODE (t)) + { + /* For pointers, hash on pointee type plus some swizzling. */ + case POINTER_TYPE: + return c_type_hash (TREE_TYPE (t)) ^ 0x3003003; + /* Hash on number of elements and total size. */ + case ENUMERAL_TYPE: + shift = 3; + t2 = TYPE_VALUES (t); + break; + case RECORD_TYPE: + shift = 0; + t2 = TYPE_FIELDS (t); + break; + case QUAL_UNION_TYPE: + shift = 1; + t2 = TYPE_FIELDS (t); + break; + case UNION_TYPE: + shift = 2; + t2 = TYPE_FIELDS (t); + break; + default: + gcc_unreachable (); + } + for (; t2; t2 = TREE_CHAIN (t2)) + i++; + /* We might have a VLA here. */ + if (TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST) + size = 0; + else + size = TREE_INT_CST_LOW (TYPE_SIZE (t)); + return ((size << 24) | (i << shift)); +} + +static GTY((param_is (union tree_node))) htab_t type_hash_table; + +/* Return the typed-based alias set for T, which may be an expression + or a type. Return -1 if we don't do anything special. */ + +alias_set_type +c_common_get_alias_set (tree t) +{ + tree u; + PTR *slot; + + /* For VLAs, use the alias set of the element type rather than the + default of alias set 0 for types compared structurally. */ + if (TYPE_P (t) && TYPE_STRUCTURAL_EQUALITY_P (t)) + { + if (TREE_CODE (t) == ARRAY_TYPE) + return get_alias_set (TREE_TYPE (t)); + return -1; + } + + /* Permit type-punning when accessing a union, provided the access + is directly through the union. For example, this code does not + permit taking the address of a union member and then storing + through it. Even the type-punning allowed here is a GCC + extension, albeit a common and useful one; the C standard says + that such accesses have implementation-defined behavior. */ + for (u = t; + TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF; + u = TREE_OPERAND (u, 0)) + if (TREE_CODE (u) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE) + return 0; + + /* That's all the expressions we handle specially. */ + if (!TYPE_P (t)) + return -1; + + /* The C standard guarantees that any object may be accessed via an + lvalue that has character type. */ + if (t == char_type_node + || t == signed_char_type_node + || t == unsigned_char_type_node) + return 0; + + /* The C standard specifically allows aliasing between signed and + unsigned variants of the same type. We treat the signed + variant as canonical. */ + if (TREE_CODE (t) == INTEGER_TYPE && TYPE_UNSIGNED (t)) + { + tree t1 = c_common_signed_type (t); + + /* t1 == t can happen for boolean nodes which are always unsigned. */ + if (t1 != t) + return get_alias_set (t1); + } + else if (POINTER_TYPE_P (t)) + { + tree t1; + + /* Unfortunately, there is no canonical form of a pointer type. + In particular, if we have `typedef int I', then `int *', and + `I *' are different types. So, we have to pick a canonical + representative. We do this below. + + Technically, this approach is actually more conservative that + it needs to be. In particular, `const int *' and `int *' + should be in different alias sets, according to the C and C++ + standard, since their types are not the same, and so, + technically, an `int **' and `const int **' cannot point at + the same thing. + + But, the standard is wrong. In particular, this code is + legal C++: + + int *ip; + int **ipp = &ip; + const int* const* cipp = ipp; + + And, it doesn't make sense for that to be legal unless you + can dereference IPP and CIPP. So, we ignore cv-qualifiers on + the pointed-to types. This issue has been reported to the + C++ committee. */ + t1 = build_type_no_quals (t); + if (t1 != t) + return get_alias_set (t1); + } + + /* Handle the case of multiple type nodes referring to "the same" type, + which occurs with IMA. These share an alias set. FIXME: Currently only + C90 is handled. (In C99 type compatibility is not transitive, which + complicates things mightily. The alias set splay trees can theoretically + represent this, but insertion is tricky when you consider all the + different orders things might arrive in.) */ + + if (c_language != clk_c || flag_isoc99) + return -1; + + /* Save time if there's only one input file. */ + if (num_in_fnames == 1) + return -1; + + /* Pointers need special handling if they point to any type that + needs special handling (below). */ + if (TREE_CODE (t) == POINTER_TYPE) + { + tree t2; + /* Find bottom type under any nested POINTERs. */ + for (t2 = TREE_TYPE (t); + TREE_CODE (t2) == POINTER_TYPE; + t2 = TREE_TYPE (t2)) + ; + if (TREE_CODE (t2) != RECORD_TYPE + && TREE_CODE (t2) != ENUMERAL_TYPE + && TREE_CODE (t2) != QUAL_UNION_TYPE + && TREE_CODE (t2) != UNION_TYPE) + return -1; + if (TYPE_SIZE (t2) == 0) + return -1; + } + /* These are the only cases that need special handling. */ + if (TREE_CODE (t) != RECORD_TYPE + && TREE_CODE (t) != ENUMERAL_TYPE + && TREE_CODE (t) != QUAL_UNION_TYPE + && TREE_CODE (t) != UNION_TYPE + && TREE_CODE (t) != POINTER_TYPE) + return -1; + /* Undefined? */ + if (TYPE_SIZE (t) == 0) + return -1; + + /* Look up t in hash table. Only one of the compatible types within each + alias set is recorded in the table. */ + if (!type_hash_table) + type_hash_table = htab_create_ggc (1021, c_type_hash, + (htab_eq) lang_hooks.types_compatible_p, + NULL); + slot = htab_find_slot (type_hash_table, t, INSERT); + if (*slot != NULL) + { + TYPE_ALIAS_SET (t) = TYPE_ALIAS_SET ((tree)*slot); + return TYPE_ALIAS_SET ((tree)*slot); + } + else + /* Our caller will assign and record (in t) a new alias set; all we need + to do is remember t in the hash table. */ + *slot = t; + + return -1; +} + +/* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where + the second parameter indicates which OPERATOR is being applied. + The COMPLAIN flag controls whether we should diagnose possibly + ill-formed constructs or not. LOC is the location of the SIZEOF or + TYPEOF operator. */ + +tree +c_sizeof_or_alignof_type (location_t loc, + tree type, bool is_sizeof, int complain) +{ + const char *op_name; + tree value = NULL; + enum tree_code type_code = TREE_CODE (type); + + op_name = is_sizeof ? "sizeof" : "__alignof__"; + + if (type_code == FUNCTION_TYPE) + { + if (is_sizeof) + { + if (complain && (pedantic || warn_pointer_arith)) + pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + "invalid application of % to a function type"); + else if (!complain) + return error_mark_node; + value = size_one_node; + } + else + value = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT); + } + else if (type_code == VOID_TYPE || type_code == ERROR_MARK) + { + if (type_code == VOID_TYPE + && complain && (pedantic || warn_pointer_arith)) + pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + "invalid application of %qs to a void type", op_name); + else if (!complain) + return error_mark_node; + value = size_one_node; + } + else if (!COMPLETE_TYPE_P (type)) + { + if (complain) + error_at (loc, "invalid application of %qs to incomplete type %qT ", + op_name, type); + return error_mark_node; + } + else + { + if (is_sizeof) + /* Convert in case a char is more than one unit. */ + value = size_binop_loc (loc, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type), + size_int (TYPE_PRECISION (char_type_node) + / BITS_PER_UNIT)); + else + value = size_int (TYPE_ALIGN_UNIT (type)); + } + + /* VALUE will have an integer type with TYPE_IS_SIZETYPE set. + TYPE_IS_SIZETYPE means that certain things (like overflow) will + never happen. However, this node should really have type + `size_t', which is just a typedef for an ordinary integer type. */ + value = fold_convert_loc (loc, size_type_node, value); + gcc_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value))); + + return value; +} + +/* Implement the __alignof keyword: Return the minimum required + alignment of EXPR, measured in bytes. For VAR_DECLs, + FUNCTION_DECLs and FIELD_DECLs return DECL_ALIGN (which can be set + from an "aligned" __attribute__ specification). LOC is the + location of the ALIGNOF operator. */ + +tree +c_alignof_expr (location_t loc, tree expr) +{ + tree t; + + if (VAR_OR_FUNCTION_DECL_P (expr)) + t = size_int (DECL_ALIGN_UNIT (expr)); + + else if (TREE_CODE (expr) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1))) + { + error_at (loc, "%<__alignof%> applied to a bit-field"); + t = size_one_node; + } + else if (TREE_CODE (expr) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL) + t = size_int (DECL_ALIGN_UNIT (TREE_OPERAND (expr, 1))); + + else if (TREE_CODE (expr) == INDIRECT_REF) + { + tree t = TREE_OPERAND (expr, 0); + tree best = t; + int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + + while (CONVERT_EXPR_P (t) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE) + { + int thisalign; + + t = TREE_OPERAND (t, 0); + thisalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + if (thisalign > bestalign) + best = t, bestalign = thisalign; + } + return c_alignof (loc, TREE_TYPE (TREE_TYPE (best))); + } + else + return c_alignof (loc, TREE_TYPE (expr)); + + return fold_convert_loc (loc, size_type_node, t); +} + +/* Handle C and C++ default attributes. */ + +enum built_in_attribute +{ +#define DEF_ATTR_NULL_TREE(ENUM) ENUM, +#define DEF_ATTR_INT(ENUM, VALUE) ENUM, +#define DEF_ATTR_IDENT(ENUM, STRING) ENUM, +#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM, +#include "builtin-attrs.def" +#undef DEF_ATTR_NULL_TREE +#undef DEF_ATTR_INT +#undef DEF_ATTR_IDENT +#undef DEF_ATTR_TREE_LIST + ATTR_LAST +}; + +static GTY(()) tree built_in_attributes[(int) ATTR_LAST]; + +static void c_init_attributes (void); + +enum c_builtin_type +{ +#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME, +#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME, +#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME, +#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME, +#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, +#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, +#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, +#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, +#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, +#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, +#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, +#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, +#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, +#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \ + NAME, +#define DEF_POINTER_TYPE(NAME, TYPE) NAME, +#include "builtin-types.def" +#undef DEF_PRIMITIVE_TYPE +#undef DEF_FUNCTION_TYPE_0 +#undef DEF_FUNCTION_TYPE_1 +#undef DEF_FUNCTION_TYPE_2 +#undef DEF_FUNCTION_TYPE_3 +#undef DEF_FUNCTION_TYPE_4 +#undef DEF_FUNCTION_TYPE_5 +#undef DEF_FUNCTION_TYPE_6 +#undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_1 +#undef DEF_FUNCTION_TYPE_VAR_2 +#undef DEF_FUNCTION_TYPE_VAR_3 +#undef DEF_FUNCTION_TYPE_VAR_4 +#undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_POINTER_TYPE + BT_LAST +}; + +typedef enum c_builtin_type builtin_type; + +/* A temporary array for c_common_nodes_and_builtins. Used in + communication with def_fn_type. */ +static tree builtin_types[(int) BT_LAST + 1]; + +/* A helper function for c_common_nodes_and_builtins. Build function type + for DEF with return type RET and N arguments. If VAR is true, then the + function should be variadic after those N arguments. + + Takes special care not to ICE if any of the types involved are + error_mark_node, which indicates that said type is not in fact available + (see builtin_type_for_size). In which case the function type as a whole + should be error_mark_node. */ + +static void +def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...) +{ + tree args = NULL, t; + va_list list; + int i; + + va_start (list, n); + for (i = 0; i < n; ++i) + { + builtin_type a = (builtin_type) va_arg (list, int); + t = builtin_types[a]; + if (t == error_mark_node) + goto egress; + args = tree_cons (NULL_TREE, t, args); + } + va_end (list); + + args = nreverse (args); + if (!var) + args = chainon (args, void_list_node); + + t = builtin_types[ret]; + if (t == error_mark_node) + goto egress; + t = build_function_type (t, args); + + egress: + builtin_types[def] = t; +} + +/* Build builtin functions common to both C and C++ language + frontends. */ + +static void +c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node) +{ +#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \ + builtin_types[ENUM] = VALUE; +#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ + def_fn_type (ENUM, RETURN, 0, 0); +#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \ + def_fn_type (ENUM, RETURN, 0, 1, ARG1); +#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \ + def_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2); +#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ + def_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3); +#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ + def_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4); +#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ + def_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5); +#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6) \ + def_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6); +#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7) \ + def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); +#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ + def_fn_type (ENUM, RETURN, 1, 0); +#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ + def_fn_type (ENUM, RETURN, 1, 1, ARG1); +#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ + def_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2); +#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ + def_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3); +#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ + def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4); +#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ + def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5); +#define DEF_POINTER_TYPE(ENUM, TYPE) \ + builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]); + +#include "builtin-types.def" + +#undef DEF_PRIMITIVE_TYPE +#undef DEF_FUNCTION_TYPE_1 +#undef DEF_FUNCTION_TYPE_2 +#undef DEF_FUNCTION_TYPE_3 +#undef DEF_FUNCTION_TYPE_4 +#undef DEF_FUNCTION_TYPE_5 +#undef DEF_FUNCTION_TYPE_6 +#undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_1 +#undef DEF_FUNCTION_TYPE_VAR_2 +#undef DEF_FUNCTION_TYPE_VAR_3 +#undef DEF_FUNCTION_TYPE_VAR_4 +#undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_POINTER_TYPE + builtin_types[(int) BT_LAST] = NULL_TREE; + + c_init_attributes (); + +#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \ + NONANSI_P, ATTRS, IMPLICIT, COND) \ + if (NAME && COND) \ + def_builtin_1 (ENUM, NAME, CLASS, \ + builtin_types[(int) TYPE], \ + builtin_types[(int) LIBTYPE], \ + BOTH_P, FALLBACK_P, NONANSI_P, \ + built_in_attributes[(int) ATTRS], IMPLICIT); +#include "builtins.def" +#undef DEF_BUILTIN + + targetm.init_builtins (); + + build_common_builtin_nodes (); + + if (flag_mudflap) + mudflap_init (); +} + +/* Like get_identifier, but avoid warnings about null arguments when + the argument may be NULL for targets where GCC lacks stdint.h type + information. */ + +static inline tree +c_get_ident (const char *id) +{ + return get_identifier (id); +} + +/* Build tree nodes and builtin functions common to both C and C++ language + frontends. */ + +void +c_common_nodes_and_builtins (void) +{ + int char16_type_size; + int char32_type_size; + int wchar_type_size; + tree array_domain_type; + tree va_list_ref_type_node; + tree va_list_arg_type_node; + + /* Define `int' and `char' first so that dbx will output them first. */ + record_builtin_type (RID_INT, NULL, integer_type_node); + record_builtin_type (RID_CHAR, "char", char_type_node); + + /* `signed' is the same as `int'. FIXME: the declarations of "signed", + "unsigned long", "long long unsigned" and "unsigned short" were in C++ + but not C. Are the conditionals here needed? */ + if (c_dialect_cxx ()) + record_builtin_type (RID_SIGNED, NULL, integer_type_node); + record_builtin_type (RID_LONG, "long int", long_integer_type_node); + record_builtin_type (RID_UNSIGNED, "unsigned int", unsigned_type_node); + record_builtin_type (RID_MAX, "long unsigned int", + long_unsigned_type_node); + if (int128_integer_type_node != NULL_TREE) + { + record_builtin_type (RID_INT128, "__int128", + int128_integer_type_node); + record_builtin_type (RID_MAX, "__int128 unsigned", + int128_unsigned_type_node); + } + if (c_dialect_cxx ()) + record_builtin_type (RID_MAX, "unsigned long", long_unsigned_type_node); + record_builtin_type (RID_MAX, "long long int", + long_long_integer_type_node); + record_builtin_type (RID_MAX, "long long unsigned int", + long_long_unsigned_type_node); + if (c_dialect_cxx ()) + record_builtin_type (RID_MAX, "long long unsigned", + long_long_unsigned_type_node); + record_builtin_type (RID_SHORT, "short int", short_integer_type_node); + record_builtin_type (RID_MAX, "short unsigned int", + short_unsigned_type_node); + if (c_dialect_cxx ()) + record_builtin_type (RID_MAX, "unsigned short", + short_unsigned_type_node); + + /* Define both `signed char' and `unsigned char'. */ + record_builtin_type (RID_MAX, "signed char", signed_char_type_node); + record_builtin_type (RID_MAX, "unsigned char", unsigned_char_type_node); + + /* These are types that c_common_type_for_size and + c_common_type_for_mode use. */ + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, NULL_TREE, + intQI_type_node)); + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, NULL_TREE, + intHI_type_node)); + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, NULL_TREE, + intSI_type_node)); + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, NULL_TREE, + intDI_type_node)); +#if HOST_BITS_PER_WIDE_INT >= 64 + if (targetm.scalar_mode_supported_p (TImode)) + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, + get_identifier ("__int128_t"), + intTI_type_node)); +#endif + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, NULL_TREE, + unsigned_intQI_type_node)); + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, NULL_TREE, + unsigned_intHI_type_node)); + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, NULL_TREE, + unsigned_intSI_type_node)); + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, NULL_TREE, + unsigned_intDI_type_node)); +#if HOST_BITS_PER_WIDE_INT >= 64 + if (targetm.scalar_mode_supported_p (TImode)) + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, + get_identifier ("__uint128_t"), + unsigned_intTI_type_node)); +#endif + + /* Create the widest literal types. */ + widest_integer_literal_type_node + = make_signed_type (HOST_BITS_PER_WIDE_INT * 2); + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, NULL_TREE, + widest_integer_literal_type_node)); + + widest_unsigned_literal_type_node + = make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2); + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, NULL_TREE, + widest_unsigned_literal_type_node)); + + /* `unsigned long' is the standard type for sizeof. + Note that stddef.h uses `unsigned long', + and this must agree, even if long and int are the same size. */ + size_type_node = + TREE_TYPE (identifier_global_value (get_identifier (SIZE_TYPE))); + signed_size_type_node = c_common_signed_type (size_type_node); + set_sizetype (size_type_node); + + pid_type_node = + TREE_TYPE (identifier_global_value (get_identifier (PID_TYPE))); + + build_common_tree_nodes_2 (flag_short_double); + + record_builtin_type (RID_FLOAT, NULL, float_type_node); + record_builtin_type (RID_DOUBLE, NULL, double_type_node); + record_builtin_type (RID_MAX, "long double", long_double_type_node); + + /* Only supported decimal floating point extension if the target + actually supports underlying modes. */ + if (targetm.scalar_mode_supported_p (SDmode) + && targetm.scalar_mode_supported_p (DDmode) + && targetm.scalar_mode_supported_p (TDmode)) + { + record_builtin_type (RID_DFLOAT32, NULL, dfloat32_type_node); + record_builtin_type (RID_DFLOAT64, NULL, dfloat64_type_node); + record_builtin_type (RID_DFLOAT128, NULL, dfloat128_type_node); + } + + if (targetm.fixed_point_supported_p ()) + { + record_builtin_type (RID_MAX, "short _Fract", short_fract_type_node); + record_builtin_type (RID_FRACT, NULL, fract_type_node); + record_builtin_type (RID_MAX, "long _Fract", long_fract_type_node); + record_builtin_type (RID_MAX, "long long _Fract", + long_long_fract_type_node); + record_builtin_type (RID_MAX, "unsigned short _Fract", + unsigned_short_fract_type_node); + record_builtin_type (RID_MAX, "unsigned _Fract", + unsigned_fract_type_node); + record_builtin_type (RID_MAX, "unsigned long _Fract", + unsigned_long_fract_type_node); + record_builtin_type (RID_MAX, "unsigned long long _Fract", + unsigned_long_long_fract_type_node); + record_builtin_type (RID_MAX, "_Sat short _Fract", + sat_short_fract_type_node); + record_builtin_type (RID_MAX, "_Sat _Fract", sat_fract_type_node); + record_builtin_type (RID_MAX, "_Sat long _Fract", + sat_long_fract_type_node); + record_builtin_type (RID_MAX, "_Sat long long _Fract", + sat_long_long_fract_type_node); + record_builtin_type (RID_MAX, "_Sat unsigned short _Fract", + sat_unsigned_short_fract_type_node); + record_builtin_type (RID_MAX, "_Sat unsigned _Fract", + sat_unsigned_fract_type_node); + record_builtin_type (RID_MAX, "_Sat unsigned long _Fract", + sat_unsigned_long_fract_type_node); + record_builtin_type (RID_MAX, "_Sat unsigned long long _Fract", + sat_unsigned_long_long_fract_type_node); + record_builtin_type (RID_MAX, "short _Accum", short_accum_type_node); + record_builtin_type (RID_ACCUM, NULL, accum_type_node); + record_builtin_type (RID_MAX, "long _Accum", long_accum_type_node); + record_builtin_type (RID_MAX, "long long _Accum", + long_long_accum_type_node); + record_builtin_type (RID_MAX, "unsigned short _Accum", + unsigned_short_accum_type_node); + record_builtin_type (RID_MAX, "unsigned _Accum", + unsigned_accum_type_node); + record_builtin_type (RID_MAX, "unsigned long _Accum", + unsigned_long_accum_type_node); + record_builtin_type (RID_MAX, "unsigned long long _Accum", + unsigned_long_long_accum_type_node); + record_builtin_type (RID_MAX, "_Sat short _Accum", + sat_short_accum_type_node); + record_builtin_type (RID_MAX, "_Sat _Accum", sat_accum_type_node); + record_builtin_type (RID_MAX, "_Sat long _Accum", + sat_long_accum_type_node); + record_builtin_type (RID_MAX, "_Sat long long _Accum", + sat_long_long_accum_type_node); + record_builtin_type (RID_MAX, "_Sat unsigned short _Accum", + sat_unsigned_short_accum_type_node); + record_builtin_type (RID_MAX, "_Sat unsigned _Accum", + sat_unsigned_accum_type_node); + record_builtin_type (RID_MAX, "_Sat unsigned long _Accum", + sat_unsigned_long_accum_type_node); + record_builtin_type (RID_MAX, "_Sat unsigned long long _Accum", + sat_unsigned_long_long_accum_type_node); + + } + + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, + get_identifier ("complex int"), + complex_integer_type_node)); + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, + get_identifier ("complex float"), + complex_float_type_node)); + lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, + get_identifier ("complex double"), + complex_double_type_node)); + lang_hooks.decls.pushdecl + (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, get_identifier ("complex long double"), + complex_long_double_type_node)); + + if (c_dialect_cxx ()) + /* For C++, make fileptr_type_node a distinct void * type until + FILE type is defined. */ + fileptr_type_node = build_variant_type_copy (ptr_type_node); + + record_builtin_type (RID_VOID, NULL, void_type_node); + + /* Set the TYPE_NAME for any variants that were built before + record_builtin_type gave names to the built-in types. */ + { + tree void_name = TYPE_NAME (void_type_node); + TYPE_NAME (void_type_node) = NULL_TREE; + TYPE_NAME (build_qualified_type (void_type_node, TYPE_QUAL_CONST)) + = void_name; + TYPE_NAME (void_type_node) = void_name; + } + + /* This node must not be shared. */ + void_zero_node = make_node (INTEGER_CST); + TREE_TYPE (void_zero_node) = void_type_node; + + void_list_node = build_void_list_node (); + + /* Make a type to be the domain of a few array types + whose domains don't really matter. + 200 is small enough that it always fits in size_t + and large enough that it can hold most function names for the + initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */ + array_domain_type = build_index_type (size_int (200)); + + /* Make a type for arrays of characters. + With luck nothing will ever really depend on the length of this + array type. */ + char_array_type_node + = build_array_type (char_type_node, array_domain_type); + + /* Likewise for arrays of ints. */ + int_array_type_node + = build_array_type (integer_type_node, array_domain_type); + + string_type_node = build_pointer_type (char_type_node); + const_string_type_node + = build_pointer_type (build_qualified_type + (char_type_node, TYPE_QUAL_CONST)); + + /* This is special for C++ so functions can be overloaded. */ + wchar_type_node = get_identifier (MODIFIED_WCHAR_TYPE); + wchar_type_node = TREE_TYPE (identifier_global_value (wchar_type_node)); + wchar_type_size = TYPE_PRECISION (wchar_type_node); + underlying_wchar_type_node = wchar_type_node; + if (c_dialect_cxx ()) + { + if (TYPE_UNSIGNED (wchar_type_node)) + wchar_type_node = make_unsigned_type (wchar_type_size); + else + wchar_type_node = make_signed_type (wchar_type_size); + record_builtin_type (RID_WCHAR, "wchar_t", wchar_type_node); + } + + /* This is for wide string constants. */ + wchar_array_type_node + = build_array_type (wchar_type_node, array_domain_type); + + /* Define 'char16_t'. */ + char16_type_node = get_identifier (CHAR16_TYPE); + char16_type_node = TREE_TYPE (identifier_global_value (char16_type_node)); + char16_type_size = TYPE_PRECISION (char16_type_node); + if (c_dialect_cxx ()) + { + char16_type_node = make_unsigned_type (char16_type_size); + + if (cxx_dialect == cxx0x) + record_builtin_type (RID_CHAR16, "char16_t", char16_type_node); + } + + /* This is for UTF-16 string constants. */ + char16_array_type_node + = build_array_type (char16_type_node, array_domain_type); + + /* Define 'char32_t'. */ + char32_type_node = get_identifier (CHAR32_TYPE); + char32_type_node = TREE_TYPE (identifier_global_value (char32_type_node)); + char32_type_size = TYPE_PRECISION (char32_type_node); + if (c_dialect_cxx ()) + { + char32_type_node = make_unsigned_type (char32_type_size); + + if (cxx_dialect == cxx0x) + record_builtin_type (RID_CHAR32, "char32_t", char32_type_node); + } + + /* This is for UTF-32 string constants. */ + char32_array_type_node + = build_array_type (char32_type_node, array_domain_type); + + wint_type_node = + TREE_TYPE (identifier_global_value (get_identifier (WINT_TYPE))); + + intmax_type_node = + TREE_TYPE (identifier_global_value (get_identifier (INTMAX_TYPE))); + uintmax_type_node = + TREE_TYPE (identifier_global_value (get_identifier (UINTMAX_TYPE))); + + if (SIG_ATOMIC_TYPE) + sig_atomic_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (SIG_ATOMIC_TYPE))); + if (INT8_TYPE) + int8_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT8_TYPE))); + if (INT16_TYPE) + int16_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT16_TYPE))); + if (INT32_TYPE) + int32_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT32_TYPE))); + if (INT64_TYPE) + int64_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT64_TYPE))); + if (UINT8_TYPE) + uint8_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT8_TYPE))); + if (UINT16_TYPE) + uint16_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT16_TYPE))); + if (UINT32_TYPE) + c_uint32_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT32_TYPE))); + if (UINT64_TYPE) + c_uint64_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT64_TYPE))); + if (INT_LEAST8_TYPE) + int_least8_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST8_TYPE))); + if (INT_LEAST16_TYPE) + int_least16_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST16_TYPE))); + if (INT_LEAST32_TYPE) + int_least32_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST32_TYPE))); + if (INT_LEAST64_TYPE) + int_least64_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST64_TYPE))); + if (UINT_LEAST8_TYPE) + uint_least8_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST8_TYPE))); + if (UINT_LEAST16_TYPE) + uint_least16_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST16_TYPE))); + if (UINT_LEAST32_TYPE) + uint_least32_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST32_TYPE))); + if (UINT_LEAST64_TYPE) + uint_least64_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST64_TYPE))); + if (INT_FAST8_TYPE) + int_fast8_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST8_TYPE))); + if (INT_FAST16_TYPE) + int_fast16_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST16_TYPE))); + if (INT_FAST32_TYPE) + int_fast32_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST32_TYPE))); + if (INT_FAST64_TYPE) + int_fast64_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST64_TYPE))); + if (UINT_FAST8_TYPE) + uint_fast8_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST8_TYPE))); + if (UINT_FAST16_TYPE) + uint_fast16_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST16_TYPE))); + if (UINT_FAST32_TYPE) + uint_fast32_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST32_TYPE))); + if (UINT_FAST64_TYPE) + uint_fast64_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST64_TYPE))); + if (INTPTR_TYPE) + intptr_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (INTPTR_TYPE))); + if (UINTPTR_TYPE) + uintptr_type_node = + TREE_TYPE (identifier_global_value (c_get_ident (UINTPTR_TYPE))); + + default_function_type = build_function_type (integer_type_node, NULL_TREE); + ptrdiff_type_node + = TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE))); + unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node); + + lang_hooks.decls.pushdecl + (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, get_identifier ("__builtin_va_list"), + va_list_type_node)); + if (targetm.enum_va_list) + { + int l; + const char *pname; + tree ptype; + + for (l = 0; targetm.enum_va_list (l, &pname, &ptype); ++l) + { + lang_hooks.decls.pushdecl + (build_decl (UNKNOWN_LOCATION, + TYPE_DECL, get_identifier (pname), + ptype)); + + } + } + + if (TREE_CODE (va_list_type_node) == ARRAY_TYPE) + { + va_list_arg_type_node = va_list_ref_type_node = + build_pointer_type (TREE_TYPE (va_list_type_node)); + } + else + { + va_list_arg_type_node = va_list_type_node; + va_list_ref_type_node = build_reference_type (va_list_type_node); + } + + if (!flag_preprocess_only) + c_define_builtins (va_list_ref_type_node, va_list_arg_type_node); + + main_identifier_node = get_identifier ("main"); + + /* Create the built-in __null node. It is important that this is + not shared. */ + null_node = make_node (INTEGER_CST); + TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0); + + /* Since builtin_types isn't gc'ed, don't export these nodes. */ + memset (builtin_types, 0, sizeof (builtin_types)); +} + +/* The number of named compound-literals generated thus far. */ +static GTY(()) int compound_literal_number; + +/* Set DECL_NAME for DECL, a VAR_DECL for a compound-literal. */ + +void +set_compound_literal_name (tree decl) +{ + char *name; + ASM_FORMAT_PRIVATE_NAME (name, "__compound_literal", + compound_literal_number); + compound_literal_number++; + DECL_NAME (decl) = get_identifier (name); +} + +tree +build_va_arg (location_t loc, tree expr, tree type) +{ + expr = build1 (VA_ARG_EXPR, type, expr); + SET_EXPR_LOCATION (expr, loc); + return expr; +} + + +/* Linked list of disabled built-in functions. */ + +typedef struct disabled_builtin +{ + const char *name; + struct disabled_builtin *next; +} disabled_builtin; +static disabled_builtin *disabled_builtins = NULL; + +static bool builtin_function_disabled_p (const char *); + +/* Disable a built-in function specified by -fno-builtin-NAME. If NAME + begins with "__builtin_", give an error. */ + +void +disable_builtin_function (const char *name) +{ + if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0) + error ("cannot disable built-in function %qs", name); + else + { + disabled_builtin *new_disabled_builtin = XNEW (disabled_builtin); + new_disabled_builtin->name = name; + new_disabled_builtin->next = disabled_builtins; + disabled_builtins = new_disabled_builtin; + } +} + + +/* Return true if the built-in function NAME has been disabled, false + otherwise. */ + +static bool +builtin_function_disabled_p (const char *name) +{ + disabled_builtin *p; + for (p = disabled_builtins; p != NULL; p = p->next) + { + if (strcmp (name, p->name) == 0) + return true; + } + return false; +} + + +/* Worker for DEF_BUILTIN. + Possibly define a builtin function with one or two names. + Does not declare a non-__builtin_ function if flag_no_builtin, or if + nonansi_p and flag_no_nonansi_builtin. */ + +static void +def_builtin_1 (enum built_in_function fncode, + const char *name, + enum built_in_class fnclass, + tree fntype, tree libtype, + bool both_p, bool fallback_p, bool nonansi_p, + tree fnattrs, bool implicit_p) +{ + tree decl; + const char *libname; + + if (fntype == error_mark_node) + return; + + gcc_assert ((!both_p && !fallback_p) + || !strncmp (name, "__builtin_", + strlen ("__builtin_"))); + + libname = name + strlen ("__builtin_"); + decl = add_builtin_function (name, fntype, fncode, fnclass, + (fallback_p ? libname : NULL), + fnattrs); + if (both_p + && !flag_no_builtin && !builtin_function_disabled_p (libname) + && !(nonansi_p && flag_no_nonansi_builtin)) + add_builtin_function (libname, libtype, fncode, fnclass, + NULL, fnattrs); + + built_in_decls[(int) fncode] = decl; + if (implicit_p) + implicit_built_in_decls[(int) fncode] = decl; +} + +/* Nonzero if the type T promotes to int. This is (nearly) the + integral promotions defined in ISO C99 6.3.1.1/2. */ + +bool +c_promoting_integer_type_p (const_tree t) +{ + switch (TREE_CODE (t)) + { + case INTEGER_TYPE: + return (TYPE_MAIN_VARIANT (t) == char_type_node + || TYPE_MAIN_VARIANT (t) == signed_char_type_node + || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node + || TYPE_MAIN_VARIANT (t) == short_integer_type_node + || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node + || TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node)); + + case ENUMERAL_TYPE: + /* ??? Technically all enumerations not larger than an int + promote to an int. But this is used along code paths + that only want to notice a size change. */ + return TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node); + + case BOOLEAN_TYPE: + return 1; + + default: + return 0; + } +} + +/* Return 1 if PARMS specifies a fixed number of parameters + and none of their types is affected by default promotions. */ + +int +self_promoting_args_p (const_tree parms) +{ + const_tree t; + for (t = parms; t; t = TREE_CHAIN (t)) + { + tree type = TREE_VALUE (t); + + if (type == error_mark_node) + continue; + + if (TREE_CHAIN (t) == 0 && type != void_type_node) + return 0; + + if (type == 0) + return 0; + + if (TYPE_MAIN_VARIANT (type) == float_type_node) + return 0; + + if (c_promoting_integer_type_p (type)) + return 0; + } + return 1; +} + +/* Recursively remove any '*' or '&' operator from TYPE. */ +tree +strip_pointer_operator (tree t) +{ + while (POINTER_TYPE_P (t)) + t = TREE_TYPE (t); + return t; +} + +/* Recursively remove pointer or array type from TYPE. */ +tree +strip_pointer_or_array_types (tree t) +{ + while (TREE_CODE (t) == ARRAY_TYPE || POINTER_TYPE_P (t)) + t = TREE_TYPE (t); + return t; +} + +/* Used to compare case labels. K1 and K2 are actually tree nodes + representing case labels, or NULL_TREE for a `default' label. + Returns -1 if K1 is ordered before K2, -1 if K1 is ordered after + K2, and 0 if K1 and K2 are equal. */ + +int +case_compare (splay_tree_key k1, splay_tree_key k2) +{ + /* Consider a NULL key (such as arises with a `default' label) to be + smaller than anything else. */ + if (!k1) + return k2 ? -1 : 0; + else if (!k2) + return k1 ? 1 : 0; + + return tree_int_cst_compare ((tree) k1, (tree) k2); +} + +/* Process a case label, located at LOC, for the range LOW_VALUE + ... HIGH_VALUE. If LOW_VALUE and HIGH_VALUE are both NULL_TREE + then this case label is actually a `default' label. If only + HIGH_VALUE is NULL_TREE, then case label was declared using the + usual C/C++ syntax, rather than the GNU case range extension. + CASES is a tree containing all the case ranges processed so far; + COND is the condition for the switch-statement itself. Returns the + CASE_LABEL_EXPR created, or ERROR_MARK_NODE if no CASE_LABEL_EXPR + is created. */ + +tree +c_add_case_label (location_t loc, splay_tree cases, tree cond, tree orig_type, + tree low_value, tree high_value) +{ + tree type; + tree label; + tree case_label; + splay_tree_node node; + + /* Create the LABEL_DECL itself. */ + label = create_artificial_label (loc); + + /* If there was an error processing the switch condition, bail now + before we get more confused. */ + if (!cond || cond == error_mark_node) + goto error_out; + + if ((low_value && TREE_TYPE (low_value) + && POINTER_TYPE_P (TREE_TYPE (low_value))) + || (high_value && TREE_TYPE (high_value) + && POINTER_TYPE_P (TREE_TYPE (high_value)))) + { + error_at (loc, "pointers are not permitted as case values"); + goto error_out; + } + + /* Case ranges are a GNU extension. */ + if (high_value) + pedwarn (loc, OPT_pedantic, + "range expressions in switch statements are non-standard"); + + type = TREE_TYPE (cond); + if (low_value) + { + low_value = check_case_value (low_value); + low_value = convert_and_check (type, low_value); + if (low_value == error_mark_node) + goto error_out; + } + if (high_value) + { + high_value = check_case_value (high_value); + high_value = convert_and_check (type, high_value); + if (high_value == error_mark_node) + goto error_out; + } + + if (low_value && high_value) + { + /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't + really a case range, even though it was written that way. + Remove the HIGH_VALUE to simplify later processing. */ + if (tree_int_cst_equal (low_value, high_value)) + high_value = NULL_TREE; + else if (!tree_int_cst_lt (low_value, high_value)) + warning_at (loc, 0, "empty range specified"); + } + + /* See if the case is in range of the type of the original testing + expression. If both low_value and high_value are out of range, + don't insert the case label and return NULL_TREE. */ + if (low_value + && !check_case_bounds (type, orig_type, + &low_value, high_value ? &high_value : NULL)) + return NULL_TREE; + + /* Look up the LOW_VALUE in the table of case labels we already + have. */ + node = splay_tree_lookup (cases, (splay_tree_key) low_value); + /* If there was not an exact match, check for overlapping ranges. + There's no need to do this if there's no LOW_VALUE or HIGH_VALUE; + that's a `default' label and the only overlap is an exact match. */ + if (!node && (low_value || high_value)) + { + splay_tree_node low_bound; + splay_tree_node high_bound; + + /* Even though there wasn't an exact match, there might be an + overlap between this case range and another case range. + Since we've (inductively) not allowed any overlapping case + ranges, we simply need to find the greatest low case label + that is smaller that LOW_VALUE, and the smallest low case + label that is greater than LOW_VALUE. If there is an overlap + it will occur in one of these two ranges. */ + low_bound = splay_tree_predecessor (cases, + (splay_tree_key) low_value); + high_bound = splay_tree_successor (cases, + (splay_tree_key) low_value); + + /* Check to see if the LOW_BOUND overlaps. It is smaller than + the LOW_VALUE, so there is no need to check unless the + LOW_BOUND is in fact itself a case range. */ + if (low_bound + && CASE_HIGH ((tree) low_bound->value) + && tree_int_cst_compare (CASE_HIGH ((tree) low_bound->value), + low_value) >= 0) + node = low_bound; + /* Check to see if the HIGH_BOUND overlaps. The low end of that + range is bigger than the low end of the current range, so we + are only interested if the current range is a real range, and + not an ordinary case label. */ + else if (high_bound + && high_value + && (tree_int_cst_compare ((tree) high_bound->key, + high_value) + <= 0)) + node = high_bound; + } + /* If there was an overlap, issue an error. */ + if (node) + { + tree duplicate = CASE_LABEL ((tree) node->value); + + if (high_value) + { + error_at (loc, "duplicate (or overlapping) case value"); + error_at (DECL_SOURCE_LOCATION (duplicate), + "this is the first entry overlapping that value"); + } + else if (low_value) + { + error_at (loc, "duplicate case value") ; + error_at (DECL_SOURCE_LOCATION (duplicate), "previously used here"); + } + else + { + error_at (loc, "multiple default labels in one switch"); + error_at (DECL_SOURCE_LOCATION (duplicate), + "this is the first default label"); + } + goto error_out; + } + + /* Add a CASE_LABEL to the statement-tree. */ + case_label = add_stmt (build_case_label (loc, low_value, high_value, label)); + /* Register this case label in the splay tree. */ + splay_tree_insert (cases, + (splay_tree_key) low_value, + (splay_tree_value) case_label); + + return case_label; + + error_out: + /* Add a label so that the back-end doesn't think that the beginning of + the switch is unreachable. Note that we do not add a case label, as + that just leads to duplicates and thence to failure later on. */ + if (!cases->root) + { + tree t = create_artificial_label (loc); + add_stmt (build_stmt (loc, LABEL_EXPR, t)); + } + return error_mark_node; +} + +/* Subroutines of c_do_switch_warnings, called via splay_tree_foreach. + Used to verify that case values match up with enumerator values. */ + +static void +match_case_to_enum_1 (tree key, tree type, tree label) +{ + char buf[2 + 2*HOST_BITS_PER_WIDE_INT/4 + 1]; + + /* ??? Not working too hard to print the double-word value. + Should perhaps be done with %lwd in the diagnostic routines? */ + if (TREE_INT_CST_HIGH (key) == 0) + snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_UNSIGNED, + TREE_INT_CST_LOW (key)); + else if (!TYPE_UNSIGNED (type) + && TREE_INT_CST_HIGH (key) == -1 + && TREE_INT_CST_LOW (key) != 0) + snprintf (buf, sizeof (buf), "-" HOST_WIDE_INT_PRINT_UNSIGNED, + -TREE_INT_CST_LOW (key)); + else + snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_DOUBLE_HEX, + (unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (key), + (unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (key)); + + if (TYPE_NAME (type) == 0) + warning_at (DECL_SOURCE_LOCATION (CASE_LABEL (label)), + warn_switch ? OPT_Wswitch : OPT_Wswitch_enum, + "case value %qs not in enumerated type", + buf); + else + warning_at (DECL_SOURCE_LOCATION (CASE_LABEL (label)), + warn_switch ? OPT_Wswitch : OPT_Wswitch_enum, + "case value %qs not in enumerated type %qT", + buf, type); +} + +/* Subroutine of c_do_switch_warnings, called via splay_tree_foreach. + Used to verify that case values match up with enumerator values. */ + +static int +match_case_to_enum (splay_tree_node node, void *data) +{ + tree label = (tree) node->value; + tree type = (tree) data; + + /* Skip default case. */ + if (!CASE_LOW (label)) + return 0; + + /* If CASE_LOW_SEEN is not set, that means CASE_LOW did not appear + when we did our enum->case scan. Reset our scratch bit after. */ + if (!CASE_LOW_SEEN (label)) + match_case_to_enum_1 (CASE_LOW (label), type, label); + else + CASE_LOW_SEEN (label) = 0; + + /* If CASE_HIGH is non-null, we have a range. If CASE_HIGH_SEEN is + not set, that means that CASE_HIGH did not appear when we did our + enum->case scan. Reset our scratch bit after. */ + if (CASE_HIGH (label)) + { + if (!CASE_HIGH_SEEN (label)) + match_case_to_enum_1 (CASE_HIGH (label), type, label); + else + CASE_HIGH_SEEN (label) = 0; + } + + return 0; +} + +/* Handle -Wswitch*. Called from the front end after parsing the + switch construct. */ +/* ??? Should probably be somewhere generic, since other languages + besides C and C++ would want this. At the moment, however, C/C++ + are the only tree-ssa languages that support enumerations at all, + so the point is moot. */ + +void +c_do_switch_warnings (splay_tree cases, location_t switch_location, + tree type, tree cond) +{ + splay_tree_node default_node; + splay_tree_node node; + tree chain; + + if (!warn_switch && !warn_switch_enum && !warn_switch_default) + return; + + default_node = splay_tree_lookup (cases, (splay_tree_key) NULL); + if (!default_node) + warning_at (switch_location, OPT_Wswitch_default, + "switch missing default case"); + + /* From here on, we only care about about enumerated types. */ + if (!type || TREE_CODE (type) != ENUMERAL_TYPE) + return; + + /* From here on, we only care about -Wswitch and -Wswitch-enum. */ + if (!warn_switch_enum && !warn_switch) + return; + + /* Check the cases. Warn about case values which are not members of + the enumerated type. For -Wswitch-enum, or for -Wswitch when + there is no default case, check that exactly all enumeration + literals are covered by the cases. */ + + /* Clearing COND if it is not an integer constant simplifies + the tests inside the loop below. */ + if (TREE_CODE (cond) != INTEGER_CST) + cond = NULL_TREE; + + /* The time complexity here is O(N*lg(N)) worst case, but for the + common case of monotonically increasing enumerators, it is + O(N), since the nature of the splay tree will keep the next + element adjacent to the root at all times. */ + + for (chain = TYPE_VALUES (type); chain; chain = TREE_CHAIN (chain)) + { + tree value = TREE_VALUE (chain); + if (TREE_CODE (value) == CONST_DECL) + value = DECL_INITIAL (value); + node = splay_tree_lookup (cases, (splay_tree_key) value); + if (node) + { + /* Mark the CASE_LOW part of the case entry as seen. */ + tree label = (tree) node->value; + CASE_LOW_SEEN (label) = 1; + continue; + } + + /* Even though there wasn't an exact match, there might be a + case range which includes the enumerator's value. */ + node = splay_tree_predecessor (cases, (splay_tree_key) value); + if (node && CASE_HIGH ((tree) node->value)) + { + tree label = (tree) node->value; + int cmp = tree_int_cst_compare (CASE_HIGH (label), value); + if (cmp >= 0) + { + /* If we match the upper bound exactly, mark the CASE_HIGH + part of the case entry as seen. */ + if (cmp == 0) + CASE_HIGH_SEEN (label) = 1; + continue; + } + } + + /* We've now determined that this enumerated literal isn't + handled by the case labels of the switch statement. */ + + /* If the switch expression is a constant, we only really care + about whether that constant is handled by the switch. */ + if (cond && tree_int_cst_compare (cond, value)) + continue; + + /* If there is a default_node, the only relevant option is + Wswitch-enum. Otherwise, if both are enabled then we prefer + to warn using -Wswitch because -Wswitch is enabled by -Wall + while -Wswitch-enum is explicit. */ + warning_at (switch_location, + (default_node || !warn_switch + ? OPT_Wswitch_enum + : OPT_Wswitch), + "enumeration value %qE not handled in switch", + TREE_PURPOSE (chain)); + } + + /* Warn if there are case expressions that don't correspond to + enumerators. This can occur since C and C++ don't enforce + type-checking of assignments to enumeration variables. + + The time complexity here is now always O(N) worst case, since + we should have marked both the lower bound and upper bound of + every disjoint case label, with CASE_LOW_SEEN and CASE_HIGH_SEEN + above. This scan also resets those fields. */ + + splay_tree_foreach (cases, match_case_to_enum, type); +} + +/* Finish an expression taking the address of LABEL (an + IDENTIFIER_NODE). Returns an expression for the address. + + LOC is the location for the expression returned. */ + +tree +finish_label_address_expr (tree label, location_t loc) +{ + tree result; + + pedwarn (input_location, OPT_pedantic, "taking the address of a label is non-standard"); + + if (label == error_mark_node) + return error_mark_node; + + label = lookup_label (label); + if (label == NULL_TREE) + result = null_pointer_node; + else + { + TREE_USED (label) = 1; + result = build1 (ADDR_EXPR, ptr_type_node, label); + /* The current function is not necessarily uninlinable. + Computed gotos are incompatible with inlining, but the value + here could be used only in a diagnostic, for example. */ + protected_set_expr_location (result, loc); + } + + return result; +} + + +/* Given a boolean expression ARG, return a tree representing an increment + or decrement (as indicated by CODE) of ARG. The front end must check for + invalid cases (e.g., decrement in C++). */ +tree +boolean_increment (enum tree_code code, tree arg) +{ + tree val; + tree true_res = build_int_cst (TREE_TYPE (arg), 1); + + arg = stabilize_reference (arg); + switch (code) + { + case PREINCREMENT_EXPR: + val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res); + break; + case POSTINCREMENT_EXPR: + val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res); + arg = save_expr (arg); + val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg); + val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val); + break; + case PREDECREMENT_EXPR: + val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, + invert_truthvalue_loc (input_location, arg)); + break; + case POSTDECREMENT_EXPR: + val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, + invert_truthvalue_loc (input_location, arg)); + arg = save_expr (arg); + val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg); + val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val); + break; + default: + gcc_unreachable (); + } + TREE_SIDE_EFFECTS (val) = 1; + return val; +} + +/* Built-in macros for stddef.h and stdint.h, that require macros + defined in this file. */ +void +c_stddef_cpp_builtins(void) +{ + builtin_define_with_value ("__SIZE_TYPE__", SIZE_TYPE, 0); + builtin_define_with_value ("__PTRDIFF_TYPE__", PTRDIFF_TYPE, 0); + builtin_define_with_value ("__WCHAR_TYPE__", MODIFIED_WCHAR_TYPE, 0); + builtin_define_with_value ("__WINT_TYPE__", WINT_TYPE, 0); + builtin_define_with_value ("__INTMAX_TYPE__", INTMAX_TYPE, 0); + builtin_define_with_value ("__UINTMAX_TYPE__", UINTMAX_TYPE, 0); + builtin_define_with_value ("__CHAR16_TYPE__", CHAR16_TYPE, 0); + builtin_define_with_value ("__CHAR32_TYPE__", CHAR32_TYPE, 0); + if (SIG_ATOMIC_TYPE) + builtin_define_with_value ("__SIG_ATOMIC_TYPE__", SIG_ATOMIC_TYPE, 0); + if (INT8_TYPE) + builtin_define_with_value ("__INT8_TYPE__", INT8_TYPE, 0); + if (INT16_TYPE) + builtin_define_with_value ("__INT16_TYPE__", INT16_TYPE, 0); + if (INT32_TYPE) + builtin_define_with_value ("__INT32_TYPE__", INT32_TYPE, 0); + if (INT64_TYPE) + builtin_define_with_value ("__INT64_TYPE__", INT64_TYPE, 0); + if (UINT8_TYPE) + builtin_define_with_value ("__UINT8_TYPE__", UINT8_TYPE, 0); + if (UINT16_TYPE) + builtin_define_with_value ("__UINT16_TYPE__", UINT16_TYPE, 0); + if (UINT32_TYPE) + builtin_define_with_value ("__UINT32_TYPE__", UINT32_TYPE, 0); + if (UINT64_TYPE) + builtin_define_with_value ("__UINT64_TYPE__", UINT64_TYPE, 0); + if (INT_LEAST8_TYPE) + builtin_define_with_value ("__INT_LEAST8_TYPE__", INT_LEAST8_TYPE, 0); + if (INT_LEAST16_TYPE) + builtin_define_with_value ("__INT_LEAST16_TYPE__", INT_LEAST16_TYPE, 0); + if (INT_LEAST32_TYPE) + builtin_define_with_value ("__INT_LEAST32_TYPE__", INT_LEAST32_TYPE, 0); + if (INT_LEAST64_TYPE) + builtin_define_with_value ("__INT_LEAST64_TYPE__", INT_LEAST64_TYPE, 0); + if (UINT_LEAST8_TYPE) + builtin_define_with_value ("__UINT_LEAST8_TYPE__", UINT_LEAST8_TYPE, 0); + if (UINT_LEAST16_TYPE) + builtin_define_with_value ("__UINT_LEAST16_TYPE__", UINT_LEAST16_TYPE, 0); + if (UINT_LEAST32_TYPE) + builtin_define_with_value ("__UINT_LEAST32_TYPE__", UINT_LEAST32_TYPE, 0); + if (UINT_LEAST64_TYPE) + builtin_define_with_value ("__UINT_LEAST64_TYPE__", UINT_LEAST64_TYPE, 0); + if (INT_FAST8_TYPE) + builtin_define_with_value ("__INT_FAST8_TYPE__", INT_FAST8_TYPE, 0); + if (INT_FAST16_TYPE) + builtin_define_with_value ("__INT_FAST16_TYPE__", INT_FAST16_TYPE, 0); + if (INT_FAST32_TYPE) + builtin_define_with_value ("__INT_FAST32_TYPE__", INT_FAST32_TYPE, 0); + if (INT_FAST64_TYPE) + builtin_define_with_value ("__INT_FAST64_TYPE__", INT_FAST64_TYPE, 0); + if (UINT_FAST8_TYPE) + builtin_define_with_value ("__UINT_FAST8_TYPE__", UINT_FAST8_TYPE, 0); + if (UINT_FAST16_TYPE) + builtin_define_with_value ("__UINT_FAST16_TYPE__", UINT_FAST16_TYPE, 0); + if (UINT_FAST32_TYPE) + builtin_define_with_value ("__UINT_FAST32_TYPE__", UINT_FAST32_TYPE, 0); + if (UINT_FAST64_TYPE) + builtin_define_with_value ("__UINT_FAST64_TYPE__", UINT_FAST64_TYPE, 0); + if (INTPTR_TYPE) + builtin_define_with_value ("__INTPTR_TYPE__", INTPTR_TYPE, 0); + if (UINTPTR_TYPE) + builtin_define_with_value ("__UINTPTR_TYPE__", UINTPTR_TYPE, 0); +} + +static void +c_init_attributes (void) +{ + /* Fill in the built_in_attributes array. */ +#define DEF_ATTR_NULL_TREE(ENUM) \ + built_in_attributes[(int) ENUM] = NULL_TREE; +#define DEF_ATTR_INT(ENUM, VALUE) \ + built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE); +#define DEF_ATTR_IDENT(ENUM, STRING) \ + built_in_attributes[(int) ENUM] = get_identifier (STRING); +#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \ + built_in_attributes[(int) ENUM] \ + = tree_cons (built_in_attributes[(int) PURPOSE], \ + built_in_attributes[(int) VALUE], \ + built_in_attributes[(int) CHAIN]); +#include "builtin-attrs.def" +#undef DEF_ATTR_NULL_TREE +#undef DEF_ATTR_INT +#undef DEF_ATTR_IDENT +#undef DEF_ATTR_TREE_LIST +} + +/* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain + identifier as an argument, so the front end shouldn't look it up. */ + +bool +attribute_takes_identifier_p (const_tree attr_id) +{ + if (is_attribute_p ("mode", attr_id) + || is_attribute_p ("format", attr_id) + || is_attribute_p ("cleanup", attr_id)) + return true; + else + return targetm.attribute_takes_identifier_p (attr_id); +} + +/* Attribute handlers common to C front ends. */ + +/* Handle a "packed" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_packed_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int flags, bool *no_add_attrs) +{ + if (TYPE_P (*node)) + { + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + *node = build_variant_type_copy (*node); + TYPE_PACKED (*node) = 1; + } + else if (TREE_CODE (*node) == FIELD_DECL) + { + if (TYPE_ALIGN (TREE_TYPE (*node)) <= BITS_PER_UNIT + /* Still pack bitfields. */ + && ! DECL_INITIAL (*node)) + warning (OPT_Wattributes, + "%qE attribute ignored for field of type %qT", + name, TREE_TYPE (*node)); + else + DECL_PACKED (*node) = 1; + } + /* We can't set DECL_PACKED for a VAR_DECL, because the bit is + used for DECL_REGISTER. It wouldn't mean anything anyway. + We can't set DECL_PACKED on the type of a TYPE_DECL, because + that changes what the typedef is typing. */ + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "nocommon" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_nocommon_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == VAR_DECL) + DECL_COMMON (*node) = 0; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "common" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_common_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == VAR_DECL) + DECL_COMMON (*node) = 1; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "noreturn" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree type = TREE_TYPE (*node); + + /* See FIXME comment in c_common_attribute_table. */ + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_THIS_VOLATILE (*node) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) + = build_pointer_type + (build_type_variant (TREE_TYPE (type), + TYPE_READONLY (TREE_TYPE (type)), 1)); + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "hot" and attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL) + { + warning (OPT_Wattributes, "%qE attribute conflicts with attribute %s", + name, "cold"); + *no_add_attrs = true; + } + /* Most of the rest of the hot processing is done later with + lookup_attribute. */ + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} +/* Handle a "cold" and attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL) + { + warning (OPT_Wattributes, "%qE attribute conflicts with attribute %s", + name, "hot"); + *no_add_attrs = true; + } + /* Most of the rest of the cold processing is done later with + lookup_attribute. */ + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "noinline" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_noinline_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + DECL_UNINLINABLE (*node) = 1; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "noclone" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_noclone_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "always_inline" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_always_inline_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + /* Set the attribute and mark it for disregarding inline + limits. */ + DECL_DISREGARD_INLINE_LIMITS (*node) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "gnu_inline" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_gnu_inline_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (*node)) + { + /* Do nothing else, just set the attribute. We'll get at + it later with lookup_attribute. */ + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle an "artificial" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_artificial_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (*node)) + { + /* Do nothing else, just set the attribute. We'll get at + it later with lookup_attribute. */ + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "flatten" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_flatten_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + /* Do nothing else, just set the attribute. We'll get at + it later with lookup_attribute. */ + ; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "warning" or "error" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_error_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL + || TREE_CODE (TREE_VALUE (args)) == STRING_CST) + /* Do nothing else, just set the attribute. We'll get at + it later with lookup_attribute. */ + ; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "used" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree node = *pnode; + + if (TREE_CODE (node) == FUNCTION_DECL + || (TREE_CODE (node) == VAR_DECL && TREE_STATIC (node))) + { + TREE_USED (node) = 1; + DECL_PRESERVE_P (node) = 1; + if (TREE_CODE (node) == VAR_DECL) + DECL_READ_P (node) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "unused" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int flags, bool *no_add_attrs) +{ + if (DECL_P (*node)) + { + tree decl = *node; + + if (TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == LABEL_DECL + || TREE_CODE (decl) == TYPE_DECL) + { + TREE_USED (decl) = 1; + if (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL) + DECL_READ_P (decl) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + } + else + { + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + *node = build_variant_type_copy (*node); + TREE_USED (*node) = 1; + } + + return NULL_TREE; +} + +/* Handle a "externally_visible" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_externally_visible_attribute (tree *pnode, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + tree node = *pnode; + + if (TREE_CODE (node) == FUNCTION_DECL || TREE_CODE (node) == VAR_DECL) + { + if ((!TREE_STATIC (node) && TREE_CODE (node) != FUNCTION_DECL + && !DECL_EXTERNAL (node)) || !TREE_PUBLIC (node)) + { + warning (OPT_Wattributes, + "%qE attribute have effect only on public objects", name); + *no_add_attrs = true; + } + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "const" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree type = TREE_TYPE (*node); + + /* See FIXME comment on noreturn in c_common_attribute_table. */ + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_READONLY (*node) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) + = build_pointer_type + (build_type_variant (TREE_TYPE (type), 1, + TREE_THIS_VOLATILE (TREE_TYPE (type)))); + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "transparent_union" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_transparent_union_attribute (tree *node, tree name, + tree ARG_UNUSED (args), int flags, + bool *no_add_attrs) +{ + tree type; + + *no_add_attrs = true; + + if (TREE_CODE (*node) == TYPE_DECL) + node = &TREE_TYPE (*node); + type = *node; + + if (TREE_CODE (type) == UNION_TYPE) + { + /* When IN_PLACE is set, leave the check for FIELDS and MODE to + the code in finish_struct. */ + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + { + if (TYPE_FIELDS (type) == NULL_TREE + || TYPE_MODE (type) != DECL_MODE (TYPE_FIELDS (type))) + goto ignored; + + /* A type variant isn't good enough, since we don't a cast + to such a type removed as a no-op. */ + *node = type = build_duplicate_type (type); + } + + TYPE_TRANSPARENT_AGGR (type) = 1; + return NULL_TREE; + } + + ignored: + warning (OPT_Wattributes, "%qE attribute ignored", name); + return NULL_TREE; +} + +/* Subroutine of handle_{con,de}structor_attribute. Evaluate ARGS to + get the requested priority for a constructor or destructor, + possibly issuing diagnostics for invalid or reserved + priorities. */ + +static priority_type +get_priority (tree args, bool is_destructor) +{ + HOST_WIDE_INT pri; + tree arg; + + if (!args) + return DEFAULT_INIT_PRIORITY; + + if (!SUPPORTS_INIT_PRIORITY) + { + if (is_destructor) + error ("destructor priorities are not supported"); + else + error ("constructor priorities are not supported"); + return DEFAULT_INIT_PRIORITY; + } + + arg = TREE_VALUE (args); + if (!host_integerp (arg, /*pos=*/0) + || !INTEGRAL_TYPE_P (TREE_TYPE (arg))) + goto invalid; + + pri = tree_low_cst (TREE_VALUE (args), /*pos=*/0); + if (pri < 0 || pri > MAX_INIT_PRIORITY) + goto invalid; + + if (pri <= MAX_RESERVED_INIT_PRIORITY) + { + if (is_destructor) + warning (0, + "destructor priorities from 0 to %d are reserved " + "for the implementation", + MAX_RESERVED_INIT_PRIORITY); + else + warning (0, + "constructor priorities from 0 to %d are reserved " + "for the implementation", + MAX_RESERVED_INIT_PRIORITY); + } + return pri; + + invalid: + if (is_destructor) + error ("destructor priorities must be integers from 0 to %d inclusive", + MAX_INIT_PRIORITY); + else + error ("constructor priorities must be integers from 0 to %d inclusive", + MAX_INIT_PRIORITY); + return DEFAULT_INIT_PRIORITY; +} + +/* Handle a "constructor" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_constructor_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + tree decl = *node; + tree type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == FUNCTION_DECL + && TREE_CODE (type) == FUNCTION_TYPE + && decl_function_context (decl) == 0) + { + priority_type priority; + DECL_STATIC_CONSTRUCTOR (decl) = 1; + priority = get_priority (args, /*is_destructor=*/false); + SET_DECL_INIT_PRIORITY (decl, priority); + TREE_USED (decl) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "destructor" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_destructor_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + tree decl = *node; + tree type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == FUNCTION_DECL + && TREE_CODE (type) == FUNCTION_TYPE + && decl_function_context (decl) == 0) + { + priority_type priority; + DECL_STATIC_DESTRUCTOR (decl) = 1; + priority = get_priority (args, /*is_destructor=*/true); + SET_DECL_FINI_PRIORITY (decl, priority); + TREE_USED (decl) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "mode" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_mode_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree type = *node; + tree ident = TREE_VALUE (args); + + *no_add_attrs = true; + + if (TREE_CODE (ident) != IDENTIFIER_NODE) + warning (OPT_Wattributes, "%qE attribute ignored", name); + else + { + int j; + const char *p = IDENTIFIER_POINTER (ident); + int len = strlen (p); + enum machine_mode mode = VOIDmode; + tree typefm; + bool valid_mode; + + if (len > 4 && p[0] == '_' && p[1] == '_' + && p[len - 1] == '_' && p[len - 2] == '_') + { + char *newp = (char *) alloca (len - 1); + + strcpy (newp, &p[2]); + newp[len - 4] = '\0'; + p = newp; + } + + /* Change this type to have a type with the specified mode. + First check for the special modes. */ + if (!strcmp (p, "byte")) + mode = byte_mode; + else if (!strcmp (p, "word")) + mode = word_mode; + else if (!strcmp (p, "pointer")) + mode = ptr_mode; + else if (!strcmp (p, "libgcc_cmp_return")) + mode = targetm.libgcc_cmp_return_mode (); + else if (!strcmp (p, "libgcc_shift_count")) + mode = targetm.libgcc_shift_count_mode (); + else if (!strcmp (p, "unwind_word")) + mode = targetm.unwind_word_mode (); + else + for (j = 0; j < NUM_MACHINE_MODES; j++) + if (!strcmp (p, GET_MODE_NAME (j))) + { + mode = (enum machine_mode) j; + break; + } + + if (mode == VOIDmode) + { + error ("unknown machine mode %qE", ident); + return NULL_TREE; + } + + valid_mode = false; + switch (GET_MODE_CLASS (mode)) + { + case MODE_INT: + case MODE_PARTIAL_INT: + case MODE_FLOAT: + case MODE_DECIMAL_FLOAT: + case MODE_FRACT: + case MODE_UFRACT: + case MODE_ACCUM: + case MODE_UACCUM: + valid_mode = targetm.scalar_mode_supported_p (mode); + break; + + case MODE_COMPLEX_INT: + case MODE_COMPLEX_FLOAT: + valid_mode = targetm.scalar_mode_supported_p (GET_MODE_INNER (mode)); + break; + + case MODE_VECTOR_INT: + case MODE_VECTOR_FLOAT: + case MODE_VECTOR_FRACT: + case MODE_VECTOR_UFRACT: + case MODE_VECTOR_ACCUM: + case MODE_VECTOR_UACCUM: + warning (OPT_Wattributes, "specifying vector types with " + "__attribute__ ((mode)) is deprecated"); + warning (OPT_Wattributes, + "use __attribute__ ((vector_size)) instead"); + valid_mode = vector_mode_valid_p (mode); + break; + + default: + break; + } + if (!valid_mode) + { + error ("unable to emulate %qs", p); + return NULL_TREE; + } + + if (POINTER_TYPE_P (type)) + { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type)); + tree (*fn)(tree, enum machine_mode, bool); + + if (!targetm.addr_space.valid_pointer_mode (mode, as)) + { + error ("invalid pointer mode %qs", p); + return NULL_TREE; + } + + if (TREE_CODE (type) == POINTER_TYPE) + fn = build_pointer_type_for_mode; + else + fn = build_reference_type_for_mode; + typefm = fn (TREE_TYPE (type), mode, false); + } + else + { + /* For fixed-point modes, we need to test if the signness of type + and the machine mode are consistent. */ + if (ALL_FIXED_POINT_MODE_P (mode) + && TYPE_UNSIGNED (type) != UNSIGNED_FIXED_POINT_MODE_P (mode)) + { + error ("signness of type and machine mode %qs don't match", p); + return NULL_TREE; + } + /* For fixed-point modes, we need to pass saturating info. */ + typefm = lang_hooks.types.type_for_mode (mode, + ALL_FIXED_POINT_MODE_P (mode) ? TYPE_SATURATING (type) + : TYPE_UNSIGNED (type)); + } + + if (typefm == NULL_TREE) + { + error ("no data type for mode %qs", p); + return NULL_TREE; + } + else if (TREE_CODE (type) == ENUMERAL_TYPE) + { + /* For enumeral types, copy the precision from the integer + type returned above. If not an INTEGER_TYPE, we can't use + this mode for this type. */ + if (TREE_CODE (typefm) != INTEGER_TYPE) + { + error ("cannot use mode %qs for enumeral types", p); + return NULL_TREE; + } + + if (flags & ATTR_FLAG_TYPE_IN_PLACE) + { + TYPE_PRECISION (type) = TYPE_PRECISION (typefm); + typefm = type; + } + else + { + /* We cannot build a type variant, as there's code that assumes + that TYPE_MAIN_VARIANT has the same mode. This includes the + debug generators. Instead, create a subrange type. This + results in all of the enumeral values being emitted only once + in the original, and the subtype gets them by reference. */ + if (TYPE_UNSIGNED (type)) + typefm = make_unsigned_type (TYPE_PRECISION (typefm)); + else + typefm = make_signed_type (TYPE_PRECISION (typefm)); + TREE_TYPE (typefm) = type; + } + } + else if (VECTOR_MODE_P (mode) + ? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm)) + : TREE_CODE (type) != TREE_CODE (typefm)) + { + error ("mode %qs applied to inappropriate type", p); + return NULL_TREE; + } + + *node = typefm; + } + + return NULL_TREE; +} + +/* Handle a "section" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree decl = *node; + + if (targetm.have_named_sections) + { + user_defined_section_attribute = true; + + if ((TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == VAR_DECL) + && TREE_CODE (TREE_VALUE (args)) == STRING_CST) + { + if (TREE_CODE (decl) == VAR_DECL + && current_function_decl != NULL_TREE + && !TREE_STATIC (decl)) + { + error_at (DECL_SOURCE_LOCATION (decl), + "section attribute cannot be specified for " + "local variables"); + *no_add_attrs = true; + } + + /* The decl may have already been given a section attribute + from a previous declaration. Ensure they match. */ + else if (DECL_SECTION_NAME (decl) != NULL_TREE + && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), + TREE_STRING_POINTER (TREE_VALUE (args))) != 0) + { + error ("section of %q+D conflicts with previous declaration", + *node); + *no_add_attrs = true; + } + else if (TREE_CODE (decl) == VAR_DECL + && !targetm.have_tls && targetm.emutls.tmpl_section + && DECL_THREAD_LOCAL_P (decl)) + { + error ("section of %q+D cannot be overridden", *node); + *no_add_attrs = true; + } + else + DECL_SECTION_NAME (decl) = TREE_VALUE (args); + } + else + { + error ("section attribute not allowed for %q+D", *node); + *no_add_attrs = true; + } + } + else + { + error_at (DECL_SOURCE_LOCATION (*node), + "section attributes are not supported for this target"); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "aligned" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, + int flags, bool *no_add_attrs) +{ + tree decl = NULL_TREE; + tree *type = NULL; + int is_type = 0; + tree align_expr = (args ? TREE_VALUE (args) + : size_int (ATTRIBUTE_ALIGNED_VALUE / BITS_PER_UNIT)); + int i; + + if (DECL_P (*node)) + { + decl = *node; + type = &TREE_TYPE (decl); + is_type = TREE_CODE (*node) == TYPE_DECL; + } + else if (TYPE_P (*node)) + type = node, is_type = 1; + + if (TREE_CODE (align_expr) != INTEGER_CST) + { + error ("requested alignment is not a constant"); + *no_add_attrs = true; + } + else if ((i = tree_log2 (align_expr)) == -1) + { + error ("requested alignment is not a power of 2"); + *no_add_attrs = true; + } + else if (i >= HOST_BITS_PER_INT - BITS_PER_UNIT_LOG) + { + error ("requested alignment is too large"); + *no_add_attrs = true; + } + else if (is_type) + { + if ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + /* OK, modify the type in place. */; + /* If we have a TYPE_DECL, then copy the type, so that we + don't accidentally modify a builtin type. See pushdecl. */ + else if (decl && TREE_TYPE (decl) != error_mark_node + && DECL_ORIGINAL_TYPE (decl) == NULL_TREE) + { + tree tt = TREE_TYPE (decl); + *type = build_variant_type_copy (*type); + DECL_ORIGINAL_TYPE (decl) = tt; + TYPE_NAME (*type) = decl; + TREE_USED (*type) = TREE_USED (decl); + TREE_TYPE (decl) = *type; + } + else + *type = build_variant_type_copy (*type); + + TYPE_ALIGN (*type) = (1U << i) * BITS_PER_UNIT; + TYPE_USER_ALIGN (*type) = 1; + } + else if (! VAR_OR_FUNCTION_DECL_P (decl) + && TREE_CODE (decl) != FIELD_DECL) + { + error ("alignment may not be specified for %q+D", decl); + *no_add_attrs = true; + } + else if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) + { + if (DECL_USER_ALIGN (decl)) + error ("alignment for %q+D was previously specified as %d " + "and may not be decreased", decl, + DECL_ALIGN (decl) / BITS_PER_UNIT); + else + error ("alignment for %q+D must be at least %d", decl, + DECL_ALIGN (decl) / BITS_PER_UNIT); + *no_add_attrs = true; + } + else + { + DECL_ALIGN (decl) = (1U << i) * BITS_PER_UNIT; + DECL_USER_ALIGN (decl) = 1; + } + + return NULL_TREE; +} + +/* Handle a "weak" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_weak_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + if (TREE_CODE (*node) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (*node)) + { + error ("inline function %q+D cannot be declared weak", *node); + *no_add_attrs = true; + } + else if (TREE_CODE (*node) == FUNCTION_DECL + || TREE_CODE (*node) == VAR_DECL) + declare_weak (*node); + else + warning (OPT_Wattributes, "%qE attribute ignored", name); + + return NULL_TREE; +} + +/* Handle an "alias" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_alias_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree decl = *node; + + if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) + || (TREE_CODE (decl) != FUNCTION_DECL + && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) + /* A static variable declaration is always a tentative definition, + but the alias is a non-tentative definition which overrides. */ + || (TREE_CODE (decl) != FUNCTION_DECL + && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl))) + { + error ("%q+D defined both normally and as an alias", decl); + *no_add_attrs = true; + } + + /* Note that the very first time we process a nested declaration, + decl_function_context will not be set. Indeed, *would* never + be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that + we do below. After such frobbery, pushdecl would set the context. + In any case, this is never what we want. */ + else if (decl_function_context (decl) == 0 && current_function_decl == NULL) + { + tree id; + + id = TREE_VALUE (args); + if (TREE_CODE (id) != STRING_CST) + { + error ("alias argument not a string"); + *no_add_attrs = true; + return NULL_TREE; + } + id = get_identifier (TREE_STRING_POINTER (id)); + /* This counts as a use of the object pointed to. */ + TREE_USED (id) = 1; + + if (TREE_CODE (decl) == FUNCTION_DECL) + DECL_INITIAL (decl) = error_mark_node; + else + { + if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))) + DECL_EXTERNAL (decl) = 1; + else + DECL_EXTERNAL (decl) = 0; + TREE_STATIC (decl) = 1; + } + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "weakref" attribute; arguments as in struct + attribute_spec.handler. */ + +static tree +handle_weakref_attribute (tree *node, tree ARG_UNUSED (name), tree args, + int flags, bool *no_add_attrs) +{ + tree attr = NULL_TREE; + + /* We must ignore the attribute when it is associated with + local-scoped decls, since attribute alias is ignored and many + such symbols do not even have a DECL_WEAK field. */ + if (decl_function_context (*node) + || current_function_decl + || (TREE_CODE (*node) != VAR_DECL && TREE_CODE (*node) != FUNCTION_DECL)) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + return NULL_TREE; + } + + /* The idea here is that `weakref("name")' mutates into `weakref, + alias("name")', and weakref without arguments, in turn, + implicitly adds weak. */ + + if (args) + { + attr = tree_cons (get_identifier ("alias"), args, attr); + attr = tree_cons (get_identifier ("weakref"), NULL_TREE, attr); + + *no_add_attrs = true; + + decl_attributes (node, attr, flags); + } + else + { + if (lookup_attribute ("alias", DECL_ATTRIBUTES (*node))) + error_at (DECL_SOURCE_LOCATION (*node), + "weakref attribute must appear before alias attribute"); + + /* Can't call declare_weak because it wants this to be TREE_PUBLIC, + and that isn't supported; and because it wants to add it to + the list of weak decls, which isn't helpful. */ + DECL_WEAK (*node) = 1; + } + + return NULL_TREE; +} + +/* Handle an "visibility" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_visibility_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), + bool *ARG_UNUSED (no_add_attrs)) +{ + tree decl = *node; + tree id = TREE_VALUE (args); + enum symbol_visibility vis; + + if (TYPE_P (*node)) + { + if (TREE_CODE (*node) == ENUMERAL_TYPE) + /* OK */; + else if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE) + { + warning (OPT_Wattributes, "%qE attribute ignored on non-class types", + name); + return NULL_TREE; + } + else if (TYPE_FIELDS (*node)) + { + error ("%qE attribute ignored because %qT is already defined", + name, *node); + return NULL_TREE; + } + } + else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl)) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + return NULL_TREE; + } + + if (TREE_CODE (id) != STRING_CST) + { + error ("visibility argument not a string"); + return NULL_TREE; + } + + /* If this is a type, set the visibility on the type decl. */ + if (TYPE_P (decl)) + { + decl = TYPE_NAME (decl); + if (!decl) + return NULL_TREE; + if (TREE_CODE (decl) == IDENTIFIER_NODE) + { + warning (OPT_Wattributes, "%qE attribute ignored on types", + name); + return NULL_TREE; + } + } + + if (strcmp (TREE_STRING_POINTER (id), "default") == 0) + vis = VISIBILITY_DEFAULT; + else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0) + vis = VISIBILITY_INTERNAL; + else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0) + vis = VISIBILITY_HIDDEN; + else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0) + vis = VISIBILITY_PROTECTED; + else + { + error ("visibility argument must be one of \"default\", \"hidden\", \"protected\" or \"internal\""); + vis = VISIBILITY_DEFAULT; + } + + if (DECL_VISIBILITY_SPECIFIED (decl) + && vis != DECL_VISIBILITY (decl)) + { + tree attributes = (TYPE_P (*node) + ? TYPE_ATTRIBUTES (*node) + : DECL_ATTRIBUTES (decl)); + if (lookup_attribute ("visibility", attributes)) + error ("%qD redeclared with different visibility", decl); + else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && lookup_attribute ("dllimport", attributes)) + error ("%qD was declared %qs which implies default visibility", + decl, "dllimport"); + else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && lookup_attribute ("dllexport", attributes)) + error ("%qD was declared %qs which implies default visibility", + decl, "dllexport"); + } + + DECL_VISIBILITY (decl) = vis; + DECL_VISIBILITY_SPECIFIED (decl) = 1; + + /* Go ahead and attach the attribute to the node as well. This is needed + so we can determine whether we have VISIBILITY_DEFAULT because the + visibility was not specified, or because it was explicitly overridden + from the containing scope. */ + + return NULL_TREE; +} + +/* Determine the ELF symbol visibility for DECL, which is either a + variable or a function. It is an error to use this function if a + definition of DECL is not available in this translation unit. + Returns true if the final visibility has been determined by this + function; false if the caller is free to make additional + modifications. */ + +bool +c_determine_visibility (tree decl) +{ + gcc_assert (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL); + + /* If the user explicitly specified the visibility with an + attribute, honor that. DECL_VISIBILITY will have been set during + the processing of the attribute. We check for an explicit + attribute, rather than just checking DECL_VISIBILITY_SPECIFIED, + to distinguish the use of an attribute from the use of a "#pragma + GCC visibility push(...)"; in the latter case we still want other + considerations to be able to overrule the #pragma. */ + if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)) + || (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && (lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)) + || lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))))) + return true; + + /* Set default visibility to whatever the user supplied with + visibility_specified depending on #pragma GCC visibility. */ + if (!DECL_VISIBILITY_SPECIFIED (decl)) + { + if (visibility_options.inpragma + || DECL_VISIBILITY (decl) != default_visibility) + { + DECL_VISIBILITY (decl) = default_visibility; + DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma; + /* If visibility changed and DECL already has DECL_RTL, ensure + symbol flags are updated. */ + if (((TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) + || TREE_CODE (decl) == FUNCTION_DECL) + && DECL_RTL_SET_P (decl)) + make_decl_rtl (decl); + } + } + return false; +} + +/* Handle an "tls_model" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_tls_model_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree id; + tree decl = *node; + enum tls_model kind; + + *no_add_attrs = true; + + if (TREE_CODE (decl) != VAR_DECL || !DECL_THREAD_LOCAL_P (decl)) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + return NULL_TREE; + } + + kind = DECL_TLS_MODEL (decl); + id = TREE_VALUE (args); + if (TREE_CODE (id) != STRING_CST) + { + error ("tls_model argument not a string"); + return NULL_TREE; + } + + if (!strcmp (TREE_STRING_POINTER (id), "local-exec")) + kind = TLS_MODEL_LOCAL_EXEC; + else if (!strcmp (TREE_STRING_POINTER (id), "initial-exec")) + kind = TLS_MODEL_INITIAL_EXEC; + else if (!strcmp (TREE_STRING_POINTER (id), "local-dynamic")) + kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC; + else if (!strcmp (TREE_STRING_POINTER (id), "global-dynamic")) + kind = TLS_MODEL_GLOBAL_DYNAMIC; + else + error ("tls_model argument must be one of \"local-exec\", \"initial-exec\", \"local-dynamic\" or \"global-dynamic\""); + + DECL_TLS_MODEL (decl) = kind; + return NULL_TREE; +} + +/* Handle a "no_instrument_function" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_no_instrument_function_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + tree decl = *node; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute applies only to functions", name); + *no_add_attrs = true; + } + else if (DECL_INITIAL (decl)) + { + error_at (DECL_SOURCE_LOCATION (decl), + "can%'t set %qE attribute after definition", name); + *no_add_attrs = true; + } + else + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; + + return NULL_TREE; +} + +/* Handle a "malloc" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))) + DECL_IS_MALLOC (*node) = 1; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "alloc_size" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + unsigned arg_count = type_num_arguments (*node); + for (; args; args = TREE_CHAIN (args)) + { + tree position = TREE_VALUE (args); + + if (TREE_CODE (position) != INTEGER_CST + || TREE_INT_CST_HIGH (position) + || TREE_INT_CST_LOW (position) < 1 + || TREE_INT_CST_LOW (position) > arg_count ) + { + warning (OPT_Wattributes, + "alloc_size parameter outside range"); + *no_add_attrs = true; + return NULL_TREE; + } + } + return NULL_TREE; +} + +/* Handle a "fn spec" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name), + tree args, int ARG_UNUSED (flags), + bool *no_add_attrs ATTRIBUTE_UNUSED) +{ + gcc_assert (args + && TREE_CODE (TREE_VALUE (args)) == STRING_CST + && !TREE_CHAIN (args)); + return NULL_TREE; +} + +/* Handle a "returns_twice" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_returns_twice_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + DECL_IS_RETURNS_TWICE (*node) = 1; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "no_limit_stack" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_no_limit_stack_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + tree decl = *node; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute applies only to functions", name); + *no_add_attrs = true; + } + else if (DECL_INITIAL (decl)) + { + error_at (DECL_SOURCE_LOCATION (decl), + "can%'t set %qE attribute after definition", name); + *no_add_attrs = true; + } + else + DECL_NO_LIMIT_STACK (decl) = 1; + + return NULL_TREE; +} + +/* Handle a "pure" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + DECL_PURE_P (*node) = 1; + /* ??? TODO: Support types. */ + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "no vops" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_novops_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool *ARG_UNUSED (no_add_attrs)) +{ + gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + DECL_IS_NOVOPS (*node) = 1; + return NULL_TREE; +} + +/* Handle a "deprecated" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_deprecated_attribute (tree *node, tree name, + tree args, int flags, + bool *no_add_attrs) +{ + tree type = NULL_TREE; + int warn = 0; + tree what = NULL_TREE; + + if (!args) + *no_add_attrs = true; + else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) + { + error ("deprecated message is not a string"); + *no_add_attrs = true; + } + + if (DECL_P (*node)) + { + tree decl = *node; + type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == FIELD_DECL) + TREE_DEPRECATED (decl) = 1; + else + warn = 1; + } + else if (TYPE_P (*node)) + { + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + *node = build_variant_type_copy (*node); + TREE_DEPRECATED (*node) = 1; + type = *node; + } + else + warn = 1; + + if (warn) + { + *no_add_attrs = true; + if (type && TYPE_NAME (type)) + { + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + what = TYPE_NAME (*node); + else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (type))) + what = DECL_NAME (TYPE_NAME (type)); + } + if (what) + warning (OPT_Wattributes, "%qE attribute ignored for %qE", name, what); + else + warning (OPT_Wattributes, "%qE attribute ignored", name); + } + + return NULL_TREE; +} + +/* Handle a "vector_size" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_vector_size_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + unsigned HOST_WIDE_INT vecsize, nunits; + enum machine_mode orig_mode; + tree type = *node, new_type, size; + + *no_add_attrs = true; + + size = TREE_VALUE (args); + + if (!host_integerp (size, 1)) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + return NULL_TREE; + } + + /* Get the vector size (in bytes). */ + vecsize = tree_low_cst (size, 1); + + /* We need to provide for vector pointers, vector arrays, and + functions returning vectors. For example: + + __attribute__((vector_size(16))) short *foo; + + In this case, the mode is SI, but the type being modified is + HI, so we need to look further. */ + + while (POINTER_TYPE_P (type) + || TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == METHOD_TYPE + || TREE_CODE (type) == ARRAY_TYPE + || TREE_CODE (type) == OFFSET_TYPE) + type = TREE_TYPE (type); + + /* Get the mode of the type being modified. */ + orig_mode = TYPE_MODE (type); + + if ((!INTEGRAL_TYPE_P (type) + && !SCALAR_FLOAT_TYPE_P (type) + && !FIXED_POINT_TYPE_P (type)) + || (!SCALAR_FLOAT_MODE_P (orig_mode) + && GET_MODE_CLASS (orig_mode) != MODE_INT + && !ALL_SCALAR_FIXED_POINT_MODE_P (orig_mode)) + || !host_integerp (TYPE_SIZE_UNIT (type), 1) + || TREE_CODE (type) == BOOLEAN_TYPE) + { + error ("invalid vector type for attribute %qE", name); + return NULL_TREE; + } + + if (vecsize % tree_low_cst (TYPE_SIZE_UNIT (type), 1)) + { + error ("vector size not an integral multiple of component size"); + return NULL; + } + + if (vecsize == 0) + { + error ("zero vector size"); + return NULL; + } + + /* Calculate how many units fit in the vector. */ + nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1); + if (nunits & (nunits - 1)) + { + error ("number of components of the vector not a power of two"); + return NULL_TREE; + } + + new_type = build_vector_type (type, nunits); + + /* Build back pointers if needed. */ + *node = lang_hooks.types.reconstruct_complex_type (*node, new_type); + + return NULL_TREE; +} + +/* Handle the "nonnull" attribute. */ +static tree +handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), + tree args, int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + tree type = *node; + unsigned HOST_WIDE_INT attr_arg_num; + + /* If no arguments are specified, all pointer arguments should be + non-null. Verify a full prototype is given so that the arguments + will have the correct types when we actually check them later. */ + if (!args) + { + if (!TYPE_ARG_TYPES (type)) + { + error ("nonnull attribute without arguments on a non-prototype"); + *no_add_attrs = true; + } + return NULL_TREE; + } + + /* Argument list specified. Verify that each argument number references + a pointer argument. */ + for (attr_arg_num = 1; args; args = TREE_CHAIN (args)) + { + tree argument; + unsigned HOST_WIDE_INT arg_num = 0, ck_num; + + if (!get_nonnull_operand (TREE_VALUE (args), &arg_num)) + { + error ("nonnull argument has invalid operand number (argument %lu)", + (unsigned long) attr_arg_num); + *no_add_attrs = true; + return NULL_TREE; + } + + argument = TYPE_ARG_TYPES (type); + if (argument) + { + for (ck_num = 1; ; ck_num++) + { + if (!argument || ck_num == arg_num) + break; + argument = TREE_CHAIN (argument); + } + + if (!argument + || TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE) + { + error ("nonnull argument with out-of-range operand number (argument %lu, operand %lu)", + (unsigned long) attr_arg_num, (unsigned long) arg_num); + *no_add_attrs = true; + return NULL_TREE; + } + + if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE) + { + error ("nonnull argument references non-pointer operand (argument %lu, operand %lu)", + (unsigned long) attr_arg_num, (unsigned long) arg_num); + *no_add_attrs = true; + return NULL_TREE; + } + } + } + + return NULL_TREE; +} + +/* Check the argument list of a function call for null in argument slots + that are marked as requiring a non-null pointer argument. The NARGS + arguments are passed in the array ARGARRAY. +*/ + +static void +check_function_nonnull (tree attrs, int nargs, tree *argarray) +{ + tree a, args; + int i; + + for (a = attrs; a; a = TREE_CHAIN (a)) + { + if (is_attribute_p ("nonnull", TREE_PURPOSE (a))) + { + args = TREE_VALUE (a); + + /* Walk the argument list. If we encounter an argument number we + should check for non-null, do it. If the attribute has no args, + then every pointer argument is checked (in which case the check + for pointer type is done in check_nonnull_arg). */ + for (i = 0; i < nargs; i++) + { + if (!args || nonnull_check_p (args, i + 1)) + check_function_arguments_recurse (check_nonnull_arg, NULL, + argarray[i], + i + 1); + } + } + } +} + +/* Check that the Nth argument of a function call (counting backwards + from the end) is a (pointer)0. The NARGS arguments are passed in the + array ARGARRAY. */ + +static void +check_function_sentinel (tree attrs, int nargs, tree *argarray, tree typelist) +{ + tree attr = lookup_attribute ("sentinel", attrs); + + if (attr) + { + int len = 0; + int pos = 0; + tree sentinel; + + /* Skip over the named arguments. */ + while (typelist && len < nargs) + { + typelist = TREE_CHAIN (typelist); + len++; + } + + if (TREE_VALUE (attr)) + { + tree p = TREE_VALUE (TREE_VALUE (attr)); + pos = TREE_INT_CST_LOW (p); + } + + /* The sentinel must be one of the varargs, i.e. + in position >= the number of fixed arguments. */ + if ((nargs - 1 - pos) < len) + { + warning (OPT_Wformat, + "not enough variable arguments to fit a sentinel"); + return; + } + + /* Validate the sentinel. */ + sentinel = argarray[nargs - 1 - pos]; + if ((!POINTER_TYPE_P (TREE_TYPE (sentinel)) + || !integer_zerop (sentinel)) + /* Although __null (in C++) is only an integer we allow it + nevertheless, as we are guaranteed that it's exactly + as wide as a pointer, and we don't want to force + users to cast the NULL they have written there. + We warn with -Wstrict-null-sentinel, though. */ + && (warn_strict_null_sentinel || null_node != sentinel)) + warning (OPT_Wformat, "missing sentinel in function call"); + } +} + +/* Helper for check_function_nonnull; given a list of operands which + must be non-null in ARGS, determine if operand PARAM_NUM should be + checked. */ + +static bool +nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num) +{ + unsigned HOST_WIDE_INT arg_num = 0; + + for (; args; args = TREE_CHAIN (args)) + { + bool found = get_nonnull_operand (TREE_VALUE (args), &arg_num); + + gcc_assert (found); + + if (arg_num == param_num) + return true; + } + return false; +} + +/* Check that the function argument PARAM (which is operand number + PARAM_NUM) is non-null. This is called by check_function_nonnull + via check_function_arguments_recurse. */ + +static void +check_nonnull_arg (void * ARG_UNUSED (ctx), tree param, + unsigned HOST_WIDE_INT param_num) +{ + /* Just skip checking the argument if it's not a pointer. This can + happen if the "nonnull" attribute was given without an operand + list (which means to check every pointer argument). */ + + if (TREE_CODE (TREE_TYPE (param)) != POINTER_TYPE) + return; + + if (integer_zerop (param)) + warning (OPT_Wnonnull, "null argument where non-null required " + "(argument %lu)", (unsigned long) param_num); +} + +/* Helper for nonnull attribute handling; fetch the operand number + from the attribute argument list. */ + +static bool +get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp) +{ + /* Verify the arg number is a constant. */ + if (TREE_CODE (arg_num_expr) != INTEGER_CST + || TREE_INT_CST_HIGH (arg_num_expr) != 0) + return false; + + *valp = TREE_INT_CST_LOW (arg_num_expr); + return true; +} + +/* Handle a "nothrow" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_nothrow_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_NOTHROW (*node) = 1; + /* ??? TODO: Support types. */ + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "cleanup" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_cleanup_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree decl = *node; + tree cleanup_id, cleanup_decl; + + /* ??? Could perhaps support cleanups on TREE_STATIC, much like we do + for global destructors in C++. This requires infrastructure that + we don't have generically at the moment. It's also not a feature + we'd be missing too much, since we do have attribute constructor. */ + if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl)) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + return NULL_TREE; + } + + /* Verify that the argument is a function in scope. */ + /* ??? We could support pointers to functions here as well, if + that was considered desirable. */ + cleanup_id = TREE_VALUE (args); + if (TREE_CODE (cleanup_id) != IDENTIFIER_NODE) + { + error ("cleanup argument not an identifier"); + *no_add_attrs = true; + return NULL_TREE; + } + cleanup_decl = lookup_name (cleanup_id); + if (!cleanup_decl || TREE_CODE (cleanup_decl) != FUNCTION_DECL) + { + error ("cleanup argument not a function"); + *no_add_attrs = true; + return NULL_TREE; + } + + /* That the function has proper type is checked with the + eventual call to build_function_call. */ + + return NULL_TREE; +} + +/* Handle a "warn_unused_result" attribute. No special handling. */ + +static tree +handle_warn_unused_result_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + /* Ignore the attribute for functions not returning any value. */ + if (VOID_TYPE_P (TREE_TYPE (*node))) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "sentinel" attribute. */ + +static tree +handle_sentinel_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree params = TYPE_ARG_TYPES (*node); + + if (!params) + { + warning (OPT_Wattributes, + "%qE attribute requires prototypes with named arguments", name); + *no_add_attrs = true; + } + else + { + while (TREE_CHAIN (params)) + params = TREE_CHAIN (params); + + if (VOID_TYPE_P (TREE_VALUE (params))) + { + warning (OPT_Wattributes, + "%qE attribute only applies to variadic functions", name); + *no_add_attrs = true; + } + } + + if (args) + { + tree position = TREE_VALUE (args); + + if (TREE_CODE (position) != INTEGER_CST) + { + warning (OPT_Wattributes, + "requested position is not an integer constant"); + *no_add_attrs = true; + } + else + { + if (tree_int_cst_lt (position, integer_zero_node)) + { + warning (OPT_Wattributes, + "requested position is less than zero"); + *no_add_attrs = true; + } + } + } + + return NULL_TREE; +} + +/* Handle a "type_generic" attribute. */ + +static tree +handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree params; + + /* Ensure we have a function type. */ + gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); + + params = TYPE_ARG_TYPES (*node); + while (params && ! VOID_TYPE_P (TREE_VALUE (params))) + params = TREE_CHAIN (params); + + /* Ensure we have a variadic function. */ + gcc_assert (!params); + + return NULL_TREE; +} + +/* Handle a "target" attribute. */ + +static tree +handle_target_attribute (tree *node, tree name, tree args, int flags, + bool *no_add_attrs) +{ + /* Ensure we have a function type. */ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + else if (! targetm.target_option.valid_attribute_p (*node, name, args, + flags)) + *no_add_attrs = true; + + return NULL_TREE; +} + +/* Arguments being collected for optimization. */ +typedef const char *const_char_p; /* For DEF_VEC_P. */ +DEF_VEC_P(const_char_p); +DEF_VEC_ALLOC_P(const_char_p, gc); +static GTY(()) VEC(const_char_p, gc) *optimize_args; + + +/* Inner function to convert a TREE_LIST to argv string to parse the optimize + options in ARGS. ATTR_P is true if this is for attribute(optimize), and + false for #pragma GCC optimize. */ + +bool +parse_optimize_options (tree args, bool attr_p) +{ + bool ret = true; + unsigned opt_argc; + unsigned i; + int saved_flag_strict_aliasing; + const char **opt_argv; + tree ap; + + /* Build up argv vector. Just in case the string is stored away, use garbage + collected strings. */ + VEC_truncate (const_char_p, optimize_args, 0); + VEC_safe_push (const_char_p, gc, optimize_args, NULL); + + for (ap = args; ap != NULL_TREE; ap = TREE_CHAIN (ap)) + { + tree value = TREE_VALUE (ap); + + if (TREE_CODE (value) == INTEGER_CST) + { + char buffer[20]; + sprintf (buffer, "-O%ld", (long) TREE_INT_CST_LOW (value)); + VEC_safe_push (const_char_p, gc, optimize_args, ggc_strdup (buffer)); + } + + else if (TREE_CODE (value) == STRING_CST) + { + /* Split string into multiple substrings. */ + size_t len = TREE_STRING_LENGTH (value); + char *p = ASTRDUP (TREE_STRING_POINTER (value)); + char *end = p + len; + char *comma; + char *next_p = p; + + while (next_p != NULL) + { + size_t len2; + char *q, *r; + + p = next_p; + comma = strchr (p, ','); + if (comma) + { + len2 = comma - p; + *comma = '\0'; + next_p = comma+1; + } + else + { + len2 = end - p; + next_p = NULL; + } + + r = q = (char *) ggc_alloc (len2 + 3); + + /* If the user supplied -Oxxx or -fxxx, only allow -Oxxx or -fxxx + options. */ + if (*p == '-' && p[1] != 'O' && p[1] != 'f') + { + ret = false; + if (attr_p) + warning (OPT_Wattributes, + "Bad option %s to optimize attribute.", p); + else + warning (OPT_Wpragmas, + "Bad option %s to pragma attribute", p); + continue; + } + + if (*p != '-') + { + *r++ = '-'; + + /* Assume that Ox is -Ox, a numeric value is -Ox, a s by + itself is -Os, and any other switch begins with a -f. */ + if ((*p >= '0' && *p <= '9') + || (p[0] == 's' && p[1] == '\0')) + *r++ = 'O'; + else if (*p != 'O') + *r++ = 'f'; + } + + memcpy (r, p, len2); + r[len2] = '\0'; + VEC_safe_push (const_char_p, gc, optimize_args, q); + } + + } + } + + opt_argc = VEC_length (const_char_p, optimize_args); + opt_argv = (const char **) alloca (sizeof (char *) * (opt_argc + 1)); + + for (i = 1; i < opt_argc; i++) + opt_argv[i] = VEC_index (const_char_p, optimize_args, i); + + saved_flag_strict_aliasing = flag_strict_aliasing; + + /* Now parse the options. */ + decode_options (opt_argc, opt_argv); + + targetm.override_options_after_change(); + + /* Don't allow changing -fstrict-aliasing. */ + flag_strict_aliasing = saved_flag_strict_aliasing; + + VEC_truncate (const_char_p, optimize_args, 0); + return ret; +} + +/* For handling "optimize" attribute. arguments as in + struct attribute_spec.handler. */ + +static tree +handle_optimize_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + /* Ensure we have a function type. */ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + else + { + struct cl_optimization cur_opts; + tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node); + + /* Save current options. */ + cl_optimization_save (&cur_opts); + + /* If we previously had some optimization options, use them as the + default. */ + if (old_opts) + cl_optimization_restore (TREE_OPTIMIZATION (old_opts)); + + /* Parse options, and update the vector. */ + parse_optimize_options (args, true); + DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) + = build_optimization_node (); + + /* Restore current options. */ + cl_optimization_restore (&cur_opts); + } + + return NULL_TREE; +} + +/* Check for valid arguments being passed to a function. + ATTRS is a list of attributes. There are NARGS arguments in the array + ARGARRAY. TYPELIST is the list of argument types for the function. + */ +void +check_function_arguments (tree attrs, int nargs, tree *argarray, tree typelist) +{ + /* Check for null being passed in a pointer argument that must be + non-null. We also need to do this if format checking is enabled. */ + + if (warn_nonnull) + check_function_nonnull (attrs, nargs, argarray); + + /* Check for errors in format strings. */ + + if (warn_format || warn_missing_format_attribute) + check_function_format (attrs, nargs, argarray); + + if (warn_format) + check_function_sentinel (attrs, nargs, argarray, typelist); +} + +/* Generic argument checking recursion routine. PARAM is the argument to + be checked. PARAM_NUM is the number of the argument. CALLBACK is invoked + once the argument is resolved. CTX is context for the callback. */ +void +check_function_arguments_recurse (void (*callback) + (void *, tree, unsigned HOST_WIDE_INT), + void *ctx, tree param, + unsigned HOST_WIDE_INT param_num) +{ + if (CONVERT_EXPR_P (param) + && (TYPE_PRECISION (TREE_TYPE (param)) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (param, 0))))) + { + /* Strip coercion. */ + check_function_arguments_recurse (callback, ctx, + TREE_OPERAND (param, 0), param_num); + return; + } + + if (TREE_CODE (param) == CALL_EXPR) + { + tree type = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (param))); + tree attrs; + bool found_format_arg = false; + + /* See if this is a call to a known internationalization function + that modifies a format arg. Such a function may have multiple + format_arg attributes (for example, ngettext). */ + + for (attrs = TYPE_ATTRIBUTES (type); + attrs; + attrs = TREE_CHAIN (attrs)) + if (is_attribute_p ("format_arg", TREE_PURPOSE (attrs))) + { + tree inner_arg; + tree format_num_expr; + int format_num; + int i; + call_expr_arg_iterator iter; + + /* Extract the argument number, which was previously checked + to be valid. */ + format_num_expr = TREE_VALUE (TREE_VALUE (attrs)); + + gcc_assert (TREE_CODE (format_num_expr) == INTEGER_CST + && !TREE_INT_CST_HIGH (format_num_expr)); + + format_num = TREE_INT_CST_LOW (format_num_expr); + + for (inner_arg = first_call_expr_arg (param, &iter), i = 1; + inner_arg != 0; + inner_arg = next_call_expr_arg (&iter), i++) + if (i == format_num) + { + check_function_arguments_recurse (callback, ctx, + inner_arg, param_num); + found_format_arg = true; + break; + } + } + + /* If we found a format_arg attribute and did a recursive check, + we are done with checking this argument. Otherwise, we continue + and this will be considered a non-literal. */ + if (found_format_arg) + return; + } + + if (TREE_CODE (param) == COND_EXPR) + { + /* Check both halves of the conditional expression. */ + check_function_arguments_recurse (callback, ctx, + TREE_OPERAND (param, 1), param_num); + check_function_arguments_recurse (callback, ctx, + TREE_OPERAND (param, 2), param_num); + return; + } + + (*callback) (ctx, param, param_num); +} + +/* Checks for a builtin function FNDECL that the number of arguments + NARGS against the required number REQUIRED and issues an error if + there is a mismatch. Returns true if the number of arguments is + correct, otherwise false. */ + +static bool +builtin_function_validate_nargs (tree fndecl, int nargs, int required) +{ + if (nargs < required) + { + error_at (input_location, + "not enough arguments to function %qE", fndecl); + return false; + } + else if (nargs > required) + { + error_at (input_location, + "too many arguments to function %qE", fndecl); + return false; + } + return true; +} + +/* Verifies the NARGS arguments ARGS to the builtin function FNDECL. + Returns false if there was an error, otherwise true. */ + +bool +check_builtin_function_arguments (tree fndecl, int nargs, tree *args) +{ + if (!DECL_BUILT_IN (fndecl) + || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL) + return true; + + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_CONSTANT_P: + return builtin_function_validate_nargs (fndecl, nargs, 1); + + case BUILT_IN_ISFINITE: + case BUILT_IN_ISINF: + case BUILT_IN_ISINF_SIGN: + case BUILT_IN_ISNAN: + case BUILT_IN_ISNORMAL: + if (builtin_function_validate_nargs (fndecl, nargs, 1)) + { + if (TREE_CODE (TREE_TYPE (args[0])) != REAL_TYPE) + { + error ("non-floating-point argument in call to " + "function %qE", fndecl); + return false; + } + return true; + } + return false; + + case BUILT_IN_ISGREATER: + case BUILT_IN_ISGREATEREQUAL: + case BUILT_IN_ISLESS: + case BUILT_IN_ISLESSEQUAL: + case BUILT_IN_ISLESSGREATER: + case BUILT_IN_ISUNORDERED: + if (builtin_function_validate_nargs (fndecl, nargs, 2)) + { + enum tree_code code0, code1; + code0 = TREE_CODE (TREE_TYPE (args[0])); + code1 = TREE_CODE (TREE_TYPE (args[1])); + if (!((code0 == REAL_TYPE && code1 == REAL_TYPE) + || (code0 == REAL_TYPE && code1 == INTEGER_TYPE) + || (code0 == INTEGER_TYPE && code1 == REAL_TYPE))) + { + error ("non-floating-point arguments in call to " + "function %qE", fndecl); + return false; + } + return true; + } + return false; + + case BUILT_IN_FPCLASSIFY: + if (builtin_function_validate_nargs (fndecl, nargs, 6)) + { + unsigned i; + + for (i=0; i<5; i++) + if (TREE_CODE (args[i]) != INTEGER_CST) + { + error ("non-const integer argument %u in call to function %qE", + i+1, fndecl); + return false; + } + + if (TREE_CODE (TREE_TYPE (args[5])) != REAL_TYPE) + { + error ("non-floating-point argument in call to function %qE", + fndecl); + return false; + } + return true; + } + return false; + + default: + return true; + } +} + +/* Function to help qsort sort FIELD_DECLs by name order. */ + +int +field_decl_cmp (const void *x_p, const void *y_p) +{ + const tree *const x = (const tree *const) x_p; + const tree *const y = (const tree *const) 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; +} + +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 *const) x_p; + const tree *const y = (const tree *const) 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, resort_data.cookie); + resort_data.new_value (&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); +} + +/* Subroutine of c_parse_error. + Return the result of concatenating LHS and RHS. RHS is really + a string literal, its first character is indicated by RHS_START and + RHS_SIZE is its length (including the terminating NUL character). + + The caller is responsible for deleting the returned pointer. */ + +static char * +catenate_strings (const char *lhs, const char *rhs_start, int rhs_size) +{ + const int lhs_size = strlen (lhs); + char *result = XNEWVEC (char, lhs_size + rhs_size); + strncpy (result, lhs, lhs_size); + strncpy (result + lhs_size, rhs_start, rhs_size); + return result; +} + +/* Issue the error given by GMSGID, indicating that it occurred before + TOKEN, which had the associated VALUE. */ + +void +c_parse_error (const char *gmsgid, enum cpp_ttype token_type, + tree value, unsigned char token_flags) +{ +#define catenate_messages(M1, M2) catenate_strings ((M1), (M2), sizeof (M2)) + + char *message = NULL; + + if (token_type == CPP_EOF) + message = catenate_messages (gmsgid, " at end of input"); + else if (token_type == CPP_CHAR + || token_type == CPP_WCHAR + || token_type == CPP_CHAR16 + || token_type == CPP_CHAR32) + { + unsigned int val = TREE_INT_CST_LOW (value); + const char *prefix; + + switch (token_type) + { + default: + prefix = ""; + break; + case CPP_WCHAR: + prefix = "L"; + break; + case CPP_CHAR16: + prefix = "u"; + break; + case CPP_CHAR32: + prefix = "U"; + break; + } + + if (val <= UCHAR_MAX && ISGRAPH (val)) + message = catenate_messages (gmsgid, " before %s'%c'"); + else + message = catenate_messages (gmsgid, " before %s'\\x%x'"); + + error (message, prefix, val); + free (message); + message = NULL; + } + else if (token_type == CPP_STRING + || token_type == CPP_WSTRING + || token_type == CPP_STRING16 + || token_type == CPP_STRING32 + || token_type == CPP_UTF8STRING) + message = catenate_messages (gmsgid, " before string constant"); + else if (token_type == CPP_NUMBER) + message = catenate_messages (gmsgid, " before numeric constant"); + else if (token_type == CPP_NAME) + { + message = catenate_messages (gmsgid, " before %qE"); + error (message, value); + free (message); + message = NULL; + } + else if (token_type == CPP_PRAGMA) + message = catenate_messages (gmsgid, " before %<#pragma%>"); + else if (token_type == CPP_PRAGMA_EOL) + message = catenate_messages (gmsgid, " before end of line"); + else if (token_type < N_TTYPES) + { + message = catenate_messages (gmsgid, " before %qs token"); + error (message, cpp_type2name (token_type, token_flags)); + free (message); + message = NULL; + } + else + error (gmsgid); + + if (message) + { + error (message); + free (message); + } +#undef catenate_messages +} + +/* Mapping for cpp message reasons to the options that enable them. */ + +struct reason_option_codes_t +{ + const int reason; /* cpplib message reason. */ + const int option_code; /* gcc option that controls this message. */ +}; + +static const struct reason_option_codes_t option_codes[] = { + {CPP_W_DEPRECATED, OPT_Wdeprecated}, + {CPP_W_COMMENTS, OPT_Wcomments}, + {CPP_W_TRIGRAPHS, OPT_Wtrigraphs}, + {CPP_W_MULTICHAR, OPT_Wmultichar}, + {CPP_W_TRADITIONAL, OPT_Wtraditional}, + {CPP_W_LONG_LONG, OPT_Wlong_long}, + {CPP_W_ENDIF_LABELS, OPT_Wendif_labels}, + {CPP_W_VARIADIC_MACROS, OPT_Wvariadic_macros}, + {CPP_W_BUILTIN_MACRO_REDEFINED, OPT_Wbuiltin_macro_redefined}, + {CPP_W_UNDEF, OPT_Wundef}, + {CPP_W_UNUSED_MACROS, OPT_Wunused_macros}, + {CPP_W_CXX_OPERATOR_NAMES, OPT_Wc___compat}, + {CPP_W_NORMALIZE, OPT_Wnormalized_}, + {CPP_W_INVALID_PCH, OPT_Winvalid_pch}, + {CPP_W_WARNING_DIRECTIVE, OPT_Wcpp}, + {CPP_W_NONE, 0} +}; + +/* Return the gcc option code associated with the reason for a cpp + message, or 0 if none. */ + +static int +c_option_controlling_cpp_error (int reason) +{ + const struct reason_option_codes_t *entry; + + for (entry = option_codes; entry->reason != CPP_W_NONE; entry++) + { + if (entry->reason == reason) + return entry->option_code; + } + return 0; +} + +/* Callback from cpp_error for PFILE to print diagnostics from the + preprocessor. The diagnostic is of type LEVEL, with REASON set + to the reason code if LEVEL is represents a warning, at location + LOCATION unless this is after lexing and the compiler's location + should be used instead, with column number possibly overridden by + COLUMN_OVERRIDE if not zero; MSG is the translated message and AP + the arguments. Returns true if a diagnostic was emitted, false + otherwise. */ + +bool +c_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, int reason, + location_t location, unsigned int column_override, + const char *msg, va_list *ap) +{ + diagnostic_info diagnostic; + diagnostic_t dlevel; + bool save_warn_system_headers = global_dc->warn_system_headers; + bool ret; + + switch (level) + { + case CPP_DL_WARNING_SYSHDR: + if (flag_no_output) + return false; + global_dc->warn_system_headers = 1; + /* Fall through. */ + case CPP_DL_WARNING: + if (flag_no_output) + return false; + dlevel = DK_WARNING; + break; + case CPP_DL_PEDWARN: + if (flag_no_output && !flag_pedantic_errors) + return false; + dlevel = DK_PEDWARN; + break; + case CPP_DL_ERROR: + dlevel = DK_ERROR; + break; + case CPP_DL_ICE: + dlevel = DK_ICE; + break; + case CPP_DL_NOTE: + dlevel = DK_NOTE; + break; + case CPP_DL_FATAL: + dlevel = DK_FATAL; + break; + default: + gcc_unreachable (); + } + if (done_lexing) + location = input_location; + diagnostic_set_info_translated (&diagnostic, msg, ap, + location, dlevel); + if (column_override) + diagnostic_override_column (&diagnostic, column_override); + diagnostic_override_option_index (&diagnostic, + c_option_controlling_cpp_error (reason)); + ret = report_diagnostic (&diagnostic); + if (level == CPP_DL_WARNING_SYSHDR) + global_dc->warn_system_headers = save_warn_system_headers; + return ret; +} + +/* Convert a character from the host to the target execution character + set. cpplib handles this, mostly. */ + +HOST_WIDE_INT +c_common_to_target_charset (HOST_WIDE_INT c) +{ + /* Character constants in GCC proper are sign-extended under -fsigned-char, + zero-extended under -fno-signed-char. cpplib insists that characters + and character constants are always unsigned. Hence we must convert + back and forth. */ + cppchar_t uc = ((cppchar_t)c) & ((((cppchar_t)1) << CHAR_BIT)-1); + + uc = cpp_host_to_exec_charset (parse_in, uc); + + if (flag_signed_char) + return ((HOST_WIDE_INT)uc) << (HOST_BITS_PER_WIDE_INT - CHAR_TYPE_SIZE) + >> (HOST_BITS_PER_WIDE_INT - CHAR_TYPE_SIZE); + else + return uc; +} + +/* Build the result of __builtin_offsetof. EXPR is a nested sequence of + component references, with STOP_REF, or alternatively an INDIRECT_REF of + NULL, at the bottom; much like the traditional rendering of offsetof as a + macro. Returns the folded and properly cast result. */ + +static tree +fold_offsetof_1 (tree expr, tree stop_ref) +{ + enum tree_code code = PLUS_EXPR; + tree base, off, t; + + if (expr == stop_ref && TREE_CODE (expr) != ERROR_MARK) + return size_zero_node; + + switch (TREE_CODE (expr)) + { + case ERROR_MARK: + return expr; + + case VAR_DECL: + error ("cannot apply % to static data member %qD", expr); + return error_mark_node; + + case CALL_EXPR: + case TARGET_EXPR: + error ("cannot apply % when % is overloaded"); + return error_mark_node; + + case NOP_EXPR: + case INDIRECT_REF: + if (!integer_zerop (TREE_OPERAND (expr, 0))) + { + error ("cannot apply % to a non constant address"); + return error_mark_node; + } + return size_zero_node; + + case COMPONENT_REF: + base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref); + if (base == error_mark_node) + return base; + + t = TREE_OPERAND (expr, 1); + if (DECL_C_BIT_FIELD (t)) + { + error ("attempt to take address of bit-field structure " + "member %qD", t); + return error_mark_node; + } + off = size_binop_loc (input_location, PLUS_EXPR, DECL_FIELD_OFFSET (t), + size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), + 1) + / BITS_PER_UNIT)); + break; + + case ARRAY_REF: + base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref); + if (base == error_mark_node) + return base; + + t = TREE_OPERAND (expr, 1); + if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0) + { + code = MINUS_EXPR; + t = fold_build1_loc (input_location, NEGATE_EXPR, TREE_TYPE (t), t); + } + t = convert (sizetype, t); + off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t); + + /* Check if the offset goes beyond the upper bound of the array. */ + if (code == PLUS_EXPR && TREE_CODE (t) == INTEGER_CST) + { + tree upbound = array_ref_up_bound (expr); + if (upbound != NULL_TREE + && TREE_CODE (upbound) == INTEGER_CST + && !tree_int_cst_equal (upbound, + TYPE_MAX_VALUE (TREE_TYPE (upbound)))) + { + upbound = size_binop (PLUS_EXPR, upbound, + build_int_cst (TREE_TYPE (upbound), 1)); + if (tree_int_cst_lt (upbound, t)) + { + tree v; + + for (v = TREE_OPERAND (expr, 0); + TREE_CODE (v) == COMPONENT_REF; + v = TREE_OPERAND (v, 0)) + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) + == RECORD_TYPE) + { + tree fld_chain = TREE_CHAIN (TREE_OPERAND (v, 1)); + for (; fld_chain; fld_chain = TREE_CHAIN (fld_chain)) + if (TREE_CODE (fld_chain) == FIELD_DECL) + break; + + if (fld_chain) + break; + } + /* Don't warn if the array might be considered a poor + man's flexible array member with a very permissive + definition thereof. */ + if (TREE_CODE (v) == ARRAY_REF + || TREE_CODE (v) == COMPONENT_REF) + warning (OPT_Warray_bounds, + "index %E denotes an offset " + "greater than size of %qT", + t, TREE_TYPE (TREE_OPERAND (expr, 0))); + } + } + } + break; + + case COMPOUND_EXPR: + /* Handle static members of volatile structs. */ + t = TREE_OPERAND (expr, 1); + gcc_assert (TREE_CODE (t) == VAR_DECL); + return fold_offsetof_1 (t, stop_ref); + + default: + gcc_unreachable (); + } + + return size_binop (code, base, off); +} + +tree +fold_offsetof (tree expr, tree stop_ref) +{ + /* Convert back from the internal sizetype to size_t. */ + return convert (size_type_node, fold_offsetof_1 (expr, stop_ref)); +} + +/* Print an error message for an invalid lvalue. USE says + how the lvalue is being used and so selects the error message. */ + +void +lvalue_error (enum lvalue_use use) +{ + switch (use) + { + case lv_assign: + error ("lvalue required as left operand of assignment"); + break; + case lv_increment: + error ("lvalue required as increment operand"); + break; + case lv_decrement: + error ("lvalue required as decrement operand"); + break; + case lv_addressof: + error ("lvalue required as unary %<&%> operand"); + break; + case lv_asm: + error ("lvalue required in asm statement"); + break; + default: + gcc_unreachable (); + } +} + +/* *PTYPE is an incomplete array. Complete it with a domain based on + INITIAL_VALUE. If INITIAL_VALUE is not present, use 1 if DO_DEFAULT + is true. Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered, + 2 if INITIAL_VALUE was NULL, and 3 if INITIAL_VALUE was empty. */ + +int +complete_array_type (tree *ptype, tree initial_value, bool do_default) +{ + tree maxindex, type, main_type, elt, unqual_elt; + int failure = 0, quals; + hashval_t hashcode = 0; + + maxindex = size_zero_node; + if (initial_value) + { + if (TREE_CODE (initial_value) == STRING_CST) + { + int eltsize + = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value))); + maxindex = size_int (TREE_STRING_LENGTH (initial_value)/eltsize - 1); + } + else if (TREE_CODE (initial_value) == CONSTRUCTOR) + { + VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (initial_value); + + if (VEC_empty (constructor_elt, v)) + { + if (pedantic) + failure = 3; + maxindex = integer_minus_one_node; + } + else + { + tree curindex; + unsigned HOST_WIDE_INT cnt; + constructor_elt *ce; + bool fold_p = false; + + if (VEC_index (constructor_elt, v, 0)->index) + maxindex = fold_convert_loc (input_location, sizetype, + VEC_index (constructor_elt, + v, 0)->index); + curindex = maxindex; + + for (cnt = 1; + VEC_iterate (constructor_elt, v, cnt, ce); + cnt++) + { + bool curfold_p = false; + if (ce->index) + curindex = ce->index, curfold_p = true; + else + { + if (fold_p) + curindex = fold_convert (sizetype, curindex); + curindex = size_binop (PLUS_EXPR, curindex, + size_one_node); + } + if (tree_int_cst_lt (maxindex, curindex)) + maxindex = curindex, fold_p = curfold_p; + } + if (fold_p) + maxindex = fold_convert (sizetype, maxindex); + } + } + else + { + /* Make an error message unless that happened already. */ + if (initial_value != error_mark_node) + failure = 1; + } + } + else + { + failure = 2; + if (!do_default) + return failure; + } + + type = *ptype; + elt = TREE_TYPE (type); + quals = TYPE_QUALS (strip_array_types (elt)); + if (quals == 0) + unqual_elt = elt; + else + unqual_elt = c_build_qualified_type (elt, KEEP_QUAL_ADDR_SPACE (quals)); + + /* Using build_distinct_type_copy and modifying things afterward instead + of using build_array_type to create a new type preserves all of the + TYPE_LANG_FLAG_? bits that the front end may have set. */ + main_type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + TREE_TYPE (main_type) = unqual_elt; + TYPE_DOMAIN (main_type) = build_index_type (maxindex); + layout_type (main_type); + + /* Make sure we have the canonical MAIN_TYPE. */ + hashcode = iterative_hash_object (TYPE_HASH (unqual_elt), hashcode); + hashcode = iterative_hash_object (TYPE_HASH (TYPE_DOMAIN (main_type)), + hashcode); + main_type = type_hash_canon (hashcode, main_type); + + /* Fix the canonical type. */ + if (TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (main_type)) + || TYPE_STRUCTURAL_EQUALITY_P (TYPE_DOMAIN (main_type))) + SET_TYPE_STRUCTURAL_EQUALITY (main_type); + else if (TYPE_CANONICAL (TREE_TYPE (main_type)) != TREE_TYPE (main_type) + || (TYPE_CANONICAL (TYPE_DOMAIN (main_type)) + != TYPE_DOMAIN (main_type))) + TYPE_CANONICAL (main_type) + = build_array_type (TYPE_CANONICAL (TREE_TYPE (main_type)), + TYPE_CANONICAL (TYPE_DOMAIN (main_type))); + else + TYPE_CANONICAL (main_type) = main_type; + + if (quals == 0) + type = main_type; + else + type = c_build_qualified_type (main_type, quals); + + if (COMPLETE_TYPE_P (type) + && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST + && TREE_OVERFLOW (TYPE_SIZE_UNIT (type))) + { + error ("size of array is too large"); + /* If we proceed with the array type as it is, we'll eventually + crash in tree_low_cst(). */ + type = error_mark_node; + } + + *ptype = type; + return failure; +} + + +/* Used to help initialize the builtin-types.def table. When a type of + the correct size doesn't exist, use error_mark_node instead of NULL. + The later results in segfaults even when a decl using the type doesn't + get invoked. */ + +tree +builtin_type_for_size (int size, bool unsignedp) +{ + tree type = lang_hooks.types.type_for_size (size, unsignedp); + return type ? type : error_mark_node; +} + +/* A helper function for resolve_overloaded_builtin in resolving the + overloaded __sync_ builtins. Returns a positive power of 2 if the + first operand of PARAMS is a pointer to a supported data type. + Returns 0 if an error is encountered. */ + +static int +sync_resolve_size (tree function, VEC(tree,gc) *params) +{ + tree type; + int size; + + if (VEC_empty (tree, params)) + { + error ("too few arguments to function %qE", function); + return 0; + } + + type = TREE_TYPE (VEC_index (tree, params, 0)); + if (TREE_CODE (type) != POINTER_TYPE) + goto incompatible; + + type = TREE_TYPE (type); + if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) + goto incompatible; + + size = tree_low_cst (TYPE_SIZE_UNIT (type), 1); + if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16) + return size; + + incompatible: + error ("incompatible type for argument %d of %qE", 1, function); + return 0; +} + +/* A helper function for resolve_overloaded_builtin. Adds casts to + PARAMS to make arguments match up with those of FUNCTION. Drops + the variadic arguments at the end. Returns false if some error + was encountered; true on success. */ + +static bool +sync_resolve_params (tree orig_function, tree function, VEC(tree, gc) *params) +{ + tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (function)); + tree ptype; + unsigned int parmnum; + + /* We've declared the implementation functions to use "volatile void *" + as the pointer parameter, so we shouldn't get any complaints from the + call to check_function_arguments what ever type the user used. */ + arg_types = TREE_CHAIN (arg_types); + ptype = TREE_TYPE (TREE_TYPE (VEC_index (tree, params, 0))); + + /* For the rest of the values, we need to cast these to FTYPE, so that we + don't get warnings for passing pointer types, etc. */ + parmnum = 0; + while (arg_types != void_list_node) + { + tree val; + + ++parmnum; + if (VEC_length (tree, params) <= parmnum) + { + error ("too few arguments to function %qE", orig_function); + return false; + } + + /* ??? Ideally for the first conversion we'd use convert_for_assignment + so that we get warnings for anything that doesn't match the pointer + type. This isn't portable across the C and C++ front ends atm. */ + val = VEC_index (tree, params, parmnum); + val = convert (ptype, val); + val = convert (TREE_VALUE (arg_types), val); + VEC_replace (tree, params, parmnum, val); + + arg_types = TREE_CHAIN (arg_types); + } + + /* The definition of these primitives is variadic, with the remaining + being "an optional list of variables protected by the memory barrier". + No clue what that's supposed to mean, precisely, but we consider all + call-clobbered variables to be protected so we're safe. */ + VEC_truncate (tree, params, parmnum + 1); + + return true; +} + +/* A helper function for resolve_overloaded_builtin. Adds a cast to + RESULT to make it match the type of the first pointer argument in + PARAMS. */ + +static tree +sync_resolve_return (tree first_param, tree result) +{ + tree ptype = TREE_TYPE (TREE_TYPE (first_param)); + ptype = TYPE_MAIN_VARIANT (ptype); + return convert (ptype, result); +} + +/* Some builtin functions are placeholders for other expressions. This + function should be called immediately after parsing the call expression + before surrounding code has committed to the type of the expression. + + LOC is the location of the builtin call. + + FUNCTION is the DECL that has been invoked; it is known to be a builtin. + PARAMS is the argument list for the call. The return value is non-null + when expansion is complete, and null if normal processing should + continue. */ + +tree +resolve_overloaded_builtin (location_t loc, tree function, VEC(tree,gc) *params) +{ + enum built_in_function orig_code = DECL_FUNCTION_CODE (function); + switch (DECL_BUILT_IN_CLASS (function)) + { + case BUILT_IN_NORMAL: + break; + case BUILT_IN_MD: + if (targetm.resolve_overloaded_builtin) + return targetm.resolve_overloaded_builtin (loc, function, params); + else + return NULL_TREE; + default: + return NULL_TREE; + } + + /* Handle BUILT_IN_NORMAL here. */ + switch (orig_code) + { + case BUILT_IN_FETCH_AND_ADD_N: + case BUILT_IN_FETCH_AND_SUB_N: + case BUILT_IN_FETCH_AND_OR_N: + case BUILT_IN_FETCH_AND_AND_N: + case BUILT_IN_FETCH_AND_XOR_N: + case BUILT_IN_FETCH_AND_NAND_N: + case BUILT_IN_ADD_AND_FETCH_N: + case BUILT_IN_SUB_AND_FETCH_N: + case BUILT_IN_OR_AND_FETCH_N: + case BUILT_IN_AND_AND_FETCH_N: + case BUILT_IN_XOR_AND_FETCH_N: + case BUILT_IN_NAND_AND_FETCH_N: + case BUILT_IN_BOOL_COMPARE_AND_SWAP_N: + case BUILT_IN_VAL_COMPARE_AND_SWAP_N: + case BUILT_IN_LOCK_TEST_AND_SET_N: + case BUILT_IN_LOCK_RELEASE_N: + { + int n = sync_resolve_size (function, params); + tree new_function, first_param, result; + + if (n == 0) + return error_mark_node; + + new_function = built_in_decls[orig_code + exact_log2 (n) + 1]; + if (!sync_resolve_params (function, new_function, params)) + return error_mark_node; + + first_param = VEC_index (tree, params, 0); + result = build_function_call_vec (loc, new_function, params, NULL); + if (orig_code != BUILT_IN_BOOL_COMPARE_AND_SWAP_N + && orig_code != BUILT_IN_LOCK_RELEASE_N) + result = sync_resolve_return (first_param, result); + + return result; + } + + default: + return NULL_TREE; + } +} + +/* Ignoring their sign, return true if two scalar types are the same. */ +bool +same_scalar_type_ignoring_signedness (tree t1, tree t2) +{ + enum tree_code c1 = TREE_CODE (t1), c2 = TREE_CODE (t2); + + gcc_assert ((c1 == INTEGER_TYPE || c1 == REAL_TYPE || c1 == FIXED_POINT_TYPE) + && (c2 == INTEGER_TYPE || c2 == REAL_TYPE + || c2 == FIXED_POINT_TYPE)); + + /* Equality works here because c_common_signed_type uses + TYPE_MAIN_VARIANT. */ + return c_common_signed_type (t1) + == c_common_signed_type (t2); +} + +/* Check for missing format attributes on function pointers. LTYPE is + the new type or left-hand side type. RTYPE is the old type or + right-hand side type. Returns TRUE if LTYPE is missing the desired + attribute. */ + +bool +check_missing_format_attribute (tree ltype, tree rtype) +{ + tree const ttr = TREE_TYPE (rtype), ttl = TREE_TYPE (ltype); + tree ra; + + for (ra = TYPE_ATTRIBUTES (ttr); ra; ra = TREE_CHAIN (ra)) + if (is_attribute_p ("format", TREE_PURPOSE (ra))) + break; + if (ra) + { + tree la; + for (la = TYPE_ATTRIBUTES (ttl); la; la = TREE_CHAIN (la)) + if (is_attribute_p ("format", TREE_PURPOSE (la))) + break; + return !la; + } + else + return false; +} + +/* Subscripting with type char is likely to lose on a machine where + chars are signed. So warn on any machine, but optionally. Don't + warn for unsigned char since that type is safe. Don't warn for + signed char because anyone who uses that must have done so + deliberately. Furthermore, we reduce the false positive load by + warning only for non-constant value of type char. */ + +void +warn_array_subscript_with_type_char (tree index) +{ + if (TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node + && TREE_CODE (index) != INTEGER_CST) + warning (OPT_Wchar_subscripts, "array subscript has type %"); +} + +/* Implement -Wparentheses for the unexpected C precedence rules, to + cover cases like x + y << z which readers are likely to + misinterpret. We have seen an expression in which CODE is a binary + operator used to combine expressions ARG_LEFT and ARG_RIGHT, which + before folding had CODE_LEFT and CODE_RIGHT. CODE_LEFT and + CODE_RIGHT may be ERROR_MARK, which means that that side of the + expression was not formed using a binary or unary operator, or it + was enclosed in parentheses. */ + +void +warn_about_parentheses (enum tree_code code, + enum tree_code code_left, tree arg_left, + enum tree_code code_right, tree arg_right) +{ + if (!warn_parentheses) + return; + + /* This macro tests that the expression ARG with original tree code + CODE appears to be a boolean expression. or the result of folding a + boolean expression. */ +#define APPEARS_TO_BE_BOOLEAN_EXPR_P(CODE, ARG) \ + (truth_value_p (TREE_CODE (ARG)) \ + || TREE_CODE (TREE_TYPE (ARG)) == BOOLEAN_TYPE \ + /* Folding may create 0 or 1 integers from other expressions. */ \ + || ((CODE) != INTEGER_CST \ + && (integer_onep (ARG) || integer_zerop (ARG)))) + + switch (code) + { + case LSHIFT_EXPR: + if (code_left == PLUS_EXPR || code_right == PLUS_EXPR) + warning (OPT_Wparentheses, + "suggest parentheses around %<+%> inside %<<<%>"); + else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR) + warning (OPT_Wparentheses, + "suggest parentheses around %<-%> inside %<<<%>"); + return; + + case RSHIFT_EXPR: + if (code_left == PLUS_EXPR || code_right == PLUS_EXPR) + warning (OPT_Wparentheses, + "suggest parentheses around %<+%> inside %<>>%>"); + else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR) + warning (OPT_Wparentheses, + "suggest parentheses around %<-%> inside %<>>%>"); + return; + + case TRUTH_ORIF_EXPR: + if (code_left == TRUTH_ANDIF_EXPR || code_right == TRUTH_ANDIF_EXPR) + warning (OPT_Wparentheses, + "suggest parentheses around %<&&%> within %<||%>"); + return; + + case BIT_IOR_EXPR: + if (code_left == BIT_AND_EXPR || code_left == BIT_XOR_EXPR + || code_left == PLUS_EXPR || code_left == MINUS_EXPR + || code_right == BIT_AND_EXPR || code_right == BIT_XOR_EXPR + || code_right == PLUS_EXPR || code_right == MINUS_EXPR) + warning (OPT_Wparentheses, + "suggest parentheses around arithmetic in operand of %<|%>"); + /* Check cases like x|y==z */ + else if (TREE_CODE_CLASS (code_left) == tcc_comparison + || TREE_CODE_CLASS (code_right) == tcc_comparison) + warning (OPT_Wparentheses, + "suggest parentheses around comparison in operand of %<|%>"); + /* Check cases like !x | y */ + else if (code_left == TRUTH_NOT_EXPR + && !APPEARS_TO_BE_BOOLEAN_EXPR_P (code_right, arg_right)) + warning (OPT_Wparentheses, "suggest parentheses around operand of " + "% or change %<|%> to %<||%> or % to %<~%>"); + return; + + case BIT_XOR_EXPR: + if (code_left == BIT_AND_EXPR + || code_left == PLUS_EXPR || code_left == MINUS_EXPR + || code_right == BIT_AND_EXPR + || code_right == PLUS_EXPR || code_right == MINUS_EXPR) + warning (OPT_Wparentheses, + "suggest parentheses around arithmetic in operand of %<^%>"); + /* Check cases like x^y==z */ + else if (TREE_CODE_CLASS (code_left) == tcc_comparison + || TREE_CODE_CLASS (code_right) == tcc_comparison) + warning (OPT_Wparentheses, + "suggest parentheses around comparison in operand of %<^%>"); + return; + + case BIT_AND_EXPR: + if (code_left == PLUS_EXPR || code_right == PLUS_EXPR) + warning (OPT_Wparentheses, + "suggest parentheses around %<+%> in operand of %<&%>"); + else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR) + warning (OPT_Wparentheses, + "suggest parentheses around %<-%> in operand of %<&%>"); + /* Check cases like x&y==z */ + else if (TREE_CODE_CLASS (code_left) == tcc_comparison + || TREE_CODE_CLASS (code_right) == tcc_comparison) + warning (OPT_Wparentheses, + "suggest parentheses around comparison in operand of %<&%>"); + /* Check cases like !x & y */ + else if (code_left == TRUTH_NOT_EXPR + && !APPEARS_TO_BE_BOOLEAN_EXPR_P (code_right, arg_right)) + warning (OPT_Wparentheses, "suggest parentheses around operand of " + "% or change %<&%> to %<&&%> or % to %<~%>"); + return; + + case EQ_EXPR: + if (TREE_CODE_CLASS (code_left) == tcc_comparison + || TREE_CODE_CLASS (code_right) == tcc_comparison) + warning (OPT_Wparentheses, + "suggest parentheses around comparison in operand of %<==%>"); + return; + case NE_EXPR: + if (TREE_CODE_CLASS (code_left) == tcc_comparison + || TREE_CODE_CLASS (code_right) == tcc_comparison) + warning (OPT_Wparentheses, + "suggest parentheses around comparison in operand of %"); + return; + + default: + if (TREE_CODE_CLASS (code) == tcc_comparison + && ((TREE_CODE_CLASS (code_left) == tcc_comparison + && code_left != NE_EXPR && code_left != EQ_EXPR + && INTEGRAL_TYPE_P (TREE_TYPE (arg_left))) + || (TREE_CODE_CLASS (code_right) == tcc_comparison + && code_right != NE_EXPR && code_right != EQ_EXPR + && INTEGRAL_TYPE_P (TREE_TYPE (arg_right))))) + warning (OPT_Wparentheses, "comparisons like % do not " + "have their mathematical meaning"); + return; + } +#undef NOT_A_BOOLEAN_EXPR_P +} + +/* If LABEL (a LABEL_DECL) has not been used, issue a warning. */ + +void +warn_for_unused_label (tree label) +{ + if (!TREE_USED (label)) + { + if (DECL_INITIAL (label)) + warning (OPT_Wunused_label, "label %q+D defined but not used", label); + else + warning (OPT_Wunused_label, "label %q+D declared but not defined", label); + } +} + +#ifndef TARGET_HAS_TARGETCM +struct gcc_targetcm targetcm = TARGETCM_INITIALIZER; +#endif + +/* Warn for division by zero according to the value of DIVISOR. LOC + is the location of the division operator. */ + +void +warn_for_div_by_zero (location_t loc, tree divisor) +{ + /* If DIVISOR is zero, and has integral or fixed-point type, issue a warning + about division by zero. Do not issue a warning if DIVISOR has a + floating-point type, since we consider 0.0/0.0 a valid way of + generating a NaN. */ + if (c_inhibit_evaluation_warnings == 0 + && (integer_zerop (divisor) || fixed_zerop (divisor))) + warning_at (loc, OPT_Wdiv_by_zero, "division by zero"); +} + +/* Subroutine of build_binary_op. Give warnings for comparisons + between signed and unsigned quantities that may fail. Do the + checking based on the original operand trees ORIG_OP0 and ORIG_OP1, + so that casts will be considered, but default promotions won't + be. + + LOCATION is the location of the comparison operator. + + The arguments of this function map directly to local variables + of build_binary_op. */ + +void +warn_for_sign_compare (location_t location, + tree orig_op0, tree orig_op1, + tree op0, tree op1, + tree result_type, enum tree_code resultcode) +{ + int op0_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op0)); + int op1_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op1)); + int unsignedp0, unsignedp1; + + /* In C++, check for comparison of different enum types. */ + if (c_dialect_cxx() + && TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE + && TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0)) + != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1))) + { + warning_at (location, + OPT_Wsign_compare, "comparison between types %qT and %qT", + TREE_TYPE (orig_op0), TREE_TYPE (orig_op1)); + } + + /* Do not warn if the comparison is being done in a signed type, + 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 */; + /* Do not warn if both operands are unsigned. */ + else if (op0_signed == op1_signed) + /* OK */; + else + { + tree sop, uop, base_type; + bool ovf; + + if (op0_signed) + sop = orig_op0, uop = orig_op1; + else + sop = orig_op1, uop = orig_op0; + + STRIP_TYPE_NOPS (sop); + STRIP_TYPE_NOPS (uop); + base_type = (TREE_CODE (result_type) == COMPLEX_TYPE + ? TREE_TYPE (result_type) : result_type); + + /* Do not warn if the signed quantity is an unsuffixed integer + literal (or some static constant expression involving such + literals or a conditional expression involving such literals) + and it is non-negative. */ + if (tree_expr_nonnegative_warnv_p (sop, &ovf)) + /* OK */; + /* Do not warn if the comparison is an equality operation, the + unsigned quantity is an integral constant, and it would fit + in the result if the result were signed. */ + else if (TREE_CODE (uop) == INTEGER_CST + && (resultcode == EQ_EXPR || resultcode == NE_EXPR) + && int_fits_type_p (uop, c_common_signed_type (base_type))) + /* OK */; + /* In C, do not warn if the unsigned quantity is an enumeration + constant and its maximum value would fit in the result if the + result were signed. */ + else if (!c_dialect_cxx() && TREE_CODE (uop) == INTEGER_CST + && TREE_CODE (TREE_TYPE (uop)) == ENUMERAL_TYPE + && int_fits_type_p (TYPE_MAX_VALUE (TREE_TYPE (uop)), + c_common_signed_type (base_type))) + /* OK */; + else + warning_at (location, + OPT_Wsign_compare, + "comparison between signed and unsigned integer expressions"); + } + + /* Warn if two unsigned values are being compared in a size larger + than their original size, and one (and only one) is the result of + a `~' operator. This comparison will always fail. + + Also warn if one operand is a constant, and the constant does not + have all bits set that are set in the ~ operand when it is + extended. */ + + op0 = get_narrower (op0, &unsignedp0); + op1 = get_narrower (op1, &unsignedp1); + + if ((TREE_CODE (op0) == BIT_NOT_EXPR) + ^ (TREE_CODE (op1) == BIT_NOT_EXPR)) + { + if (TREE_CODE (op0) == BIT_NOT_EXPR) + op0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0); + if (TREE_CODE (op1) == BIT_NOT_EXPR) + op1 = get_narrower (TREE_OPERAND (op1, 0), &unsignedp1); + + if (host_integerp (op0, 0) || host_integerp (op1, 0)) + { + tree primop; + HOST_WIDE_INT constant, mask; + int unsignedp; + unsigned int bits; + + if (host_integerp (op0, 0)) + { + primop = op1; + unsignedp = unsignedp1; + constant = tree_low_cst (op0, 0); + } + else + { + primop = op0; + unsignedp = unsignedp0; + constant = tree_low_cst (op1, 0); + } + + bits = TYPE_PRECISION (TREE_TYPE (primop)); + if (bits < TYPE_PRECISION (result_type) + && bits < HOST_BITS_PER_LONG && unsignedp) + { + mask = (~ (HOST_WIDE_INT) 0) << bits; + if ((mask & constant) != mask) + { + if (constant == 0) + warning (OPT_Wsign_compare, + "promoted ~unsigned is always non-zero"); + else + warning_at (location, OPT_Wsign_compare, + "comparison of promoted ~unsigned with constant"); + } + } + } + else if (unsignedp0 && unsignedp1 + && (TYPE_PRECISION (TREE_TYPE (op0)) + < TYPE_PRECISION (result_type)) + && (TYPE_PRECISION (TREE_TYPE (op1)) + < TYPE_PRECISION (result_type))) + warning_at (location, OPT_Wsign_compare, + "comparison of promoted ~unsigned with unsigned"); + } +} + +/* Setup a TYPE_DECL node as a typedef representation. + + X is a TYPE_DECL for a typedef statement. Create a brand new + ..._TYPE node (which will be just a variant of the existing + ..._TYPE node with identical properties) and then install X + as the TYPE_NAME of this brand new (duplicate) ..._TYPE node. + + The whole point here is to end up with a situation where each + and every ..._TYPE node the compiler creates will be uniquely + associated with AT MOST one node representing a typedef name. + This way, even though the compiler substitutes corresponding + ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very + early on, later parts of the compiler can always do the reverse + translation and get back the corresponding typedef name. For + example, given: + + typedef struct S MY_TYPE; + MY_TYPE object; + + Later parts of the compiler might only know that `object' was of + type `struct S' if it were not for code just below. With this + code however, later parts of the compiler see something like: + + struct S' == struct S + typedef struct S' MY_TYPE; + struct S' object; + + And they can then deduce (from the node for type struct S') that + the original object declaration was: + + MY_TYPE object; + + Being able to do this is important for proper support of protoize, + and also for generating precise symbolic debugging information + which takes full account of the programmer's (typedef) vocabulary. + + Obviously, we don't want to generate a duplicate ..._TYPE node if + the TYPE_DECL node that we are now processing really represents a + standard built-in type. */ + +void +set_underlying_type (tree x) +{ + if (x == error_mark_node) + return; + if (DECL_IS_BUILTIN (x)) + { + if (TYPE_NAME (TREE_TYPE (x)) == 0) + TYPE_NAME (TREE_TYPE (x)) = x; + } + else if (TREE_TYPE (x) != error_mark_node + && DECL_ORIGINAL_TYPE (x) == NULL_TREE) + { + tree tt = TREE_TYPE (x); + DECL_ORIGINAL_TYPE (x) = tt; + tt = build_variant_type_copy (tt); + TYPE_STUB_DECL (tt) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x)); + TYPE_NAME (tt) = x; + TREE_USED (tt) = TREE_USED (x); + TREE_TYPE (x) = tt; + } +} + +/* Returns true if X is a typedef decl. */ + +bool +is_typedef_decl (tree x) +{ + return (x && TREE_CODE (x) == TYPE_DECL + && DECL_ORIGINAL_TYPE (x) != NULL_TREE); +} + +/* Record the types used by the current global variable declaration + being parsed, so that we can decide later to emit their debug info. + Those types are in types_used_by_cur_var_decl, and we are going to + store them in the types_used_by_vars_hash hash table. + DECL is the declaration of the global variable that has been parsed. */ + +void +record_types_used_by_current_var_decl (tree decl) +{ + gcc_assert (decl && DECL_P (decl) && TREE_STATIC (decl)); + + if (types_used_by_cur_var_decl) + { + tree node; + for (node = types_used_by_cur_var_decl; + node; + node = TREE_CHAIN (node)) + { + tree type = TREE_PURPOSE (node); + types_used_by_var_decl_insert (type, decl); + } + types_used_by_cur_var_decl = NULL; + } +} + +/* The C and C++ parsers both use vectors to hold function arguments. + For efficiency, we keep a cache of unused vectors. This is the + cache. */ + +typedef VEC(tree,gc)* tree_gc_vec; +DEF_VEC_P(tree_gc_vec); +DEF_VEC_ALLOC_P(tree_gc_vec,gc); +static GTY((deletable)) VEC(tree_gc_vec,gc) *tree_vector_cache; + +/* Return a new vector from the cache. If the cache is empty, + allocate a new vector. These vectors are GC'ed, so it is OK if the + pointer is not released.. */ + +VEC(tree,gc) * +make_tree_vector (void) +{ + if (!VEC_empty (tree_gc_vec, tree_vector_cache)) + return VEC_pop (tree_gc_vec, tree_vector_cache); + else + { + /* Passing 0 to VEC_alloc returns NULL, and our callers require + that we always return a non-NULL value. The vector code uses + 4 when growing a NULL vector, so we do too. */ + return VEC_alloc (tree, gc, 4); + } +} + +/* Release a vector of trees back to the cache. */ + +void +release_tree_vector (VEC(tree,gc) *vec) +{ + if (vec != NULL) + { + VEC_truncate (tree, vec, 0); + VEC_safe_push (tree_gc_vec, gc, tree_vector_cache, vec); + } +} + +/* Get a new tree vector holding a single tree. */ + +VEC(tree,gc) * +make_tree_vector_single (tree t) +{ + VEC(tree,gc) *ret = make_tree_vector (); + VEC_quick_push (tree, ret, t); + return ret; +} + +/* Get a new tree vector which is a copy of an existing one. */ + +VEC(tree,gc) * +make_tree_vector_copy (const VEC(tree,gc) *orig) +{ + VEC(tree,gc) *ret; + unsigned int ix; + tree t; + + ret = make_tree_vector (); + VEC_reserve (tree, gc, ret, VEC_length (tree, orig)); + for (ix = 0; VEC_iterate (tree, orig, ix, t); ++ix) + VEC_quick_push (tree, ret, t); + return ret; +} + +#include "gt-c-family-c-common.h" diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def new file mode 100644 index 0000000..1c59363 --- /dev/null +++ b/gcc/c-family/c-common.def @@ -0,0 +1,53 @@ +/* This file contains the definitions and documentation for the + additional tree codes used in the GNU C compiler (see tree.def + for the standard codes). + Copyright (C) 1987, 1988, 1990, 1993, 1997, 1998, + 1999, 2000, 2001, 2004, 2005, 2007, 2009 Free Software Foundation, Inc. + Written by Benjamin Chelf + +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 +. */ + +/* Tree nodes used in the C frontend. These are also shared with the + C++ and Objective C frontends. */ + +/* A C_MAYBE_CONST_EXPR, currently only used for C and Objective C, + tracks information about constancy of an expression and VLA type + sizes or VM expressions from typeof that need to be evaluated + before the main expression. It is used during parsing and removed + in c_fully_fold. C_MAYBE_CONST_EXPR_PRE is the expression to + evaluate first, if not NULL; C_MAYBE_CONST_EXPR_EXPR is the main + expression. If C_MAYBE_CONST_EXPR_INT_OPERANDS is set then the + expression may be used in an unevaluated part of an integer + constant expression, but not in an evaluated part. If + C_MAYBE_CONST_EXPR_NON_CONST is set then the expression contains + something that cannot occur in an evaluated part of a constant + expression (or outside of sizeof in C90 mode); otherwise it does + not. */ +DEFTREECODE (C_MAYBE_CONST_EXPR, "c_maybe_const_expr", tcc_expression, 2) + +/* An EXCESS_PRECISION_EXPR, currently only used for C and Objective + C, represents an expression evaluated in greater range or precision + than its type. The type of the EXCESS_PRECISION_EXPR is the + semantic type while the operand represents what is actually being + evaluated. */ +DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1) + +/* +Local variables: +mode:c +End: +*/ diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h new file mode 100644 index 0000000..289d70c --- /dev/null +++ b/gcc/c-family/c-common.h @@ -0,0 +1,1191 @@ +/* Definitions for c-common.c. + Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + 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 +. */ + +#ifndef GCC_C_COMMON_H +#define GCC_C_COMMON_H + +#include "splay-tree.h" +#include "cpplib.h" +#include "ggc.h" + +/* In order for the format checking to accept the C frontend + diagnostic framework extensions, you must include this file before + toplev.h, not after. The C front end formats are a subset of those + for C++, so they are the appropriate set to use in common code; + cp-tree.h overrides this for C++. */ +#ifndef GCC_DIAG_STYLE +#define GCC_DIAG_STYLE __gcc_cdiag__ +#endif +#include "diagnostic-core.h" + +/* Usage of TREE_LANG_FLAG_?: + 0: TREE_NEGATED_INT (in INTEGER_CST). + IDENTIFIER_MARKED (used by search routines). + DECL_PRETTY_FUNCTION_P (in VAR_DECL) + C_MAYBE_CONST_EXPR_INT_OPERANDS (in C_MAYBE_CONST_EXPR, for C) + 1: C_DECLARED_LABEL_FLAG (in LABEL_DECL) + STATEMENT_LIST_STMT_EXPR (in STATEMENT_LIST) + C_MAYBE_CONST_EXPR_NON_CONST (in C_MAYBE_CONST_EXPR, for C) + 2: unused + 3: STATEMENT_LIST_HAS_LABEL (in STATEMENT_LIST) + 4: unused +*/ + +/* Reserved identifiers. This is the union of all the keywords for C, + C++, and Objective-C. All the type modifiers have to be in one + block at the beginning, because they are used as mask bits. There + are 27 type modifiers; if we add many more we will have to redesign + the mask mechanism. */ + +enum rid +{ + /* Modifiers: */ + /* C, in empirical order of frequency. */ + RID_STATIC = 0, + RID_UNSIGNED, RID_LONG, RID_CONST, RID_EXTERN, + RID_REGISTER, RID_TYPEDEF, RID_SHORT, RID_INLINE, + RID_VOLATILE, RID_SIGNED, RID_AUTO, RID_RESTRICT, + + /* C extensions */ + RID_COMPLEX, RID_THREAD, RID_SAT, + + /* C++ */ + RID_FRIEND, RID_VIRTUAL, RID_EXPLICIT, RID_EXPORT, RID_MUTABLE, + + /* ObjC */ + RID_IN, RID_OUT, RID_INOUT, RID_BYCOPY, RID_BYREF, RID_ONEWAY, + + /* C (reserved and imaginary types not implemented, so any use is a + syntax error) */ + RID_IMAGINARY, + + /* C */ + RID_INT, RID_CHAR, RID_FLOAT, RID_DOUBLE, RID_VOID, + RID_INT128, + RID_ENUM, RID_STRUCT, RID_UNION, RID_IF, RID_ELSE, + RID_WHILE, RID_DO, RID_FOR, RID_SWITCH, RID_CASE, + RID_DEFAULT, RID_BREAK, RID_CONTINUE, RID_RETURN, RID_GOTO, + RID_SIZEOF, + + /* C extensions */ + RID_ASM, RID_TYPEOF, RID_ALIGNOF, RID_ATTRIBUTE, RID_VA_ARG, + RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, + RID_TYPES_COMPATIBLE_P, + RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, + RID_FRACT, RID_ACCUM, + + /* This means to warn that this is a C++ keyword, and then treat it + as a normal identifier. */ + RID_CXX_COMPAT_WARN, + + /* Too many ways of getting the name of a function as a string */ + RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME, + + /* C++ */ + RID_BOOL, RID_WCHAR, RID_CLASS, + RID_PUBLIC, RID_PRIVATE, RID_PROTECTED, + RID_TEMPLATE, RID_NULL, RID_CATCH, + RID_DELETE, RID_FALSE, RID_NAMESPACE, + RID_NEW, RID_OFFSETOF, RID_OPERATOR, + RID_THIS, RID_THROW, RID_TRUE, + RID_TRY, RID_TYPENAME, RID_TYPEID, + RID_USING, RID_CHAR16, RID_CHAR32, + + /* casts */ + RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, + + /* C++ extensions */ + RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, + RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, + RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY, + RID_HAS_TRIVIAL_DESTRUCTOR, RID_HAS_VIRTUAL_DESTRUCTOR, + RID_IS_ABSTRACT, RID_IS_BASE_OF, + RID_IS_CONVERTIBLE_TO, RID_IS_CLASS, + RID_IS_EMPTY, RID_IS_ENUM, + RID_IS_POD, RID_IS_POLYMORPHIC, + RID_IS_STD_LAYOUT, RID_IS_TRIVIAL, + RID_IS_UNION, + + /* C++0x */ + RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT, + + /* Objective-C */ + RID_AT_ENCODE, RID_AT_END, + RID_AT_CLASS, RID_AT_ALIAS, RID_AT_DEFS, + RID_AT_PRIVATE, RID_AT_PROTECTED, RID_AT_PUBLIC, + RID_AT_PROTOCOL, RID_AT_SELECTOR, + RID_AT_THROW, RID_AT_TRY, RID_AT_CATCH, + RID_AT_FINALLY, RID_AT_SYNCHRONIZED, + RID_AT_INTERFACE, + RID_AT_IMPLEMENTATION, + + /* Named address support, mapping the keyword to a particular named address + number. Named address space 0 is reserved for the generic address. If + there are more than 254 named addresses, the addr_space_t type will need + to be grown from an unsigned char to unsigned short. */ + RID_ADDR_SPACE_0, /* generic address */ + RID_ADDR_SPACE_1, + RID_ADDR_SPACE_2, + RID_ADDR_SPACE_3, + RID_ADDR_SPACE_4, + RID_ADDR_SPACE_5, + RID_ADDR_SPACE_6, + RID_ADDR_SPACE_7, + RID_ADDR_SPACE_8, + RID_ADDR_SPACE_9, + RID_ADDR_SPACE_10, + RID_ADDR_SPACE_11, + RID_ADDR_SPACE_12, + RID_ADDR_SPACE_13, + RID_ADDR_SPACE_14, + RID_ADDR_SPACE_15, + + RID_FIRST_ADDR_SPACE = RID_ADDR_SPACE_0, + RID_LAST_ADDR_SPACE = RID_ADDR_SPACE_15, + + RID_MAX, + + RID_FIRST_MODIFIER = RID_STATIC, + RID_LAST_MODIFIER = RID_ONEWAY, + + RID_FIRST_CXX0X = RID_CONSTEXPR, + RID_LAST_CXX0X = RID_STATIC_ASSERT, + RID_FIRST_AT = RID_AT_ENCODE, + RID_LAST_AT = RID_AT_IMPLEMENTATION, + RID_FIRST_PQ = RID_IN, + RID_LAST_PQ = RID_ONEWAY +}; + +#define OBJC_IS_AT_KEYWORD(rid) \ + ((unsigned int) (rid) >= (unsigned int) RID_FIRST_AT && \ + (unsigned int) (rid) <= (unsigned int) RID_LAST_AT) + +#define OBJC_IS_PQ_KEYWORD(rid) \ + ((unsigned int) (rid) >= (unsigned int) RID_FIRST_PQ && \ + (unsigned int) (rid) <= (unsigned int) RID_LAST_PQ) + +/* The elements of `ridpointers' are identifier nodes for the reserved + type names and storage classes. It is indexed by a RID_... value. */ +extern GTY ((length ("(int) RID_MAX"))) tree *ridpointers; + +/* Standard named or nameless data types of the C compiler. */ + +enum c_tree_index +{ + CTI_CHAR16_TYPE, + CTI_CHAR32_TYPE, + CTI_WCHAR_TYPE, + CTI_UNDERLYING_WCHAR_TYPE, + CTI_WINT_TYPE, + CTI_SIGNED_SIZE_TYPE, /* For format checking only. */ + CTI_UNSIGNED_PTRDIFF_TYPE, /* For format checking only. */ + CTI_INTMAX_TYPE, + CTI_UINTMAX_TYPE, + CTI_WIDEST_INT_LIT_TYPE, + CTI_WIDEST_UINT_LIT_TYPE, + + /* Types for , that may not be defined on all + targets. */ + CTI_SIG_ATOMIC_TYPE, + CTI_INT8_TYPE, + CTI_INT16_TYPE, + CTI_INT32_TYPE, + CTI_INT64_TYPE, + CTI_UINT8_TYPE, + CTI_UINT16_TYPE, + CTI_UINT32_TYPE, + CTI_UINT64_TYPE, + CTI_INT_LEAST8_TYPE, + CTI_INT_LEAST16_TYPE, + CTI_INT_LEAST32_TYPE, + CTI_INT_LEAST64_TYPE, + CTI_UINT_LEAST8_TYPE, + CTI_UINT_LEAST16_TYPE, + CTI_UINT_LEAST32_TYPE, + CTI_UINT_LEAST64_TYPE, + CTI_INT_FAST8_TYPE, + CTI_INT_FAST16_TYPE, + CTI_INT_FAST32_TYPE, + CTI_INT_FAST64_TYPE, + CTI_UINT_FAST8_TYPE, + CTI_UINT_FAST16_TYPE, + CTI_UINT_FAST32_TYPE, + CTI_UINT_FAST64_TYPE, + CTI_INTPTR_TYPE, + CTI_UINTPTR_TYPE, + + CTI_CHAR_ARRAY_TYPE, + CTI_CHAR16_ARRAY_TYPE, + CTI_CHAR32_ARRAY_TYPE, + CTI_WCHAR_ARRAY_TYPE, + CTI_INT_ARRAY_TYPE, + CTI_STRING_TYPE, + CTI_CONST_STRING_TYPE, + + /* Type for boolean expressions (bool in C++, int in C). */ + CTI_TRUTHVALUE_TYPE, + CTI_TRUTHVALUE_TRUE, + CTI_TRUTHVALUE_FALSE, + + CTI_DEFAULT_FUNCTION_TYPE, + + /* These are not types, but we have to look them up all the time. */ + CTI_FUNCTION_NAME_DECL, + CTI_PRETTY_FUNCTION_NAME_DECL, + CTI_C99_FUNCTION_NAME_DECL, + CTI_SAVED_FUNCTION_NAME_DECLS, + + CTI_VOID_ZERO, + + CTI_NULL, + + CTI_MAX +}; + +#define C_CPP_HASHNODE(id) \ + (&(((struct c_common_identifier *) (id))->node)) +#define C_RID_CODE(id) \ + ((enum rid) (((struct c_common_identifier *) (id))->node.rid_code)) +#define C_SET_RID_CODE(id, code) \ + (((struct c_common_identifier *) (id))->node.rid_code = (unsigned char) code) + +/* Identifier part common to the C front ends. Inherits from + tree_identifier, despite appearances. */ +struct GTY(()) c_common_identifier { + struct tree_common common; + struct cpp_hashnode node; +}; + +/* An entry in the reserved keyword table. */ + +struct c_common_resword +{ + const char *const word; + ENUM_BITFIELD(rid) const rid : 16; + const unsigned int disable : 16; +}; + +/* Disable mask. Keywords are disabled if (reswords[i].disable & + mask) is _true_. Thus for keywords which are present in all + languages the disable field is zero. */ + +#define D_CONLY 0x001 /* C only (not in C++). */ +#define D_CXXONLY 0x002 /* C++ only (not in C). */ +#define D_C99 0x004 /* In C, C99 only. */ +#define D_CXX0X 0x008 /* In C++, C++0X only. */ +#define D_EXT 0x010 /* GCC extension. */ +#define D_EXT89 0x020 /* GCC extension incorporated in C99. */ +#define D_ASM 0x040 /* Disabled by -fno-asm. */ +#define D_OBJC 0x080 /* In Objective C and neither C nor C++. */ +#define D_CXX_OBJC 0x100 /* In Objective C, and C++, but not C. */ +#define D_CXXWARN 0x200 /* In C warn with -Wcxx-compat. */ + +/* The reserved keyword table. */ +extern const struct c_common_resword c_common_reswords[]; + +/* The number of items in the reserved keyword table. */ +extern const unsigned int num_c_common_reswords; + +#define char16_type_node c_global_trees[CTI_CHAR16_TYPE] +#define char32_type_node c_global_trees[CTI_CHAR32_TYPE] +#define wchar_type_node c_global_trees[CTI_WCHAR_TYPE] +#define underlying_wchar_type_node c_global_trees[CTI_UNDERLYING_WCHAR_TYPE] +#define wint_type_node c_global_trees[CTI_WINT_TYPE] +#define signed_size_type_node c_global_trees[CTI_SIGNED_SIZE_TYPE] +#define unsigned_ptrdiff_type_node c_global_trees[CTI_UNSIGNED_PTRDIFF_TYPE] +#define intmax_type_node c_global_trees[CTI_INTMAX_TYPE] +#define uintmax_type_node c_global_trees[CTI_UINTMAX_TYPE] +#define widest_integer_literal_type_node c_global_trees[CTI_WIDEST_INT_LIT_TYPE] +#define widest_unsigned_literal_type_node c_global_trees[CTI_WIDEST_UINT_LIT_TYPE] + +#define sig_atomic_type_node c_global_trees[CTI_SIG_ATOMIC_TYPE] +#define int8_type_node c_global_trees[CTI_INT8_TYPE] +#define int16_type_node c_global_trees[CTI_INT16_TYPE] +#define int32_type_node c_global_trees[CTI_INT32_TYPE] +#define int64_type_node c_global_trees[CTI_INT64_TYPE] +#define uint8_type_node c_global_trees[CTI_UINT8_TYPE] +#define uint16_type_node c_global_trees[CTI_UINT16_TYPE] +#define c_uint32_type_node c_global_trees[CTI_UINT32_TYPE] +#define c_uint64_type_node c_global_trees[CTI_UINT64_TYPE] +#define int_least8_type_node c_global_trees[CTI_INT_LEAST8_TYPE] +#define int_least16_type_node c_global_trees[CTI_INT_LEAST16_TYPE] +#define int_least32_type_node c_global_trees[CTI_INT_LEAST32_TYPE] +#define int_least64_type_node c_global_trees[CTI_INT_LEAST64_TYPE] +#define uint_least8_type_node c_global_trees[CTI_UINT_LEAST8_TYPE] +#define uint_least16_type_node c_global_trees[CTI_UINT_LEAST16_TYPE] +#define uint_least32_type_node c_global_trees[CTI_UINT_LEAST32_TYPE] +#define uint_least64_type_node c_global_trees[CTI_UINT_LEAST64_TYPE] +#define int_fast8_type_node c_global_trees[CTI_INT_FAST8_TYPE] +#define int_fast16_type_node c_global_trees[CTI_INT_FAST16_TYPE] +#define int_fast32_type_node c_global_trees[CTI_INT_FAST32_TYPE] +#define int_fast64_type_node c_global_trees[CTI_INT_FAST64_TYPE] +#define uint_fast8_type_node c_global_trees[CTI_UINT_FAST8_TYPE] +#define uint_fast16_type_node c_global_trees[CTI_UINT_FAST16_TYPE] +#define uint_fast32_type_node c_global_trees[CTI_UINT_FAST32_TYPE] +#define uint_fast64_type_node c_global_trees[CTI_UINT_FAST64_TYPE] +#define intptr_type_node c_global_trees[CTI_INTPTR_TYPE] +#define uintptr_type_node c_global_trees[CTI_UINTPTR_TYPE] + +#define truthvalue_type_node c_global_trees[CTI_TRUTHVALUE_TYPE] +#define truthvalue_true_node c_global_trees[CTI_TRUTHVALUE_TRUE] +#define truthvalue_false_node c_global_trees[CTI_TRUTHVALUE_FALSE] + +#define char_array_type_node c_global_trees[CTI_CHAR_ARRAY_TYPE] +#define char16_array_type_node c_global_trees[CTI_CHAR16_ARRAY_TYPE] +#define char32_array_type_node c_global_trees[CTI_CHAR32_ARRAY_TYPE] +#define wchar_array_type_node c_global_trees[CTI_WCHAR_ARRAY_TYPE] +#define int_array_type_node c_global_trees[CTI_INT_ARRAY_TYPE] +#define string_type_node c_global_trees[CTI_STRING_TYPE] +#define const_string_type_node c_global_trees[CTI_CONST_STRING_TYPE] + +#define default_function_type c_global_trees[CTI_DEFAULT_FUNCTION_TYPE] + +#define function_name_decl_node c_global_trees[CTI_FUNCTION_NAME_DECL] +#define pretty_function_name_decl_node c_global_trees[CTI_PRETTY_FUNCTION_NAME_DECL] +#define c99_function_name_decl_node c_global_trees[CTI_C99_FUNCTION_NAME_DECL] +#define saved_function_name_decls c_global_trees[CTI_SAVED_FUNCTION_NAME_DECLS] + +/* A node for `((void) 0)'. */ +#define void_zero_node c_global_trees[CTI_VOID_ZERO] + +/* The node for C++ `__null'. */ +#define null_node c_global_trees[CTI_NULL] + +extern GTY(()) tree c_global_trees[CTI_MAX]; + +/* In a RECORD_TYPE, a sorted array of the fields of the type, not a + tree for size reasons. */ +struct GTY(()) sorted_fields_type { + int len; + tree GTY((length ("%h.len"))) elts[1]; +}; + +/* Mark which labels are explicitly declared. + These may be shadowed, and may be referenced from nested functions. */ +#define C_DECLARED_LABEL_FLAG(label) TREE_LANG_FLAG_1 (label) + +typedef enum c_language_kind +{ + clk_c = 0, /* C90, C94 or C99 */ + clk_objc = 1, /* clk_c with ObjC features. */ + clk_cxx = 2, /* ANSI/ISO C++ */ + clk_objcxx = 3 /* clk_cxx with ObjC features. */ +} +c_language_kind; + +/* To test for a specific language use c_language, defined by each + front end. For "ObjC features" or "not C++" use the macros. */ +extern c_language_kind c_language; + +#define c_dialect_cxx() ((c_language & clk_cxx) != 0) +#define c_dialect_objc() ((c_language & clk_objc) != 0) + +/* The various name of operator that appears in error messages. */ +typedef enum ref_operator { + /* NULL */ + RO_NULL, + /* array indexing */ + RO_ARRAY_INDEXING, + /* unary * */ + RO_UNARY_STAR, + /* -> */ + RO_ARROW, + /* implicit conversion */ + RO_IMPLICIT_CONVERSION +} ref_operator; + +/* Information about a statement tree. */ + +struct GTY(()) stmt_tree_s { + /* The current statement list being collected. */ + tree x_cur_stmt_list; + + /* In C++, Nonzero if we should treat statements as full + expressions. In particular, this variable is no-zero if at the + end of a statement we should destroy any temporaries created + during that statement. Similarly, if, at the end of a block, we + should destroy any local variables in this block. Normally, this + variable is nonzero, since those are the normal semantics of + C++. + + However, in order to represent aggregate initialization code as + tree structure, we use statement-expressions. The statements + within the statement expression should not result in cleanups + being run until the entire enclosing statement is complete. + + This flag has no effect in C. */ + int stmts_are_full_exprs_p; +}; + +typedef struct stmt_tree_s *stmt_tree; + +/* Global state pertinent to the current function. Some C dialects + extend this structure with additional fields. */ + +struct GTY(()) c_language_function { + /* While we are parsing the function, this contains information + about the statement-tree that we are building. */ + struct stmt_tree_s x_stmt_tree; +}; + +/* When building a statement-tree, this is the current statement list + being collected. It's TREE_CHAIN is a back-pointer to the previous + statement list. */ + +#define cur_stmt_list (current_stmt_tree ()->x_cur_stmt_list) + +/* Language-specific hooks. */ + +/* If non-NULL, this function is called after a precompile header file + is loaded. */ +extern void (*lang_post_pch_load) (void); + +extern void push_file_scope (void); +extern void pop_file_scope (void); +extern stmt_tree current_stmt_tree (void); +extern tree push_stmt_list (void); +extern tree pop_stmt_list (tree); +extern tree add_stmt (tree); +extern void push_cleanup (tree, tree, bool); +extern tree pushdecl_top_level (tree); +extern tree pushdecl (tree); +extern tree build_modify_expr (location_t, tree, tree, enum tree_code, + location_t, tree, tree); +extern tree build_indirect_ref (location_t, tree, ref_operator); + +extern int c_expand_decl (tree); + +extern int field_decl_cmp (const void *, const void *); +extern void resort_sorted_fields (void *, void *, gt_pointer_operator, + void *); +extern bool has_c_linkage (const_tree decl); + +/* Switches common to the C front ends. */ + +/* Nonzero if prepreprocessing only. */ + +extern int flag_preprocess_only; + +/* Zero means that faster, ...NonNil variants of objc_msgSend... + calls will be used in ObjC; passing nil receivers to such calls + will most likely result in crashes. */ +extern int flag_nil_receivers; + +/* Nonzero means that we will allow new ObjC exception syntax (@throw, + @try, etc.) in source code. */ +extern int flag_objc_exceptions; + +/* Nonzero means that we generate NeXT setjmp based exceptions. */ +extern int flag_objc_sjlj_exceptions; + +/* Nonzero means that code generation will be altered to support + "zero-link" execution. This currently affects ObjC only, but may + affect other languages in the future. */ +extern int flag_zero_link; + +/* Nonzero means emit an '__OBJC, __image_info' for the current translation + unit. It will inform the ObjC runtime that class definition(s) herein + contained are to replace one(s) previously loaded. */ +extern int flag_replace_objc_classes; + +/* Nonzero means don't output line number information. */ + +extern char flag_no_line_commands; + +/* Nonzero causes -E output not to be done, but directives such as + #define that have side effects are still obeyed. */ + +extern char flag_no_output; + +/* Nonzero means dump macros in some fashion; contains the 'D', 'M', + 'N' or 'U' of the command line switch. */ + +extern char flag_dump_macros; + +/* Nonzero means pass #include lines through to the output. */ + +extern char flag_dump_includes; + +/* Nonzero means process PCH files while preprocessing. */ + +extern bool flag_pch_preprocess; + +/* The file name to which we should write a precompiled header, or + NULL if no header will be written in this compile. */ + +extern const char *pch_file; + +/* Nonzero if an ISO standard was selected. It rejects macros in the + user's namespace. */ + +extern int flag_iso; + +/* Nonzero if -undef was given. It suppresses target built-in macros + and assertions. */ + +extern int flag_undef; + +/* Nonzero means don't recognize the non-ANSI builtin functions. */ + +extern int flag_no_builtin; + +/* Nonzero means don't recognize the non-ANSI builtin functions. + -ansi sets this. */ + +extern int flag_no_nonansi_builtin; + +/* Nonzero means give `double' the same size as `float'. */ + +extern int flag_short_double; + +/* Nonzero means give `wchar_t' the same size as `short'. */ + +extern int flag_short_wchar; + +/* Nonzero means allow implicit conversions between vectors with + differing numbers of subparts and/or differing element types. */ +extern int flag_lax_vector_conversions; + +/* Nonzero means allow Microsoft extensions without warnings or errors. */ +extern int flag_ms_extensions; + +/* Nonzero means don't recognize the keyword `asm'. */ + +extern int flag_no_asm; + +/* Nonzero means give string constants the type `const char *', as mandated + by the standard. */ + +extern int flag_const_strings; + +/* Nonzero means to treat bitfields as signed unless they say `unsigned'. */ + +extern int flag_signed_bitfields; + +/* Warn about #pragma directives that are not recognized. */ + +extern int warn_unknown_pragmas; /* Tri state variable. */ + +/* Warn about format/argument anomalies in calls to formatted I/O functions + (*printf, *scanf, strftime, strfmon, etc.). */ + +extern int warn_format; + + +/* C/ObjC language option variables. */ + + +/* Nonzero means allow type mismatches in conditional expressions; + just make their values `void'. */ + +extern int flag_cond_mismatch; + +/* Nonzero means enable C89 Amendment 1 features. */ + +extern int flag_isoc94; + +/* Nonzero means use the ISO C99 (or C1X) dialect of C. */ + +extern int flag_isoc99; + +/* Nonzero means use the ISO C1X dialect of C. */ + +extern int flag_isoc1x; + +/* Nonzero means that we have builtin functions, and main is an int. */ + +extern int flag_hosted; + +/* ObjC language option variables. */ + + +/* Open and close the file for outputting class declarations, if + requested (ObjC). */ + +extern int flag_gen_declaration; + +/* Tells the compiler that this is a special run. Do not perform any + compiling, instead we are to test some platform dependent features + and output a C header file with appropriate definitions. */ + +extern int print_struct_values; + +/* ???. Undocumented. */ + +extern const char *constant_string_class_name; + + +/* C++ language option variables. */ + + +/* Nonzero means don't recognize any extension keywords. */ + +extern int flag_no_gnu_keywords; + +/* Nonzero means do emit exported implementations of functions even if + they can be inlined. */ + +extern int flag_implement_inlines; + +/* Nonzero means that implicit instantiations will be emitted if needed. */ + +extern int flag_implicit_templates; + +/* Nonzero means that implicit instantiations of inline templates will be + emitted if needed, even if instantiations of non-inline templates + aren't. */ + +extern int flag_implicit_inline_templates; + +/* Nonzero means generate separate instantiation control files and + juggle them at link time. */ + +extern int flag_use_repository; + +/* Nonzero if we want to issue diagnostics that the standard says are not + required. */ + +extern int flag_optional_diags; + +/* Nonzero means we should attempt to elide constructors when possible. */ + +extern int flag_elide_constructors; + +/* Nonzero means that member functions defined in class scope are + inline by default. */ + +extern int flag_default_inline; + +/* Controls whether compiler generates 'type descriptor' that give + run-time type information. */ + +extern int flag_rtti; + +/* Nonzero if we want to conserve space in the .o files. We do this + by putting uninitialized data and runtime initialized data into + .common instead of .data at the expense of not flagging multiple + definitions. */ + +extern int flag_conserve_space; + +/* Nonzero if we want to obey access control semantics. */ + +extern int flag_access_control; + +/* Nonzero if we want to check the return value of new and avoid calling + constructors if it is a null pointer. */ + +extern int flag_check_new; + +/* The supported C++ dialects. */ + +enum cxx_dialect { + /* C++98 */ + cxx98, + /* Experimental features that are likely to become part of + C++0x. */ + cxx0x +}; + +/* The C++ dialect being used. C++98 is the default. */ +extern enum cxx_dialect cxx_dialect; + +/* Nonzero if we want the new ISO rules for pushing a new scope for `for' + initialization variables. + 0: Old rules, set by -fno-for-scope. + 2: New ISO rules, set by -ffor-scope. + 1: Try to implement new ISO rules, but with backup compatibility + (and warnings). This is the default, for now. */ + +extern int flag_new_for_scope; + +/* Nonzero if we want to emit defined symbols with common-like linkage as + weak symbols where possible, in order to conform to C++ semantics. + Otherwise, emit them as local symbols. */ + +extern int flag_weak; + +/* 0 means we want the preprocessor to not emit line directives for + the current working directory. 1 means we want it to do it. -1 + means we should decide depending on whether debugging information + is being emitted or not. */ + +extern int flag_working_directory; + +/* Nonzero to use __cxa_atexit, rather than atexit, to register + destructors for local statics and global objects. */ + +extern int flag_use_cxa_atexit; + +/* Nonzero to use __cxa_get_exception_ptr in the C++ exception-handling + logic. */ + +extern int flag_use_cxa_get_exception_ptr; + +/* Nonzero means to implement standard semantics for exception + specifications, calling unexpected if an exception is thrown that + doesn't match the specification. Zero means to treat them as + assertions and optimize accordingly, but not check them. */ + +extern int flag_enforce_eh_specs; + +/* Nonzero (the default) means to generate thread-safe code for + initializing local statics. */ + +extern int flag_threadsafe_statics; + +/* Nonzero if we want to pretty-print template specializations as the + template signature followed by the arguments. */ + +extern int flag_pretty_templates; + +/* Warn about using __null (as NULL in C++) as sentinel. For code compiled + with GCC this doesn't matter as __null is guaranteed to have the right + size. */ + +extern int warn_strict_null_sentinel; + +/* Maximum template instantiation depth. This limit is rather + arbitrary, but it exists to limit the time it takes to notice + infinite template instantiations. */ + +extern int max_tinst_depth; + +/* Nonzero means that we should not issue warnings about problems that + occur when the code is executed, because the code being processed + is not expected to be executed. This is set during parsing. This + is used for cases like sizeof() and "0 ? a : b". This is a count, + not a bool, because unexecuted expressions can nest. */ + +extern int c_inhibit_evaluation_warnings; + +/* Whether lexing has been completed, so subsequent preprocessor + errors should use the compiler's input_location. */ + +extern bool done_lexing; + +/* C types are partitioned into three subsets: object, function, and + incomplete types. */ +#define C_TYPE_OBJECT_P(type) \ + (TREE_CODE (type) != FUNCTION_TYPE && TYPE_SIZE (type)) + +#define C_TYPE_INCOMPLETE_P(type) \ + (TREE_CODE (type) != FUNCTION_TYPE && TYPE_SIZE (type) == 0) + +#define C_TYPE_FUNCTION_P(type) \ + (TREE_CODE (type) == FUNCTION_TYPE) + +/* For convenience we define a single macro to identify the class of + object or incomplete types. */ +#define C_TYPE_OBJECT_OR_INCOMPLETE_P(type) \ + (!C_TYPE_FUNCTION_P (type)) + +/* Attribute table common to the C front ends. */ +extern const struct attribute_spec c_common_attribute_table[]; +extern const struct attribute_spec c_common_format_attribute_table[]; + +/* Pointer to function to lazily generate the VAR_DECL for __FUNCTION__ etc. + ID is the identifier to use, NAME is the string. + TYPE_DEP indicates whether it depends on type of the function or not + (i.e. __PRETTY_FUNCTION__). */ + +extern tree (*make_fname_decl) (location_t, tree, int); + +/* In c-decl.c and cp/tree.c. FIXME. */ +extern void c_register_addr_space (const char *str, addr_space_t as); + +/* In c-common.c. */ +extern const char *c_addr_space_name (addr_space_t as); +extern tree identifier_global_value (tree); +extern void record_builtin_type (enum rid, const char *, tree); +extern tree build_void_list_node (void); +extern void start_fname_decls (void); +extern void finish_fname_decls (void); +extern const char *fname_as_string (int); +extern tree fname_decl (location_t, unsigned, tree); + +extern void check_function_arguments (tree, int, tree *, tree); +extern void check_function_arguments_recurse (void (*) + (void *, tree, + unsigned HOST_WIDE_INT), + void *, tree, + unsigned HOST_WIDE_INT); +extern bool check_builtin_function_arguments (tree, int, tree *); +extern void check_function_format (tree, int, tree *); +extern void set_Wformat (int); +extern tree handle_format_attribute (tree *, tree, tree, int, bool *); +extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); +extern bool attribute_takes_identifier_p (const_tree); +extern int c_common_handle_option (size_t code, const char *arg, int value, int kind); +extern bool c_common_missing_argument (const char *opt, size_t code); +extern tree c_common_type_for_mode (enum machine_mode, int); +extern tree c_common_type_for_size (unsigned int, int); +extern tree c_common_fixed_point_type_for_size (unsigned int, unsigned int, + int, int); +extern tree c_common_unsigned_type (tree); +extern tree c_common_signed_type (tree); +extern tree c_common_signed_or_unsigned_type (int, tree); +extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int); +extern bool decl_with_nonnull_addr_p (const_tree); +extern tree c_fully_fold (tree, bool, bool *); +extern tree decl_constant_value_for_optimization (tree); +extern tree c_wrap_maybe_const (tree, bool); +extern tree c_save_expr (tree); +extern tree c_common_truthvalue_conversion (location_t, tree); +extern void c_apply_type_quals_to_decl (int, tree); +extern tree c_sizeof_or_alignof_type (location_t, tree, bool, int); +extern tree c_alignof_expr (location_t, tree); +/* Print an error message for invalid operands to arith operation CODE. + NOP_EXPR is used as a special case (see truthvalue_conversion). */ +extern void binary_op_error (location_t, enum tree_code, tree, tree); +extern tree fix_string_type (tree); +extern void constant_expression_warning (tree); +extern void constant_expression_error (tree); +extern bool strict_aliasing_warning (tree, tree, tree); +extern void warnings_for_convert_and_check (tree, tree, tree); +extern tree convert_and_check (tree, tree); +extern void overflow_warning (location_t, tree); +extern void warn_logical_operator (location_t, enum tree_code, tree, + enum tree_code, tree, enum tree_code, tree); +extern void check_main_parameter_types (tree decl); +extern bool c_determine_visibility (tree); +extern bool same_scalar_type_ignoring_signedness (tree, tree); +extern void mark_valid_location_for_stdc_pragma (bool); +extern bool valid_location_for_stdc_pragma_p (void); +extern void set_float_const_decimal64 (void); +extern void clear_float_const_decimal64 (void); +extern bool float_const_decimal64_p (void); + +#define c_sizeof(LOC, T) c_sizeof_or_alignof_type (LOC, T, true, 1) +#define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, 1) + +/* Subroutine of build_binary_op, used for certain operations. */ +extern tree shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise); + +/* Subroutine of build_binary_op, used for comparison operations. + See if the operands have both been converted from subword integer types + and, if so, perhaps change them both back to their original type. */ +extern tree shorten_compare (tree *, tree *, tree *, enum tree_code *); + +extern tree pointer_int_sum (location_t, enum tree_code, tree, tree); + +/* Add qualifiers to a type, in the fashion for C. */ +extern tree c_build_qualified_type (tree, int); + +/* Build tree nodes and builtin functions common to both C and C++ language + frontends. */ +extern void c_common_nodes_and_builtins (void); + +extern void disable_builtin_function (const char *); + +extern void set_compound_literal_name (tree decl); + +extern tree build_va_arg (location_t, tree, tree); + +extern unsigned int c_common_init_options (unsigned int, const char **); +extern bool c_common_post_options (const char **); +extern bool c_common_init (void); +extern void c_common_finish (void); +extern void c_common_parse_file (int); +extern alias_set_type c_common_get_alias_set (tree); +extern void c_register_builtin_type (tree, const char*); +extern bool c_promoting_integer_type_p (const_tree); +extern int self_promoting_args_p (const_tree); +extern tree strip_pointer_operator (tree); +extern tree strip_pointer_or_array_types (tree); +extern HOST_WIDE_INT c_common_to_target_charset (HOST_WIDE_INT); + +/* This is the basic parsing function. */ +extern void c_parse_file (void); +/* This is misnamed, it actually performs end-of-compilation processing. */ +extern void finish_file (void); + + +/* These macros provide convenient access to the various _STMT nodes. */ + +/* Nonzero if a given STATEMENT_LIST represents the outermost binding + if a statement expression. */ +#define STATEMENT_LIST_STMT_EXPR(NODE) \ + TREE_LANG_FLAG_1 (STATEMENT_LIST_CHECK (NODE)) + +/* Nonzero if a label has been added to the statement list. */ +#define STATEMENT_LIST_HAS_LABEL(NODE) \ + TREE_LANG_FLAG_3 (STATEMENT_LIST_CHECK (NODE)) + +/* C_MAYBE_CONST_EXPR accessors. */ +#define C_MAYBE_CONST_EXPR_PRE(NODE) \ + TREE_OPERAND (C_MAYBE_CONST_EXPR_CHECK (NODE), 0) +#define C_MAYBE_CONST_EXPR_EXPR(NODE) \ + TREE_OPERAND (C_MAYBE_CONST_EXPR_CHECK (NODE), 1) +#define C_MAYBE_CONST_EXPR_INT_OPERANDS(NODE) \ + TREE_LANG_FLAG_0 (C_MAYBE_CONST_EXPR_CHECK (NODE)) +#define C_MAYBE_CONST_EXPR_NON_CONST(NODE) \ + TREE_LANG_FLAG_1 (C_MAYBE_CONST_EXPR_CHECK (NODE)) +#define EXPR_INT_CONST_OPERANDS(EXPR) \ + (INTEGRAL_TYPE_P (TREE_TYPE (EXPR)) \ + && (TREE_CODE (EXPR) == INTEGER_CST \ + || (TREE_CODE (EXPR) == C_MAYBE_CONST_EXPR \ + && C_MAYBE_CONST_EXPR_INT_OPERANDS (EXPR)))) + +/* In a FIELD_DECL, nonzero if the decl was originally a bitfield. */ +#define DECL_C_BIT_FIELD(NODE) \ + (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1) +#define SET_DECL_C_BIT_FIELD(NODE) \ + (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1) +#define CLEAR_DECL_C_BIT_FIELD(NODE) \ + (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 0) + +extern tree do_case (location_t, tree, tree); +extern tree build_stmt (location_t, enum tree_code, ...); +extern tree build_case_label (location_t, tree, tree, tree); + +/* These functions must be defined by each front-end which implements + a variant of the C language. They are used in c-common.c. */ + +extern tree build_unary_op (location_t, enum tree_code, tree, int); +extern tree build_binary_op (location_t, enum tree_code, tree, tree, int); +extern tree perform_integral_promotions (tree); + +/* These functions must be defined by each front-end which implements + a variant of the C language. They are used by port files. */ + +extern tree default_conversion (tree); + +/* Given two integer or real types, return the type for their sum. + Given two compatible ANSI C types, returns the merged type. */ + +extern tree common_type (tree, tree); + +extern tree decl_constant_value (tree); + +/* Handle increment and decrement of boolean types. */ +extern tree boolean_increment (enum tree_code, tree); + +extern int case_compare (splay_tree_key, splay_tree_key); + +extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree, tree); + +extern void c_do_switch_warnings (splay_tree, location_t, tree, tree); + +extern tree build_function_call (location_t, tree, tree); + +extern tree build_function_call_vec (location_t, tree, + VEC(tree,gc) *, VEC(tree,gc) *); + +extern tree resolve_overloaded_builtin (location_t, tree, VEC(tree,gc) *); + +extern tree finish_label_address_expr (tree, location_t); + +/* Same function prototype, but the C and C++ front ends have + different implementations. Used in c-common.c. */ +extern tree lookup_label (tree); +extern tree lookup_name (tree); +extern bool lvalue_p (const_tree); + +extern bool vector_targets_convertible_p (const_tree t1, const_tree t2); +extern bool vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note); + +extern rtx c_expand_expr (tree, rtx, enum machine_mode, int, rtx *); + +extern void init_c_lex (void); + +extern void c_cpp_builtins (cpp_reader *); +extern void c_cpp_builtins_optimize_pragma (cpp_reader *, tree, tree); +extern bool c_cpp_error (cpp_reader *, int, int, location_t, unsigned int, + const char *, va_list *) + ATTRIBUTE_GCC_DIAG(6,0); + +/* Positive if an implicit `extern "C"' scope has just been entered; + negative if such a scope has just been exited. */ +extern GTY(()) int pending_lang_change; + +/* Information recorded about each file examined during compilation. */ + +struct c_fileinfo +{ + int time; /* Time spent in the file. */ + + /* Flags used only by C++. + INTERFACE_ONLY nonzero means that we are in an "interface" section + of the compiler. INTERFACE_UNKNOWN nonzero means we cannot trust + the value of INTERFACE_ONLY. If INTERFACE_UNKNOWN is zero and + INTERFACE_ONLY is zero, it means that we are responsible for + exporting definitions that others might need. */ + short interface_only; + short interface_unknown; +}; + +struct c_fileinfo *get_fileinfo (const char *); +extern void dump_time_statistics (void); + +extern bool c_dump_tree (void *, tree); + +extern void verify_sequence_points (tree); + +extern tree fold_offsetof (tree, tree); + +/* Places where an lvalue, or modifiable lvalue, may be required. + Used to select diagnostic messages in lvalue_error and + readonly_error. */ +enum lvalue_use { + lv_assign, + lv_increment, + lv_decrement, + lv_addressof, + lv_asm +}; + +extern void lvalue_error (enum lvalue_use); + +extern int complete_array_type (tree *, tree, bool); + +extern tree builtin_type_for_size (int, bool); + +extern void warn_array_subscript_with_type_char (tree); +extern void warn_about_parentheses (enum tree_code, + enum tree_code, tree, + enum tree_code, tree); +extern void warn_for_unused_label (tree label); +extern void warn_for_div_by_zero (location_t, tree divisor); +extern void warn_for_sign_compare (location_t, + tree orig_op0, tree orig_op1, + tree op0, tree op1, + tree result_type, + enum tree_code resultcode); +extern void set_underlying_type (tree x); +extern bool is_typedef_decl (tree x); +extern VEC(tree,gc) *make_tree_vector (void); +extern void release_tree_vector (VEC(tree,gc) *); +extern VEC(tree,gc) *make_tree_vector_single (tree); +extern VEC(tree,gc) *make_tree_vector_copy (const VEC(tree,gc) *); + +/* In c-gimplify.c */ +extern void c_genericize (tree); +extern int c_gimplify_expr (tree *, gimple_seq *, gimple_seq *); +extern tree c_build_bind_expr (location_t, tree, tree); + +/* In c-pch.c */ +extern void pch_init (void); +extern int c_common_valid_pch (cpp_reader *pfile, const char *name, int fd); +extern void c_common_read_pch (cpp_reader *pfile, const char *name, int fd, + const char *orig); +extern void c_common_write_pch (void); +extern void c_common_no_more_pch (void); +extern void c_common_pch_pragma (cpp_reader *pfile, const char *); +extern void c_common_print_pch_checksum (FILE *f); + +/* In *-checksum.c */ +extern const unsigned char executable_checksum[16]; + +/* In c-cppbuiltin.c */ +extern void builtin_define_std (const char *macro); +extern void builtin_define_with_value (const char *, const char *, int); +extern void c_stddef_cpp_builtins (void); +extern void fe_file_change (const struct line_map *); +extern void c_parse_error (const char *, enum cpp_ttype, tree, unsigned char); + +/* Objective-C / Objective-C++ entry points. */ + +/* The following ObjC/ObjC++ functions are called by the C and/or C++ + front-ends; they all must have corresponding stubs in stub-objc.c. */ +extern tree objc_is_class_name (tree); +extern tree objc_is_object_ptr (tree); +extern void objc_check_decl (tree); +extern int objc_is_reserved_word (tree); +extern bool objc_compare_types (tree, tree, int, tree); +extern void objc_volatilize_decl (tree); +extern bool objc_type_quals_match (tree, tree); +extern tree objc_rewrite_function_call (tree, tree); +extern tree objc_message_selector (void); +extern tree objc_lookup_ivar (tree, tree); +extern void objc_clear_super_receiver (void); +extern int objc_is_public (tree, tree); +extern tree objc_is_id (tree); +extern void objc_declare_alias (tree, tree); +extern void objc_declare_class (tree); +extern void objc_declare_protocols (tree); +extern tree objc_build_message_expr (tree); +extern tree objc_finish_message_expr (tree, tree, tree); +extern tree objc_build_selector_expr (location_t, tree); +extern tree objc_build_protocol_expr (tree); +extern tree objc_build_encode_expr (tree); +extern tree objc_build_string_object (tree); +extern tree objc_get_protocol_qualified_type (tree, tree); +extern tree objc_get_class_reference (tree); +extern tree objc_get_class_ivars (tree); +extern void objc_start_class_interface (tree, tree, tree); +extern void objc_start_category_interface (tree, tree, tree); +extern void objc_start_protocol (tree, tree); +extern void objc_continue_interface (void); +extern void objc_finish_interface (void); +extern void objc_start_class_implementation (tree, tree); +extern void objc_start_category_implementation (tree, tree); +extern void objc_continue_implementation (void); +extern void objc_finish_implementation (void); +extern void objc_set_visibility (int); +extern void objc_set_method_type (enum tree_code); +extern tree objc_build_method_signature (tree, tree, tree, bool); +extern void objc_add_method_declaration (tree); +extern void objc_start_method_definition (tree); +extern void objc_finish_method_definition (tree); +extern void objc_add_instance_variable (tree); +extern tree objc_build_keyword_decl (tree, tree, tree); +extern tree objc_build_throw_stmt (location_t, tree); +extern void objc_begin_try_stmt (location_t, tree); +extern tree objc_finish_try_stmt (void); +extern void objc_begin_catch_clause (tree); +extern void objc_finish_catch_clause (void); +extern void objc_build_finally_clause (location_t, tree); +extern tree objc_build_synchronized (location_t, tree, tree); +extern int objc_static_init_needed_p (void); +extern tree objc_generate_static_init_call (tree); +extern tree objc_generate_write_barrier (tree, enum tree_code, tree); + +/* The following are provided by the C and C++ front-ends, and called by + ObjC/ObjC++. */ +extern void *objc_get_current_scope (void); +extern void objc_mark_locals_volatile (void *); + +/* In c-ppoutput.c */ +extern void init_pp_output (FILE *); +extern void preprocess_file (cpp_reader *); +extern void pp_file_change (const struct line_map *); +extern void pp_dir_change (cpp_reader *, const char *); +extern bool check_missing_format_attribute (tree, tree); + +/* In c-omp.c */ +extern tree c_finish_omp_master (location_t, tree); +extern tree c_finish_omp_critical (location_t, tree, tree); +extern tree c_finish_omp_ordered (location_t, tree); +extern void c_finish_omp_barrier (location_t); +extern tree c_finish_omp_atomic (location_t, enum tree_code, tree, tree); +extern void c_finish_omp_flush (location_t); +extern void c_finish_omp_taskwait (location_t); +extern tree c_finish_omp_for (location_t, tree, tree, tree, tree, tree, tree); +extern void c_split_parallel_clauses (location_t, tree, tree *, tree *); +extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); + +/* Not in c-omp.c; provided by the front end. */ +extern bool c_omp_sharing_predetermined (tree); +extern tree c_omp_remap_decl (tree, bool); +extern void record_types_used_by_current_var_decl (tree); + +#endif /* ! GCC_C_COMMON_H */ diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c new file mode 100644 index 0000000..6bbdb46 --- /dev/null +++ b/gcc/c-family/c-cppbuiltin.c @@ -0,0 +1,1107 @@ +/* Define builtin-in macros for the C family front ends. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 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 "tree.h" +#include "version.h" +#include "flags.h" +#include "c-common.h" +#include "c-pragma.h" +#include "output.h" +#include "except.h" /* For USING_SJLJ_EXCEPTIONS. */ +#include "debug.h" /* For dwarf2out_do_cfi_asm. */ +#include "toplev.h" +#include "tm_p.h" /* For TARGET_CPU_CPP_BUILTINS & friends. */ +#include "target.h" + +#ifndef TARGET_OS_CPP_BUILTINS +# define TARGET_OS_CPP_BUILTINS() +#endif + +#ifndef TARGET_OBJFMT_CPP_BUILTINS +# define TARGET_OBJFMT_CPP_BUILTINS() +#endif + +#ifndef REGISTER_PREFIX +#define REGISTER_PREFIX "" +#endif + +/* Non-static as some targets don't use it. */ +void builtin_define_std (const char *) ATTRIBUTE_UNUSED; +static void builtin_define_with_int_value (const char *, HOST_WIDE_INT); +static void builtin_define_with_hex_fp_value (const char *, tree, + int, const char *, + const char *, + const char *); +static void builtin_define_stdint_macros (void); +static void builtin_define_constants (const char *, tree); +static void builtin_define_type_max (const char *, tree); +static void builtin_define_type_minmax (const char *, const char *, tree); +static void builtin_define_type_precision (const char *, tree); +static void builtin_define_type_sizeof (const char *, tree); +static void builtin_define_float_constants (const char *, + const char *, + const char *, + tree); +static void define__GNUC__ (void); + +/* Define NAME with value TYPE precision. */ +static void +builtin_define_type_precision (const char *name, tree type) +{ + builtin_define_with_int_value (name, TYPE_PRECISION (type)); +} + +/* Define NAME with value TYPE size_unit. */ +static void +builtin_define_type_sizeof (const char *name, tree type) +{ + builtin_define_with_int_value (name, + tree_low_cst (TYPE_SIZE_UNIT (type), 1)); +} + +/* Define the float.h constants for TYPE using NAME_PREFIX, FP_SUFFIX, + and FP_CAST. */ +static void +builtin_define_float_constants (const char *name_prefix, + const char *fp_suffix, + const char *fp_cast, + tree type) +{ + /* Used to convert radix-based values to base 10 values in several cases. + + In the max_exp -> max_10_exp conversion for 128-bit IEEE, we need at + least 6 significant digits for correct results. Using the fraction + formed by (log(2)*1e6)/(log(10)*1e6) overflows a 32-bit integer as an + intermediate; perhaps someone can find a better approximation, in the + mean time, I suspect using doubles won't harm the bootstrap here. */ + + const double log10_2 = .30102999566398119521; + double log10_b; + const struct real_format *fmt; + const struct real_format *ldfmt; + + char name[64], buf[128]; + int dig, min_10_exp, max_10_exp; + int decimal_dig; + int type_decimal_dig; + + fmt = REAL_MODE_FORMAT (TYPE_MODE (type)); + gcc_assert (fmt->b != 10); + ldfmt = REAL_MODE_FORMAT (TYPE_MODE (long_double_type_node)); + gcc_assert (ldfmt->b != 10); + + /* The radix of the exponent representation. */ + if (type == float_type_node) + builtin_define_with_int_value ("__FLT_RADIX__", fmt->b); + log10_b = log10_2; + + /* The number of radix digits, p, in the floating-point significand. */ + sprintf (name, "__%s_MANT_DIG__", name_prefix); + builtin_define_with_int_value (name, fmt->p); + + /* The number of decimal digits, q, such that any floating-point number + with q decimal digits can be rounded into a floating-point number with + p radix b digits and back again without change to the q decimal digits, + + p log10 b if b is a power of 10 + floor((p - 1) log10 b) otherwise + */ + dig = (fmt->p - 1) * log10_b; + sprintf (name, "__%s_DIG__", name_prefix); + builtin_define_with_int_value (name, dig); + + /* The minimum negative int x such that b**(x-1) is a normalized float. */ + sprintf (name, "__%s_MIN_EXP__", name_prefix); + sprintf (buf, "(%d)", fmt->emin); + builtin_define_with_value (name, buf, 0); + + /* The minimum negative int x such that 10**x is a normalized float, + + ceil (log10 (b ** (emin - 1))) + = ceil (log10 (b) * (emin - 1)) + + Recall that emin is negative, so the integer truncation calculates + the ceiling, not the floor, in this case. */ + min_10_exp = (fmt->emin - 1) * log10_b; + sprintf (name, "__%s_MIN_10_EXP__", name_prefix); + sprintf (buf, "(%d)", min_10_exp); + builtin_define_with_value (name, buf, 0); + + /* The maximum int x such that b**(x-1) is a representable float. */ + sprintf (name, "__%s_MAX_EXP__", name_prefix); + builtin_define_with_int_value (name, fmt->emax); + + /* The maximum int x such that 10**x is in the range of representable + finite floating-point numbers, + + floor (log10((1 - b**-p) * b**emax)) + = floor (log10(1 - b**-p) + log10(b**emax)) + = floor (log10(1 - b**-p) + log10(b)*emax) + + The safest thing to do here is to just compute this number. But since + we don't link cc1 with libm, we cannot. We could implement log10 here + a series expansion, but that seems too much effort because: + + Note that the first term, for all extant p, is a number exceedingly close + to zero, but slightly negative. Note that the second term is an integer + scaling an irrational number, and that because of the floor we are only + interested in its integral portion. + + In order for the first term to have any effect on the integral portion + of the second term, the second term has to be exceedingly close to an + integer itself (e.g. 123.000000000001 or something). Getting a result + that close to an integer requires that the irrational multiplicand have + a long series of zeros in its expansion, which doesn't occur in the + first 20 digits or so of log10(b). + + Hand-waving aside, crunching all of the sets of constants above by hand + does not yield a case for which the first term is significant, which + in the end is all that matters. */ + max_10_exp = fmt->emax * log10_b; + sprintf (name, "__%s_MAX_10_EXP__", name_prefix); + builtin_define_with_int_value (name, max_10_exp); + + /* The number of decimal digits, n, such that any floating-point number + can be rounded to n decimal digits and back again without change to + the value. + + p * log10(b) if b is a power of 10 + ceil(1 + p * log10(b)) otherwise + + The only macro we care about is this number for the widest supported + floating type, but we want this value for rendering constants below. */ + { + double d_decimal_dig + = 1 + (fmt->p < ldfmt->p ? ldfmt->p : fmt->p) * log10_b; + decimal_dig = d_decimal_dig; + if (decimal_dig < d_decimal_dig) + decimal_dig++; + } + /* Similar, for this type rather than long double. */ + { + double type_d_decimal_dig = 1 + fmt->p * log10_b; + type_decimal_dig = type_d_decimal_dig; + if (type_decimal_dig < type_d_decimal_dig) + type_decimal_dig++; + } + if (type == long_double_type_node) + builtin_define_with_int_value ("__DECIMAL_DIG__", decimal_dig); + else + { + sprintf (name, "__%s_DECIMAL_DIG__", name_prefix); + builtin_define_with_int_value (name, type_decimal_dig); + } + + /* Since, for the supported formats, B is always a power of 2, we + construct the following numbers directly as a hexadecimal + constants. */ + get_max_float (fmt, buf, sizeof (buf)); + + sprintf (name, "__%s_MAX__", name_prefix); + builtin_define_with_hex_fp_value (name, type, decimal_dig, buf, fp_suffix, fp_cast); + + /* The minimum normalized positive floating-point number, + b**(emin-1). */ + sprintf (name, "__%s_MIN__", name_prefix); + sprintf (buf, "0x1p%d", fmt->emin - 1); + builtin_define_with_hex_fp_value (name, type, decimal_dig, buf, fp_suffix, fp_cast); + + /* The difference between 1 and the least value greater than 1 that is + representable in the given floating point type, b**(1-p). */ + sprintf (name, "__%s_EPSILON__", name_prefix); + if (fmt->pnan < fmt->p) + /* This is an IBM extended double format, so 1.0 + any double is + representable precisely. */ + sprintf (buf, "0x1p%d", fmt->emin - fmt->p); + else + sprintf (buf, "0x1p%d", 1 - fmt->p); + builtin_define_with_hex_fp_value (name, type, decimal_dig, buf, fp_suffix, fp_cast); + + /* For C++ std::numeric_limits::denorm_min. The minimum denormalized + positive floating-point number, b**(emin-p). Zero for formats that + don't support denormals. */ + sprintf (name, "__%s_DENORM_MIN__", name_prefix); + if (fmt->has_denorm) + { + sprintf (buf, "0x1p%d", fmt->emin - fmt->p); + builtin_define_with_hex_fp_value (name, type, decimal_dig, + buf, fp_suffix, fp_cast); + } + else + { + sprintf (buf, "0.0%s", fp_suffix); + builtin_define_with_value (name, buf, 0); + } + + sprintf (name, "__%s_HAS_DENORM__", name_prefix); + builtin_define_with_value (name, fmt->has_denorm ? "1" : "0", 0); + + /* For C++ std::numeric_limits::has_infinity. */ + sprintf (name, "__%s_HAS_INFINITY__", name_prefix); + builtin_define_with_int_value (name, + MODE_HAS_INFINITIES (TYPE_MODE (type))); + /* For C++ std::numeric_limits::has_quiet_NaN. We do not have a + predicate to distinguish a target that has both quiet and + signalling NaNs from a target that has only quiet NaNs or only + signalling NaNs, so we assume that a target that has any kind of + NaN has quiet NaNs. */ + sprintf (name, "__%s_HAS_QUIET_NAN__", name_prefix); + builtin_define_with_int_value (name, MODE_HAS_NANS (TYPE_MODE (type))); +} + +/* Define __DECx__ constants for TYPE using NAME_PREFIX and SUFFIX. */ +static void +builtin_define_decimal_float_constants (const char *name_prefix, + const char *suffix, + tree type) +{ + const struct real_format *fmt; + char name[64], buf[128], *p; + int digits; + + fmt = REAL_MODE_FORMAT (TYPE_MODE (type)); + + /* The number of radix digits, p, in the significand. */ + sprintf (name, "__%s_MANT_DIG__", name_prefix); + builtin_define_with_int_value (name, fmt->p); + + /* The minimum negative int x such that b**(x-1) is a normalized float. */ + sprintf (name, "__%s_MIN_EXP__", name_prefix); + sprintf (buf, "(%d)", fmt->emin); + builtin_define_with_value (name, buf, 0); + + /* The maximum int x such that b**(x-1) is a representable float. */ + sprintf (name, "__%s_MAX_EXP__", name_prefix); + builtin_define_with_int_value (name, fmt->emax); + + /* Compute the minimum representable value. */ + sprintf (name, "__%s_MIN__", name_prefix); + sprintf (buf, "1E%d%s", fmt->emin - 1, suffix); + builtin_define_with_value (name, buf, 0); + + /* Compute the maximum representable value. */ + sprintf (name, "__%s_MAX__", name_prefix); + p = buf; + for (digits = fmt->p; digits; digits--) + { + *p++ = '9'; + if (digits == fmt->p) + *p++ = '.'; + } + *p = 0; + /* fmt->p plus 1, to account for the decimal point and fmt->emax + minus 1 because the digits are nines, not 1.0. */ + sprintf (&buf[fmt->p + 1], "E%d%s", fmt->emax - 1, suffix); + builtin_define_with_value (name, buf, 0); + + /* Compute epsilon (the difference between 1 and least value greater + than 1 representable). */ + sprintf (name, "__%s_EPSILON__", name_prefix); + sprintf (buf, "1E-%d%s", fmt->p - 1, suffix); + builtin_define_with_value (name, buf, 0); + + /* Minimum subnormal positive decimal value. */ + sprintf (name, "__%s_SUBNORMAL_MIN__", name_prefix); + p = buf; + for (digits = fmt->p; digits > 1; digits--) + { + *p++ = '0'; + if (digits == fmt->p) + *p++ = '.'; + } + *p = 0; + sprintf (&buf[fmt->p], "1E%d%s", fmt->emin - 1, suffix); + builtin_define_with_value (name, buf, 0); +} + +/* Define fixed-point constants for TYPE using NAME_PREFIX and SUFFIX. */ + +static void +builtin_define_fixed_point_constants (const char *name_prefix, + const char *suffix, + tree type) +{ + char name[64], buf[256], *new_buf; + int i, mod; + + sprintf (name, "__%s_FBIT__", name_prefix); + builtin_define_with_int_value (name, TYPE_FBIT (type)); + + sprintf (name, "__%s_IBIT__", name_prefix); + builtin_define_with_int_value (name, TYPE_IBIT (type)); + + /* If there is no suffix, defines are for fixed-point modes. + We just return. */ + if (strcmp (suffix, "") == 0) + return; + + if (TYPE_UNSIGNED (type)) + { + sprintf (name, "__%s_MIN__", name_prefix); + sprintf (buf, "0.0%s", suffix); + builtin_define_with_value (name, buf, 0); + } + else + { + sprintf (name, "__%s_MIN__", name_prefix); + if (ALL_ACCUM_MODE_P (TYPE_MODE (type))) + sprintf (buf, "(-0X1P%d%s-0X1P%d%s)", TYPE_IBIT (type) - 1, suffix, + TYPE_IBIT (type) - 1, suffix); + else + sprintf (buf, "(-0.5%s-0.5%s)", suffix, suffix); + builtin_define_with_value (name, buf, 0); + } + + sprintf (name, "__%s_MAX__", name_prefix); + sprintf (buf, "0X"); + new_buf = buf + 2; + mod = (TYPE_FBIT (type) + TYPE_IBIT (type)) % 4; + if (mod) + sprintf (new_buf++, "%x", (1 << mod) - 1); + for (i = 0; i < (TYPE_FBIT (type) + TYPE_IBIT (type)) / 4; i++) + sprintf (new_buf++, "F"); + sprintf (new_buf, "P-%d%s", TYPE_FBIT (type), suffix); + builtin_define_with_value (name, buf, 0); + + sprintf (name, "__%s_EPSILON__", name_prefix); + sprintf (buf, "0x1P-%d%s", TYPE_FBIT (type), suffix); + builtin_define_with_value (name, buf, 0); +} + +/* Define __GNUC__, __GNUC_MINOR__ and __GNUC_PATCHLEVEL__. */ +static void +define__GNUC__ (void) +{ + int major, minor, patchlevel; + + if (sscanf (BASEVER, "%d.%d.%d", &major, &minor, &patchlevel) != 3) + { + sscanf (BASEVER, "%d.%d", &major, &minor); + patchlevel = 0; + } + cpp_define_formatted (parse_in, "__GNUC__=%d", major); + cpp_define_formatted (parse_in, "__GNUC_MINOR__=%d", minor); + cpp_define_formatted (parse_in, "__GNUC_PATCHLEVEL__=%d", patchlevel); + + if (c_dialect_cxx ()) + cpp_define_formatted (parse_in, "__GNUG__=%d", major); +} + +/* Define macros used by . */ +static void +builtin_define_stdint_macros (void) +{ + builtin_define_type_max ("__INTMAX_MAX__", intmax_type_node); + builtin_define_constants ("__INTMAX_C", intmax_type_node); + builtin_define_type_max ("__UINTMAX_MAX__", uintmax_type_node); + builtin_define_constants ("__UINTMAX_C", uintmax_type_node); + if (sig_atomic_type_node) + builtin_define_type_minmax ("__SIG_ATOMIC_MIN__", "__SIG_ATOMIC_MAX__", + sig_atomic_type_node); + if (int8_type_node) + builtin_define_type_max ("__INT8_MAX__", int8_type_node); + if (int16_type_node) + builtin_define_type_max ("__INT16_MAX__", int16_type_node); + if (int32_type_node) + builtin_define_type_max ("__INT32_MAX__", int32_type_node); + if (int64_type_node) + builtin_define_type_max ("__INT64_MAX__", int64_type_node); + if (uint8_type_node) + builtin_define_type_max ("__UINT8_MAX__", uint8_type_node); + if (uint16_type_node) + builtin_define_type_max ("__UINT16_MAX__", uint16_type_node); + if (c_uint32_type_node) + builtin_define_type_max ("__UINT32_MAX__", c_uint32_type_node); + if (c_uint64_type_node) + builtin_define_type_max ("__UINT64_MAX__", c_uint64_type_node); + if (int_least8_type_node) + { + builtin_define_type_max ("__INT_LEAST8_MAX__", int_least8_type_node); + builtin_define_constants ("__INT8_C", int_least8_type_node); + } + if (int_least16_type_node) + { + builtin_define_type_max ("__INT_LEAST16_MAX__", int_least16_type_node); + builtin_define_constants ("__INT16_C", int_least16_type_node); + } + if (int_least32_type_node) + { + builtin_define_type_max ("__INT_LEAST32_MAX__", int_least32_type_node); + builtin_define_constants ("__INT32_C", int_least32_type_node); + } + if (int_least64_type_node) + { + builtin_define_type_max ("__INT_LEAST64_MAX__", int_least64_type_node); + builtin_define_constants ("__INT64_C", int_least64_type_node); + } + if (uint_least8_type_node) + { + builtin_define_type_max ("__UINT_LEAST8_MAX__", uint_least8_type_node); + builtin_define_constants ("__UINT8_C", uint_least8_type_node); + } + if (uint_least16_type_node) + { + builtin_define_type_max ("__UINT_LEAST16_MAX__", uint_least16_type_node); + builtin_define_constants ("__UINT16_C", uint_least16_type_node); + } + if (uint_least32_type_node) + { + builtin_define_type_max ("__UINT_LEAST32_MAX__", uint_least32_type_node); + builtin_define_constants ("__UINT32_C", uint_least32_type_node); + } + if (uint_least64_type_node) + { + builtin_define_type_max ("__UINT_LEAST64_MAX__", uint_least64_type_node); + builtin_define_constants ("__UINT64_C", uint_least64_type_node); + } + if (int_fast8_type_node) + builtin_define_type_max ("__INT_FAST8_MAX__", int_fast8_type_node); + if (int_fast16_type_node) + builtin_define_type_max ("__INT_FAST16_MAX__", int_fast16_type_node); + if (int_fast32_type_node) + builtin_define_type_max ("__INT_FAST32_MAX__", int_fast32_type_node); + if (int_fast64_type_node) + builtin_define_type_max ("__INT_FAST64_MAX__", int_fast64_type_node); + if (uint_fast8_type_node) + builtin_define_type_max ("__UINT_FAST8_MAX__", uint_fast8_type_node); + if (uint_fast16_type_node) + builtin_define_type_max ("__UINT_FAST16_MAX__", uint_fast16_type_node); + if (uint_fast32_type_node) + builtin_define_type_max ("__UINT_FAST32_MAX__", uint_fast32_type_node); + if (uint_fast64_type_node) + builtin_define_type_max ("__UINT_FAST64_MAX__", uint_fast64_type_node); + if (intptr_type_node) + builtin_define_type_max ("__INTPTR_MAX__", intptr_type_node); + if (uintptr_type_node) + builtin_define_type_max ("__UINTPTR_MAX__", uintptr_type_node); +} + +/* Adjust the optimization macros when a #pragma GCC optimization is done to + reflect the current level. */ +void +c_cpp_builtins_optimize_pragma (cpp_reader *pfile, tree prev_tree, + tree cur_tree) +{ + struct cl_optimization *prev = TREE_OPTIMIZATION (prev_tree); + struct cl_optimization *cur = TREE_OPTIMIZATION (cur_tree); + bool prev_fast_math; + bool cur_fast_math; + + /* -undef turns off target-specific built-ins. */ + if (flag_undef) + return; + + /* Other target-independent built-ins determined by command-line + options. */ + if (!prev->optimize_size && cur->optimize_size) + cpp_define (pfile, "__OPTIMIZE_SIZE__"); + else if (prev->optimize_size && !cur->optimize_size) + cpp_undef (pfile, "__OPTIMIZE_SIZE__"); + + if (!prev->optimize && cur->optimize) + cpp_define (pfile, "__OPTIMIZE__"); + else if (prev->optimize && !cur->optimize) + cpp_undef (pfile, "__OPTIMIZE__"); + + prev_fast_math = fast_math_flags_struct_set_p (prev); + cur_fast_math = fast_math_flags_struct_set_p (cur); + if (!prev_fast_math && cur_fast_math) + cpp_define (pfile, "__FAST_MATH__"); + else if (prev_fast_math && !cur_fast_math) + cpp_undef (pfile, "__FAST_MATH__"); + + if (!prev->flag_signaling_nans && cur->flag_signaling_nans) + cpp_define (pfile, "__SUPPORT_SNAN__"); + else if (prev->flag_signaling_nans && !cur->flag_signaling_nans) + cpp_undef (pfile, "__SUPPORT_SNAN__"); + + if (!prev->flag_finite_math_only && cur->flag_finite_math_only) + { + cpp_undef (pfile, "__FINITE_MATH_ONLY__"); + cpp_define (pfile, "__FINITE_MATH_ONLY__=1"); + } + else if (!prev->flag_finite_math_only && cur->flag_finite_math_only) + { + cpp_undef (pfile, "__FINITE_MATH_ONLY__"); + cpp_define (pfile, "__FINITE_MATH_ONLY__=0"); + } +} + + +/* Hook that registers front end and target-specific built-ins. */ +void +c_cpp_builtins (cpp_reader *pfile) +{ + /* -undef turns off target-specific built-ins. */ + if (flag_undef) + return; + + define__GNUC__ (); + + /* For stddef.h. They require macros defined in c-common.c. */ + c_stddef_cpp_builtins (); + + if (c_dialect_cxx ()) + { + if (flag_weak && SUPPORTS_ONE_ONLY) + cpp_define (pfile, "__GXX_WEAK__=1"); + else + cpp_define (pfile, "__GXX_WEAK__=0"); + if (warn_deprecated) + cpp_define (pfile, "__DEPRECATED"); + if (flag_rtti) + cpp_define (pfile, "__GXX_RTTI"); + if (cxx_dialect == cxx0x) + cpp_define (pfile, "__GXX_EXPERIMENTAL_CXX0X__"); + } + /* Note that we define this for C as well, so that we know if + __attribute__((cleanup)) will interface with EH. */ + if (flag_exceptions) + cpp_define (pfile, "__EXCEPTIONS"); + + /* Represents the C++ ABI version, always defined so it can be used while + preprocessing C and assembler. */ + if (flag_abi_version == 0) + /* Use a very large value so that: + + #if __GXX_ABI_VERSION >= + + will work whether the user explicitly says "-fabi-version=x" or + "-fabi-version=0". Do not use INT_MAX because that will be + different from system to system. */ + builtin_define_with_int_value ("__GXX_ABI_VERSION", 999999); + else if (flag_abi_version == 1) + /* Due to a historical accident, this version had the value + "102". */ + builtin_define_with_int_value ("__GXX_ABI_VERSION", 102); + else + /* Newer versions have values 1002, 1003, .... */ + builtin_define_with_int_value ("__GXX_ABI_VERSION", + 1000 + flag_abi_version); + + /* libgcc needs to know this. */ + if (USING_SJLJ_EXCEPTIONS) + cpp_define (pfile, "__USING_SJLJ_EXCEPTIONS__"); + + /* limits.h and stdint.h need to know these. */ + builtin_define_type_max ("__SCHAR_MAX__", signed_char_type_node); + builtin_define_type_max ("__SHRT_MAX__", short_integer_type_node); + builtin_define_type_max ("__INT_MAX__", integer_type_node); + builtin_define_type_max ("__LONG_MAX__", long_integer_type_node); + builtin_define_type_max ("__LONG_LONG_MAX__", long_long_integer_type_node); + builtin_define_type_minmax ("__WCHAR_MIN__", "__WCHAR_MAX__", + underlying_wchar_type_node); + builtin_define_type_minmax ("__WINT_MIN__", "__WINT_MAX__", wint_type_node); + builtin_define_type_max ("__PTRDIFF_MAX__", ptrdiff_type_node); + builtin_define_type_max ("__SIZE_MAX__", size_type_node); + + builtin_define_type_precision ("__CHAR_BIT__", char_type_node); + + /* stdint.h and the testsuite need to know these. */ + builtin_define_stdint_macros (); + + /* float.h needs to know these. */ + + builtin_define_with_int_value ("__FLT_EVAL_METHOD__", + TARGET_FLT_EVAL_METHOD); + + /* And decfloat.h needs this. */ + builtin_define_with_int_value ("__DEC_EVAL_METHOD__", + TARGET_DEC_EVAL_METHOD); + + builtin_define_float_constants ("FLT", "F", "%s", float_type_node); + /* Cast the double precision constants. This is needed when single + precision constants are specified or when pragma FLOAT_CONST_DECIMAL64 + is used. The correct result is computed by the compiler when using + macros that include a cast. */ + builtin_define_float_constants ("DBL", "L", "((double)%s)", double_type_node); + builtin_define_float_constants ("LDBL", "L", "%s", long_double_type_node); + + /* For decfloat.h. */ + builtin_define_decimal_float_constants ("DEC32", "DF", dfloat32_type_node); + builtin_define_decimal_float_constants ("DEC64", "DD", dfloat64_type_node); + builtin_define_decimal_float_constants ("DEC128", "DL", dfloat128_type_node); + + /* For fixed-point fibt, ibit, max, min, and epsilon. */ + if (targetm.fixed_point_supported_p ()) + { + builtin_define_fixed_point_constants ("SFRACT", "HR", + short_fract_type_node); + builtin_define_fixed_point_constants ("USFRACT", "UHR", + unsigned_short_fract_type_node); + builtin_define_fixed_point_constants ("FRACT", "R", + fract_type_node); + builtin_define_fixed_point_constants ("UFRACT", "UR", + unsigned_fract_type_node); + builtin_define_fixed_point_constants ("LFRACT", "LR", + long_fract_type_node); + builtin_define_fixed_point_constants ("ULFRACT", "ULR", + unsigned_long_fract_type_node); + builtin_define_fixed_point_constants ("LLFRACT", "LLR", + long_long_fract_type_node); + builtin_define_fixed_point_constants ("ULLFRACT", "ULLR", + unsigned_long_long_fract_type_node); + builtin_define_fixed_point_constants ("SACCUM", "HK", + short_accum_type_node); + builtin_define_fixed_point_constants ("USACCUM", "UHK", + unsigned_short_accum_type_node); + builtin_define_fixed_point_constants ("ACCUM", "K", + accum_type_node); + builtin_define_fixed_point_constants ("UACCUM", "UK", + unsigned_accum_type_node); + builtin_define_fixed_point_constants ("LACCUM", "LK", + long_accum_type_node); + builtin_define_fixed_point_constants ("ULACCUM", "ULK", + unsigned_long_accum_type_node); + builtin_define_fixed_point_constants ("LLACCUM", "LLK", + long_long_accum_type_node); + builtin_define_fixed_point_constants ("ULLACCUM", "ULLK", + unsigned_long_long_accum_type_node); + + builtin_define_fixed_point_constants ("QQ", "", qq_type_node); + builtin_define_fixed_point_constants ("HQ", "", hq_type_node); + builtin_define_fixed_point_constants ("SQ", "", sq_type_node); + builtin_define_fixed_point_constants ("DQ", "", dq_type_node); + builtin_define_fixed_point_constants ("TQ", "", tq_type_node); + builtin_define_fixed_point_constants ("UQQ", "", uqq_type_node); + builtin_define_fixed_point_constants ("UHQ", "", uhq_type_node); + builtin_define_fixed_point_constants ("USQ", "", usq_type_node); + builtin_define_fixed_point_constants ("UDQ", "", udq_type_node); + builtin_define_fixed_point_constants ("UTQ", "", utq_type_node); + builtin_define_fixed_point_constants ("HA", "", ha_type_node); + builtin_define_fixed_point_constants ("SA", "", sa_type_node); + builtin_define_fixed_point_constants ("DA", "", da_type_node); + builtin_define_fixed_point_constants ("TA", "", ta_type_node); + builtin_define_fixed_point_constants ("UHA", "", uha_type_node); + builtin_define_fixed_point_constants ("USA", "", usa_type_node); + builtin_define_fixed_point_constants ("UDA", "", uda_type_node); + builtin_define_fixed_point_constants ("UTA", "", uta_type_node); + } + + /* For use in assembly language. */ + builtin_define_with_value ("__REGISTER_PREFIX__", REGISTER_PREFIX, 0); + builtin_define_with_value ("__USER_LABEL_PREFIX__", user_label_prefix, 0); + + /* Misc. */ + builtin_define_with_value ("__VERSION__", version_string, 1); + + if (flag_gnu89_inline) + cpp_define (pfile, "__GNUC_GNU_INLINE__"); + else + cpp_define (pfile, "__GNUC_STDC_INLINE__"); + + /* Definitions for LP64 model. */ + if (TYPE_PRECISION (long_integer_type_node) == 64 + && POINTER_SIZE == 64 + && TYPE_PRECISION (integer_type_node) == 32) + { + cpp_define (pfile, "_LP64"); + cpp_define (pfile, "__LP64__"); + } + + /* Other target-independent built-ins determined by command-line + options. */ + if (optimize_size) + cpp_define (pfile, "__OPTIMIZE_SIZE__"); + if (optimize) + cpp_define (pfile, "__OPTIMIZE__"); + + if (fast_math_flags_set_p ()) + cpp_define (pfile, "__FAST_MATH__"); + if (flag_no_inline) + cpp_define (pfile, "__NO_INLINE__"); + if (flag_signaling_nans) + cpp_define (pfile, "__SUPPORT_SNAN__"); + if (flag_finite_math_only) + cpp_define (pfile, "__FINITE_MATH_ONLY__=1"); + else + cpp_define (pfile, "__FINITE_MATH_ONLY__=0"); + if (flag_pic) + { + builtin_define_with_int_value ("__pic__", flag_pic); + builtin_define_with_int_value ("__PIC__", flag_pic); + } + if (flag_pie) + { + builtin_define_with_int_value ("__pie__", flag_pie); + builtin_define_with_int_value ("__PIE__", flag_pie); + } + + if (flag_iso) + cpp_define (pfile, "__STRICT_ANSI__"); + + if (!flag_signed_char) + cpp_define (pfile, "__CHAR_UNSIGNED__"); + + if (c_dialect_cxx () && TYPE_UNSIGNED (wchar_type_node)) + cpp_define (pfile, "__WCHAR_UNSIGNED__"); + + /* Tell source code if the compiler makes sync_compare_and_swap + builtins available. */ +#ifdef HAVE_sync_compare_and_swapqi + if (HAVE_sync_compare_and_swapqi) + cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); +#endif + +#ifdef HAVE_sync_compare_and_swaphi + if (HAVE_sync_compare_and_swaphi) + cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); +#endif + +#ifdef HAVE_sync_compare_and_swapsi + if (HAVE_sync_compare_and_swapsi) + cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); +#endif + +#ifdef HAVE_sync_compare_and_swapdi + if (HAVE_sync_compare_and_swapdi) + cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); +#endif + +#ifdef HAVE_sync_compare_and_swapti + if (HAVE_sync_compare_and_swapti) + cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); +#endif + +#ifdef DWARF2_UNWIND_INFO + if (dwarf2out_do_cfi_asm ()) + cpp_define (pfile, "__GCC_HAVE_DWARF2_CFI_ASM"); +#endif + + /* Make the choice of ObjC runtime visible to source code. */ + if (c_dialect_objc () && flag_next_runtime) + cpp_define (pfile, "__NEXT_RUNTIME__"); + + /* Show the availability of some target pragmas. */ + cpp_define (pfile, "__PRAGMA_REDEFINE_EXTNAME"); + + if (targetm.handle_pragma_extern_prefix) + cpp_define (pfile, "__PRAGMA_EXTERN_PREFIX"); + + /* Make the choice of the stack protector runtime visible to source code. + The macro names and values here were chosen for compatibility with an + earlier implementation, i.e. ProPolice. */ + if (flag_stack_protect == 2) + cpp_define (pfile, "__SSP_ALL__=2"); + else if (flag_stack_protect == 1) + cpp_define (pfile, "__SSP__=1"); + + if (flag_openmp) + cpp_define (pfile, "_OPENMP=200805"); + + builtin_define_type_sizeof ("__SIZEOF_INT__", integer_type_node); + builtin_define_type_sizeof ("__SIZEOF_LONG__", long_integer_type_node); + builtin_define_type_sizeof ("__SIZEOF_LONG_LONG__", + long_long_integer_type_node); + if (int128_integer_type_node != NULL_TREE) + builtin_define_type_sizeof ("__SIZEOF_INT128__", + int128_integer_type_node); + builtin_define_type_sizeof ("__SIZEOF_SHORT__", short_integer_type_node); + builtin_define_type_sizeof ("__SIZEOF_FLOAT__", float_type_node); + builtin_define_type_sizeof ("__SIZEOF_DOUBLE__", double_type_node); + builtin_define_type_sizeof ("__SIZEOF_LONG_DOUBLE__", long_double_type_node); + builtin_define_type_sizeof ("__SIZEOF_SIZE_T__", size_type_node); + builtin_define_type_sizeof ("__SIZEOF_WCHAR_T__", wchar_type_node); + builtin_define_type_sizeof ("__SIZEOF_WINT_T__", wint_type_node); + builtin_define_type_sizeof ("__SIZEOF_PTRDIFF_T__", + unsigned_ptrdiff_type_node); + /* ptr_type_node can't be used here since ptr_mode is only set when + toplev calls backend_init which is not done with -E switch. */ + builtin_define_with_int_value ("__SIZEOF_POINTER__", + POINTER_SIZE / BITS_PER_UNIT); + + /* A straightforward target hook doesn't work, because of problems + linking that hook's body when part of non-C front ends. */ +# define preprocessing_asm_p() (cpp_get_options (pfile)->lang == CLK_ASM) +# define preprocessing_trad_p() (cpp_get_options (pfile)->traditional) +# define builtin_define(TXT) cpp_define (pfile, TXT) +# define builtin_assert(TXT) cpp_assert (pfile, TXT) + TARGET_CPU_CPP_BUILTINS (); + TARGET_OS_CPP_BUILTINS (); + TARGET_OBJFMT_CPP_BUILTINS (); + + /* Support the __declspec keyword by turning them into attributes. + Note that the current way we do this may result in a collision + with predefined attributes later on. This can be solved by using + one attribute, say __declspec__, and passing args to it. The + problem with that approach is that args are not accumulated: each + new appearance would clobber any existing args. */ + if (TARGET_DECLSPEC) + builtin_define ("__declspec(x)=__attribute__((x))"); + + /* If decimal floating point is supported, tell the user if the + alternate format (BID) is used instead of the standard (DPD) + format. */ + if (ENABLE_DECIMAL_FLOAT && ENABLE_DECIMAL_BID_FORMAT) + cpp_define (pfile, "__DECIMAL_BID_FORMAT__"); + + builtin_define_with_int_value ("__BIGGEST_ALIGNMENT__", + BIGGEST_ALIGNMENT / BITS_PER_UNIT); +} + +/* Pass an object-like macro. If it doesn't lie in the user's + namespace, defines it unconditionally. Otherwise define a version + with two leading underscores, and another version with two leading + and trailing underscores, and define the original only if an ISO + standard was not nominated. + + e.g. passing "unix" defines "__unix", "__unix__" and possibly + "unix". Passing "_mips" defines "__mips", "__mips__" and possibly + "_mips". */ +void +builtin_define_std (const char *macro) +{ + size_t len = strlen (macro); + char *buff = (char *) alloca (len + 5); + char *p = buff + 2; + char *q = p + len; + + /* prepend __ (or maybe just _) if in user's namespace. */ + memcpy (p, macro, len + 1); + if (!( *p == '_' && (p[1] == '_' || ISUPPER (p[1])))) + { + if (*p != '_') + *--p = '_'; + if (p[1] != '_') + *--p = '_'; + } + cpp_define (parse_in, p); + + /* If it was in user's namespace... */ + if (p != buff + 2) + { + /* Define the macro with leading and following __. */ + if (q[-1] != '_') + *q++ = '_'; + if (q[-2] != '_') + *q++ = '_'; + *q = '\0'; + cpp_define (parse_in, p); + + /* Finally, define the original macro if permitted. */ + if (!flag_iso) + cpp_define (parse_in, macro); + } +} + +/* Pass an object-like macro and a value to define it to. The third + parameter says whether or not to turn the value into a string + constant. */ +void +builtin_define_with_value (const char *macro, const char *expansion, int is_str) +{ + char *buf; + size_t mlen = strlen (macro); + size_t elen = strlen (expansion); + size_t extra = 2; /* space for an = and a NUL */ + + if (is_str) + extra += 2; /* space for two quote marks */ + + buf = (char *) alloca (mlen + elen + extra); + if (is_str) + sprintf (buf, "%s=\"%s\"", macro, expansion); + else + sprintf (buf, "%s=%s", macro, expansion); + + cpp_define (parse_in, buf); +} + + +/* Pass an object-like macro and an integer value to define it to. */ +static void +builtin_define_with_int_value (const char *macro, HOST_WIDE_INT value) +{ + char *buf; + size_t mlen = strlen (macro); + size_t vlen = 18; + size_t extra = 2; /* space for = and NUL. */ + + buf = (char *) alloca (mlen + vlen + extra); + memcpy (buf, macro, mlen); + buf[mlen] = '='; + sprintf (buf + mlen + 1, HOST_WIDE_INT_PRINT_DEC, value); + + cpp_define (parse_in, buf); +} + +/* Pass an object-like macro a hexadecimal floating-point value. */ +static void +builtin_define_with_hex_fp_value (const char *macro, + tree type, int digits, + const char *hex_str, + const char *fp_suffix, + const char *fp_cast) +{ + REAL_VALUE_TYPE real; + char dec_str[64], buf1[256], buf2[256]; + + /* Hex values are really cool and convenient, except that they're + not supported in strict ISO C90 mode. First, the "p-" sequence + is not valid as part of a preprocessor number. Second, we get a + pedwarn from the preprocessor, which has no context, so we can't + suppress the warning with __extension__. + + So instead what we do is construct the number in hex (because + it's easy to get the exact correct value), parse it as a real, + then print it back out as decimal. */ + + real_from_string (&real, hex_str); + real_to_decimal_for_mode (dec_str, &real, sizeof (dec_str), digits, 0, + TYPE_MODE (type)); + + /* Assemble the macro in the following fashion + macro = fp_cast [dec_str fp_suffix] */ + sprintf (buf1, "%s%s", dec_str, fp_suffix); + sprintf (buf2, fp_cast, buf1); + sprintf (buf1, "%s=%s", macro, buf2); + + cpp_define (parse_in, buf1); +} + +/* Return a string constant for the suffix for a value of type TYPE + promoted according to the integer promotions. The type must be one + of the standard integer type nodes. */ + +static const char * +type_suffix (tree type) +{ + static const char *const suffixes[] = { "", "U", "L", "UL", "LL", "ULL" }; + int unsigned_suffix; + int is_long; + + if (type == long_long_integer_type_node + || type == long_long_unsigned_type_node) + is_long = 2; + else if (type == long_integer_type_node + || type == long_unsigned_type_node) + is_long = 1; + else if (type == integer_type_node + || type == unsigned_type_node + || type == short_integer_type_node + || type == short_unsigned_type_node + || type == signed_char_type_node + || type == unsigned_char_type_node + /* ??? "char" is not a signed or unsigned integer type and + so is not permitted for the standard typedefs, but some + systems use it anyway. */ + || type == char_type_node) + is_long = 0; + else + gcc_unreachable (); + + unsigned_suffix = TYPE_UNSIGNED (type); + if (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + unsigned_suffix = 0; + return suffixes[is_long * 2 + unsigned_suffix]; +} + +/* Define MACRO as a constant-suffix macro for TYPE. */ +static void +builtin_define_constants (const char *macro, tree type) +{ + const char *suffix; + char *buf; + + suffix = type_suffix (type); + + if (suffix[0] == 0) + { + buf = (char *) alloca (strlen (macro) + 6); + sprintf (buf, "%s(c)=c", macro); + } + else + { + buf = (char *) alloca (strlen (macro) + 9 + strlen (suffix) + 1); + sprintf (buf, "%s(c)=c ## %s", macro, suffix); + } + + cpp_define (parse_in, buf); +} + +/* Define MAX for TYPE based on the precision of the type. */ + +static void +builtin_define_type_max (const char *macro, tree type) +{ + builtin_define_type_minmax (NULL, macro, type); +} + +/* Define MIN_MACRO (if not NULL) and MAX_MACRO for TYPE based on the + precision of the type. */ + +static void +builtin_define_type_minmax (const char *min_macro, const char *max_macro, + tree type) +{ + static const char *const values[] + = { "127", "255", + "32767", "65535", + "2147483647", "4294967295", + "9223372036854775807", "18446744073709551615", + "170141183460469231731687303715884105727", + "340282366920938463463374607431768211455" }; + + const char *value, *suffix; + char *buf; + size_t idx; + + /* Pre-rendering the values mean we don't have to futz with printing a + multi-word decimal value. There are also a very limited number of + precisions that we support, so it's really a waste of time. */ + switch (TYPE_PRECISION (type)) + { + case 8: idx = 0; break; + case 16: idx = 2; break; + case 32: idx = 4; break; + case 64: idx = 6; break; + case 128: idx = 8; break; + default: gcc_unreachable (); + } + + value = values[idx + TYPE_UNSIGNED (type)]; + suffix = type_suffix (type); + + buf = (char *) alloca (strlen (max_macro) + 1 + strlen (value) + + strlen (suffix) + 1); + sprintf (buf, "%s=%s%s", max_macro, value, suffix); + + cpp_define (parse_in, buf); + + if (min_macro) + { + if (TYPE_UNSIGNED (type)) + { + buf = (char *) alloca (strlen (min_macro) + 2 + strlen (suffix) + 1); + sprintf (buf, "%s=0%s", min_macro, suffix); + } + else + { + buf = (char *) alloca (strlen (min_macro) + 3 + + strlen (max_macro) + 6); + sprintf (buf, "%s=(-%s - 1)", min_macro, max_macro); + } + cpp_define (parse_in, buf); + } +} diff --git a/gcc/c-family/c-dump.c b/gcc/c-family/c-dump.c new file mode 100644 index 0000000..71e872e --- /dev/null +++ b/gcc/c-family/c-dump.c @@ -0,0 +1,61 @@ +/* Tree-dumping functionality for C-family languages. + Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc. + Written by Mark Mitchell + +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 "tree.h" +#include "tree-dump.h" +#include "c-common.h" + +/* Dump information common to statements from STMT. */ + +void +dump_stmt (dump_info_p di, const_tree t) +{ + if (EXPR_HAS_LOCATION (t)) + dump_int (di, "line", EXPR_LINENO (t)); +} + +/* Dump any C-specific tree codes and attributes of common codes. */ + +bool +c_dump_tree (void *dump_info, tree t) +{ + enum tree_code code; + dump_info_p di = (dump_info_p) dump_info; + + /* Figure out what kind of node this is. */ + code = TREE_CODE (t); + + switch (code) + { + case FIELD_DECL: + if (DECL_C_BIT_FIELD (t)) + dump_string (di, "bitfield"); + break; + + default: + break; + } + + return false; +} diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c new file mode 100644 index 0000000..2c73ead --- /dev/null +++ b/gcc/c-family/c-format.c @@ -0,0 +1,2870 @@ +/* Check calls to formatted I/O functions (-Wformat). + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 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 "tree.h" +#include "flags.h" +#include "c-common.h" +#include "toplev.h" +#include "intl.h" +#include "diagnostic-core.h" +#include "langhooks.h" +#include "c-format.h" +#include "alloc-pool.h" + +/* Set format warning options according to a -Wformat=n option. */ + +void +set_Wformat (int setting) +{ + warn_format = setting; + warn_format_extra_args = setting; + warn_format_zero_length = setting; + warn_format_contains_nul = setting; + if (setting != 1) + { + warn_format_nonliteral = setting; + warn_format_security = setting; + warn_format_y2k = setting; + } + /* Make sure not to disable -Wnonnull if -Wformat=0 is specified. */ + if (setting) + warn_nonnull = setting; +} + + +/* Handle attributes associated with format checking. */ + +/* This must be in the same order as format_types, except for + format_type_error. Target-specific format types do not have + matching enum values. */ +enum format_type { printf_format_type, asm_fprintf_format_type, + gcc_diag_format_type, gcc_tdiag_format_type, + gcc_cdiag_format_type, + gcc_cxxdiag_format_type, gcc_gfc_format_type, + format_type_error = -1}; + +typedef struct function_format_info +{ + int format_type; /* type of format (printf, scanf, etc.) */ + unsigned HOST_WIDE_INT format_num; /* number of format argument */ + unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */ +} function_format_info; + +static bool decode_format_attr (tree, function_format_info *, int); +static int decode_format_type (const char *); + +static bool check_format_string (tree argument, + unsigned HOST_WIDE_INT format_num, + int flags, bool *no_add_attrs); +static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value, + int validated_p); +static const char *convert_format_name_to_system_name (const char *attr_name); +static bool cmp_attribs (const char *tattr_name, const char *attr_name); + +/* Handle a "format_arg" attribute; arguments as in + struct attribute_spec.handler. */ +tree +handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name), + tree args, int flags, bool *no_add_attrs) +{ + tree type = *node; + tree format_num_expr = TREE_VALUE (args); + unsigned HOST_WIDE_INT format_num = 0; + tree argument; + + if (!get_constant (format_num_expr, &format_num, 0)) + { + error ("format string has invalid operand number"); + *no_add_attrs = true; + return NULL_TREE; + } + + argument = TYPE_ARG_TYPES (type); + if (argument) + { + if (!check_format_string (argument, format_num, flags, no_add_attrs)) + return NULL_TREE; + } + + if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) + != char_type_node)) + { + if (!(flags & (int) ATTR_FLAG_BUILT_IN)) + error ("function does not return string type"); + *no_add_attrs = true; + return NULL_TREE; + } + + return NULL_TREE; +} + +/* Verify that the format_num argument is actually a string, in case + the format attribute is in error. */ +static bool +check_format_string (tree argument, unsigned HOST_WIDE_INT format_num, + int flags, bool *no_add_attrs) +{ + unsigned HOST_WIDE_INT i; + + for (i = 1; i != format_num; i++) + { + if (argument == 0) + break; + argument = TREE_CHAIN (argument); + } + + if (!argument + || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) + != char_type_node)) + { + if (!(flags & (int) ATTR_FLAG_BUILT_IN)) + error ("format string argument not a string type"); + *no_add_attrs = true; + return false; + } + + return true; +} + +/* Verify EXPR is a constant, and store its value. + If validated_p is true there should be no errors. + Returns true on success, false otherwise. */ +static bool +get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p) +{ + if (TREE_CODE (expr) != INTEGER_CST || TREE_INT_CST_HIGH (expr) != 0) + { + gcc_assert (!validated_p); + return false; + } + + *value = TREE_INT_CST_LOW (expr); + + return true; +} + +/* Decode the arguments to a "format" attribute into a + function_format_info structure. It is already known that the list + is of the right length. If VALIDATED_P is true, then these + attributes have already been validated and must not be erroneous; + if false, it will give an error message. Returns true if the + attributes are successfully decoded, false otherwise. */ + +static bool +decode_format_attr (tree args, function_format_info *info, int validated_p) +{ + tree format_type_id = TREE_VALUE (args); + tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); + tree first_arg_num_expr + = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); + + if (TREE_CODE (format_type_id) != IDENTIFIER_NODE) + { + gcc_assert (!validated_p); + error ("unrecognized format specifier"); + return false; + } + else + { + const char *p = IDENTIFIER_POINTER (format_type_id); + + p = convert_format_name_to_system_name (p); + + info->format_type = decode_format_type (p); + + if (info->format_type == format_type_error) + { + gcc_assert (!validated_p); + warning (OPT_Wformat, "%qE is an unrecognized format function type", + format_type_id); + return false; + } + } + + if (!get_constant (format_num_expr, &info->format_num, validated_p)) + { + error ("format string has invalid operand number"); + return false; + } + + if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p)) + { + error ("%<...%> has invalid operand number"); + return false; + } + + if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num) + { + gcc_assert (!validated_p); + error ("format string argument follows the args to be formatted"); + return false; + } + + return true; +} + +/* Check a call to a format function against a parameter list. */ + +/* The C standard version C++ is treated as equivalent to + or inheriting from, for the purpose of format features supported. */ +#define CPLUSPLUS_STD_VER STD_C94 +/* The C standard version we are checking formats against when pedantic. */ +#define C_STD_VER ((int) (c_dialect_cxx () \ + ? CPLUSPLUS_STD_VER \ + : (flag_isoc99 \ + ? STD_C99 \ + : (flag_isoc94 ? STD_C94 : STD_C89)))) +/* The name to give to the standard version we are warning about when + pedantic. FEATURE_VER is the version in which the feature warned out + appeared, which is higher than C_STD_VER. */ +#define C_STD_NAME(FEATURE_VER) (c_dialect_cxx () \ + ? "ISO C++" \ + : ((FEATURE_VER) == STD_EXT \ + ? "ISO C" \ + : "ISO C90")) +/* Adjust a C standard version, which may be STD_C9L, to account for + -Wno-long-long. Returns other standard versions unchanged. */ +#define ADJ_STD(VER) ((int) ((VER) == STD_C9L \ + ? (warn_long_long ? STD_C99 : STD_C89) \ + : (VER))) + +/* Structure describing details of a type expected in format checking, + and the type to check against it. */ +typedef struct format_wanted_type +{ + /* The type wanted. */ + tree wanted_type; + /* The name of this type to use in diagnostics. */ + const char *wanted_type_name; + /* Should be type checked just for scalar width identity. */ + int scalar_identity_flag; + /* The level of indirection through pointers at which this type occurs. */ + int pointer_count; + /* Whether, when pointer_count is 1, to allow any character type when + pedantic, rather than just the character or void type specified. */ + int char_lenient_flag; + /* Whether the argument, dereferenced once, is written into and so the + argument must not be a pointer to a const-qualified type. */ + int writing_in_flag; + /* Whether the argument, dereferenced once, is read from and so + must not be a NULL pointer. */ + int reading_from_flag; + /* If warnings should be of the form "field precision should have + type 'int'", the name to use (in this case "field precision"), + otherwise NULL, for "format expects type 'long'" type + messages. */ + const char *name; + /* The actual parameter to check against the wanted type. */ + tree param; + /* The argument number of that parameter. */ + int arg_num; + /* The next type to check for this format conversion, or NULL if none. */ + struct format_wanted_type *next; +} format_wanted_type; + +/* Convenience macro for format_length_info meaning unused. */ +#define NO_FMT NULL, FMT_LEN_none, STD_C89 + +static const format_length_info printf_length_specs[] = +{ + { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 }, + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 }, + { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 }, + { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 }, + { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 }, + { "Z", FMT_LEN_z, STD_EXT, NO_FMT, 0 }, + { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 }, + { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 }, + { "H", FMT_LEN_H, STD_EXT, NO_FMT, 0 }, + { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT, 0 }, + { NO_FMT, NO_FMT, 0 } +}; + +/* Length specifiers valid for asm_fprintf. */ +static const format_length_info asm_fprintf_length_specs[] = +{ + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 }, + { "w", FMT_LEN_none, STD_C89, NO_FMT, 0 }, + { NO_FMT, NO_FMT, 0 } +}; + +/* Length specifiers valid for GCC diagnostics. */ +static const format_length_info gcc_diag_length_specs[] = +{ + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 }, + { "w", FMT_LEN_none, STD_C89, NO_FMT, 0 }, + { NO_FMT, NO_FMT, 0 } +}; + +/* The custom diagnostics all accept the same length specifiers. */ +#define gcc_tdiag_length_specs gcc_diag_length_specs +#define gcc_cdiag_length_specs gcc_diag_length_specs +#define gcc_cxxdiag_length_specs gcc_diag_length_specs + +/* This differs from printf_length_specs only in that "Z" is not accepted. */ +static const format_length_info scanf_length_specs[] = +{ + { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 }, + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 }, + { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 }, + { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 }, + { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 }, + { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 }, + { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 }, + { "H", FMT_LEN_H, STD_EXT, NO_FMT, 0 }, + { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT, 0 }, + { NO_FMT, NO_FMT, 0 } +}; + + +/* All tables for strfmon use STD_C89 everywhere, since -pedantic warnings + make no sense for a format type not part of any C standard version. */ +static const format_length_info strfmon_length_specs[] = +{ + /* A GNU extension. */ + { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 }, + { NO_FMT, NO_FMT, 0 } +}; + + +/* For now, the Fortran front-end routines only use l as length modifier. */ +static const format_length_info gcc_gfc_length_specs[] = +{ + { "l", FMT_LEN_l, STD_C89, NO_FMT, 0 }, + { NO_FMT, NO_FMT, 0 } +}; + + +static const format_flag_spec printf_flag_specs[] = +{ + { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 }, + { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, + { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, + { '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 }, + { '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 }, + { '\'', 0, 0, N_("''' flag"), N_("the ''' printf flag"), STD_EXT }, + { 'I', 0, 0, N_("'I' flag"), N_("the 'I' printf flag"), STD_EXT }, + { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, + { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, + { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, + { 0, 0, 0, NULL, NULL, STD_C89 } +}; + + +static const format_flag_pair printf_flag_pairs[] = +{ + { ' ', '+', 1, 0 }, + { '0', '-', 1, 0 }, + { '0', 'p', 1, 'i' }, + { 0, 0, 0, 0 } +}; + +static const format_flag_spec asm_fprintf_flag_specs[] = +{ + { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 }, + { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, + { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, + { '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 }, + { '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 }, + { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, + { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, + { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, + { 0, 0, 0, NULL, NULL, STD_C89 } +}; + +static const format_flag_pair asm_fprintf_flag_pairs[] = +{ + { ' ', '+', 1, 0 }, + { '0', '-', 1, 0 }, + { '0', 'p', 1, 'i' }, + { 0, 0, 0, 0 } +}; + +static const format_flag_pair gcc_diag_flag_pairs[] = +{ + { 0, 0, 0, 0 } +}; + +#define gcc_tdiag_flag_pairs gcc_diag_flag_pairs +#define gcc_cdiag_flag_pairs gcc_diag_flag_pairs +#define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs + +static const format_flag_pair gcc_gfc_flag_pairs[] = +{ + { 0, 0, 0, 0 } +}; + +static const format_flag_spec gcc_diag_flag_specs[] = +{ + { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, + { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, + { 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 }, + { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, + { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, + { 0, 0, 0, NULL, NULL, STD_C89 } +}; + +#define gcc_tdiag_flag_specs gcc_diag_flag_specs +#define gcc_cdiag_flag_specs gcc_diag_flag_specs +#define gcc_cxxdiag_flag_specs gcc_diag_flag_specs + +static const format_flag_spec scanf_flag_specs[] = +{ + { '*', 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 }, + { 'a', 0, 0, N_("'a' flag"), N_("the 'a' scanf flag"), STD_EXT }, + { 'm', 0, 0, N_("'m' flag"), N_("the 'm' scanf flag"), STD_EXT }, + { 'w', 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 }, + { 'L', 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 }, + { '\'', 0, 0, N_("''' flag"), N_("the ''' scanf flag"), STD_EXT }, + { 'I', 0, 0, N_("'I' flag"), N_("the 'I' scanf flag"), STD_EXT }, + { 0, 0, 0, NULL, NULL, STD_C89 } +}; + + +static const format_flag_pair scanf_flag_pairs[] = +{ + { '*', 'L', 0, 0 }, + { 'a', 'm', 0, 0 }, + { 0, 0, 0, 0 } +}; + + +static const format_flag_spec strftime_flag_specs[] = +{ + { '_', 0, 0, N_("'_' flag"), N_("the '_' strftime flag"), STD_EXT }, + { '-', 0, 0, N_("'-' flag"), N_("the '-' strftime flag"), STD_EXT }, + { '0', 0, 0, N_("'0' flag"), N_("the '0' strftime flag"), STD_EXT }, + { '^', 0, 0, N_("'^' flag"), N_("the '^' strftime flag"), STD_EXT }, + { '#', 0, 0, N_("'#' flag"), N_("the '#' strftime flag"), STD_EXT }, + { 'w', 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT }, + { 'E', 0, 0, N_("'E' modifier"), N_("the 'E' strftime modifier"), STD_C99 }, + { 'O', 0, 0, N_("'O' modifier"), N_("the 'O' strftime modifier"), STD_C99 }, + { 'O', 'o', 0, NULL, N_("the 'O' modifier"), STD_EXT }, + { 0, 0, 0, NULL, NULL, STD_C89 } +}; + + +static const format_flag_pair strftime_flag_pairs[] = +{ + { 'E', 'O', 0, 0 }, + { '_', '-', 0, 0 }, + { '_', '0', 0, 0 }, + { '-', '0', 0, 0 }, + { '^', '#', 0, 0 }, + { 0, 0, 0, 0 } +}; + + +static const format_flag_spec strfmon_flag_specs[] = +{ + { '=', 0, 1, N_("fill character"), N_("fill character in strfmon format"), STD_C89 }, + { '^', 0, 0, N_("'^' flag"), N_("the '^' strfmon flag"), STD_C89 }, + { '+', 0, 0, N_("'+' flag"), N_("the '+' strfmon flag"), STD_C89 }, + { '(', 0, 0, N_("'(' flag"), N_("the '(' strfmon flag"), STD_C89 }, + { '!', 0, 0, N_("'!' flag"), N_("the '!' strfmon flag"), STD_C89 }, + { '-', 0, 0, N_("'-' flag"), N_("the '-' strfmon flag"), STD_C89 }, + { 'w', 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 }, + { '#', 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 }, + { 'p', 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 }, + { 'L', 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 }, + { 0, 0, 0, NULL, NULL, STD_C89 } +}; + +static const format_flag_pair strfmon_flag_pairs[] = +{ + { '+', '(', 0, 0 }, + { 0, 0, 0, 0 } +}; + + +static const format_char_info print_char_table[] = +{ + /* C89 conversion specifiers. */ + { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "-wp0 +'I", "i", NULL }, + { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL }, + { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0'I", "i", NULL }, + { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL }, + { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#I", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c", NULL }, + { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "", "W", NULL }, + /* C99 conversion specifiers. */ + { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL }, + { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL }, + /* X/Open conversion specifiers. */ + { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, + { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL }, + /* GNU conversion specifiers. */ + { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } +}; + +static const format_char_info asm_fprintf_char_table[] = +{ + /* C89 conversion specifiers. */ + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +", "i", NULL }, + { "oxX", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0", "i", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, + + /* asm_fprintf conversion specifiers. */ + { "O", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "R", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "I", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "L", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "U", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, + { "@", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } +}; + +static const format_char_info gcc_diag_char_table[] = +{ + /* C89 conversion specifiers. */ + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, + + /* Custom conversion specifiers. */ + + /* These will require a "tree" at runtime. */ + { "K", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + + { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } +}; + +static const format_char_info gcc_tdiag_char_table[] = +{ + /* C89 conversion specifiers. */ + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, + + /* Custom conversion specifiers. */ + + /* These will require a "tree" at runtime. */ + { "DFKTEV", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, + + { "v", 0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL }, + + { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } +}; + +static const format_char_info gcc_cdiag_char_table[] = +{ + /* C89 conversion specifiers. */ + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, + + /* Custom conversion specifiers. */ + + /* These will require a "tree" at runtime. */ + { "DEFKTV", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, + + { "v", 0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL }, + + { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } +}; + +static const format_char_info gcc_cxxdiag_char_table[] = +{ + /* C89 conversion specifiers. */ + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, + + /* Custom conversion specifiers. */ + + /* These will require a "tree" at runtime. */ + { "ADEFKTV",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL }, + + { "v", 0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL }, + + /* These accept either an 'int' or an 'enum tree_code' (which is handled as an 'int'.) */ + { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + + { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } +}; + +static const format_char_info gcc_gfc_char_table[] = +{ + /* C89 conversion specifiers. */ + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL }, + + /* gfc conversion specifiers. */ + + { "C", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + + /* This will require a "locus" at runtime. */ + { "L", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "R", NULL }, + + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } +}; + +static const format_char_info scan_char_table[] = +{ + /* C89 conversion specifiers. */ + { "di", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "*w'I", "W", NULL }, + { "u", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "*w'I", "W", NULL }, + { "oxX", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, + { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "*w'", "W", NULL }, + { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*mw", "cW", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "cW", NULL }, + { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "cW[", NULL }, + { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, + { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "", "W", NULL }, + /* C99 conversion specifiers. */ + { "F", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "*w'", "W", NULL }, + { "aA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, + /* X/Open conversion specifiers. */ + { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*mw", "W", NULL }, + { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "W", NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } +}; + +static const format_char_info time_char_table[] = +{ + /* C89 conversion specifiers. */ + { "ABZab", 0, STD_C89, NOLENGTHS, "^#", "", NULL }, + { "cx", 0, STD_C89, NOLENGTHS, "E", "3", NULL }, + { "HIMSUWdmw", 0, STD_C89, NOLENGTHS, "-_0Ow", "", NULL }, + { "j", 0, STD_C89, NOLENGTHS, "-_0Ow", "o", NULL }, + { "p", 0, STD_C89, NOLENGTHS, "#", "", NULL }, + { "X", 0, STD_C89, NOLENGTHS, "E", "", NULL }, + { "y", 0, STD_C89, NOLENGTHS, "EO-_0w", "4", NULL }, + { "Y", 0, STD_C89, NOLENGTHS, "-_0EOw", "o", NULL }, + { "%", 0, STD_C89, NOLENGTHS, "", "", NULL }, + /* C99 conversion specifiers. */ + { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o", NULL }, + { "D", 0, STD_C99, NOLENGTHS, "", "2", NULL }, + { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "", NULL }, + { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "", NULL }, + { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o", NULL }, + { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o", NULL }, + { "h", 0, STD_C99, NOLENGTHS, "^#", "", NULL }, + { "z", 0, STD_C99, NOLENGTHS, "O", "o", NULL }, + /* GNU conversion specifiers. */ + { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "", NULL }, + { "P", 0, STD_EXT, NOLENGTHS, "", "", NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } +}; + +static const format_char_info monetary_char_table[] = +{ + { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "", NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } +}; + +/* This must be in the same order as enum format_type. */ +static const format_kind_info format_types_orig[] = +{ + { "gnu_printf", printf_length_specs, print_char_table, " +#0-'I", NULL, + printf_flag_specs, printf_flag_pairs, + FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK, + 'w', 0, 'p', 0, 'L', 0, + &integer_type_node, &integer_type_node + }, + { "asm_fprintf", asm_fprintf_length_specs, asm_fprintf_char_table, " +#0-", NULL, + asm_fprintf_flag_specs, asm_fprintf_flag_pairs, + FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK, + 'w', 0, 'p', 0, 'L', 0, + NULL, NULL + }, + { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "q+#", NULL, + gcc_diag_flag_specs, gcc_diag_flag_pairs, + FMT_FLAG_ARG_CONVERT, + 0, 0, 'p', 0, 'L', 0, + NULL, &integer_type_node + }, + { "gcc_tdiag", gcc_tdiag_length_specs, gcc_tdiag_char_table, "q+#", NULL, + gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs, + FMT_FLAG_ARG_CONVERT, + 0, 0, 'p', 0, 'L', 0, + NULL, &integer_type_node + }, + { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "q+#", NULL, + gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs, + FMT_FLAG_ARG_CONVERT, + 0, 0, 'p', 0, 'L', 0, + NULL, &integer_type_node + }, + { "gcc_cxxdiag", gcc_cxxdiag_length_specs, gcc_cxxdiag_char_table, "q+#", NULL, + gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs, + FMT_FLAG_ARG_CONVERT, + 0, 0, 'p', 0, 'L', 0, + NULL, &integer_type_node + }, + { "gcc_gfc", gcc_gfc_length_specs, gcc_gfc_char_table, "", NULL, + NULL, gcc_gfc_flag_pairs, + FMT_FLAG_ARG_CONVERT, + 0, 0, 0, 0, 0, 0, + NULL, NULL + }, + { "gnu_scanf", scanf_length_specs, scan_char_table, "*'I", NULL, + scanf_flag_specs, scanf_flag_pairs, + FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK, + 'w', 0, 0, '*', 'L', 'm', + NULL, NULL + }, + { "gnu_strftime", NULL, time_char_table, "_-0^#", "EO", + strftime_flag_specs, strftime_flag_pairs, + FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0, + NULL, NULL + }, + { "gnu_strfmon", strfmon_length_specs, monetary_char_table, "=^+(!-", NULL, + strfmon_flag_specs, strfmon_flag_pairs, + FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0, + NULL, NULL + } +}; + +/* This layer of indirection allows GCC to reassign format_types with + new data if necessary, while still allowing the original data to be + const. */ +static const format_kind_info *format_types = format_types_orig; +/* We can modify this one. We also add target-specific format types + to the end of the array. */ +static format_kind_info *dynamic_format_types; + +static int n_format_types = ARRAY_SIZE (format_types_orig); + +/* Structure detailing the results of checking a format function call + where the format expression may be a conditional expression with + many leaves resulting from nested conditional expressions. */ +typedef struct +{ + /* Number of leaves of the format argument that could not be checked + as they were not string literals. */ + int number_non_literal; + /* Number of leaves of the format argument that were null pointers or + string literals, but had extra format arguments. */ + int number_extra_args; + /* Number of leaves of the format argument that were null pointers or + string literals, but had extra format arguments and used $ operand + numbers. */ + int number_dollar_extra_args; + /* Number of leaves of the format argument that were wide string + literals. */ + int number_wide; + /* Number of leaves of the format argument that were empty strings. */ + int number_empty; + /* Number of leaves of the format argument that were unterminated + strings. */ + int number_unterminated; + /* Number of leaves of the format argument that were not counted above. */ + int number_other; +} format_check_results; + +typedef struct +{ + format_check_results *res; + function_format_info *info; + tree params; +} format_check_context; + +static void check_format_info (function_format_info *, tree); +static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT); +static void check_format_info_main (format_check_results *, + function_format_info *, + const char *, int, tree, + unsigned HOST_WIDE_INT, alloc_pool); + +static void init_dollar_format_checking (int, tree); +static int maybe_read_dollar_number (const char **, int, + tree, tree *, const format_kind_info *); +static bool avoid_dollar_number (const char *); +static void finish_dollar_format_checking (format_check_results *, int); + +static const format_flag_spec *get_flag_spec (const format_flag_spec *, + int, const char *); + +static void check_format_types (format_wanted_type *, const char *, int); +static void format_type_warning (const char *, const char *, int, tree, + int, const char *, tree, int); + +/* Decode a format type from a string, returning the type, or + format_type_error if not valid, in which case the caller should print an + error message. */ +static int +decode_format_type (const char *s) +{ + int i; + int slen; + + s = convert_format_name_to_system_name (s); + slen = strlen (s); + for (i = 0; i < n_format_types; i++) + { + int alen; + if (!strcmp (s, format_types[i].name)) + return i; + alen = strlen (format_types[i].name); + if (slen == alen + 4 && s[0] == '_' && s[1] == '_' + && s[slen - 1] == '_' && s[slen - 2] == '_' + && !strncmp (s + 2, format_types[i].name, alen)) + return i; + } + return format_type_error; +} + + +/* Check the argument list of a call to printf, scanf, etc. + ATTRS are the attributes on the function type. There are NARGS argument + values in the array ARGARRAY. + Also, if -Wmissing-format-attribute, + warn for calls to vprintf or vscanf in functions with no such format + attribute themselves. */ + +void +check_function_format (tree attrs, int nargs, tree *argarray) +{ + tree a; + + /* See if this function has any format attributes. */ + for (a = attrs; a; a = TREE_CHAIN (a)) + { + if (is_attribute_p ("format", TREE_PURPOSE (a))) + { + /* Yup; check it. */ + function_format_info info; + decode_format_attr (TREE_VALUE (a), &info, 1); + if (warn_format) + { + /* FIXME: Rewrite all the internal functions in this file + to use the ARGARRAY directly instead of constructing this + temporary list. */ + tree params = NULL_TREE; + int i; + for (i = nargs - 1; i >= 0; i--) + params = tree_cons (NULL_TREE, argarray[i], params); + check_format_info (&info, params); + } + if (warn_missing_format_attribute && info.first_arg_num == 0 + && (format_types[info.format_type].flags + & (int) FMT_FLAG_ARG_CONVERT)) + { + tree c; + for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); + c; + c = TREE_CHAIN (c)) + if (is_attribute_p ("format", TREE_PURPOSE (c)) + && (decode_format_type (IDENTIFIER_POINTER + (TREE_VALUE (TREE_VALUE (c)))) + == info.format_type)) + break; + if (c == NULL_TREE) + { + /* Check if the current function has a parameter to which + the format attribute could be attached; if not, it + can't be a candidate for a format attribute, despite + the vprintf-like or vscanf-like call. */ + tree args; + for (args = DECL_ARGUMENTS (current_function_decl); + args != 0; + args = TREE_CHAIN (args)) + { + if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE + && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args))) + == char_type_node)) + break; + } + if (args != 0) + warning (OPT_Wmissing_format_attribute, "function might " + "be possible candidate for %qs format attribute", + format_types[info.format_type].name); + } + } + } + } +} + + +/* Variables used by the checking of $ operand number formats. */ +static char *dollar_arguments_used = NULL; +static char *dollar_arguments_pointer_p = NULL; +static int dollar_arguments_alloc = 0; +static int dollar_arguments_count; +static int dollar_first_arg_num; +static int dollar_max_arg_used; +static int dollar_format_warned; + +/* Initialize the checking for a format string that may contain $ + parameter number specifications; we will need to keep track of whether + each parameter has been used. FIRST_ARG_NUM is the number of the first + argument that is a parameter to the format, or 0 for a vprintf-style + function; PARAMS is the list of arguments starting at this argument. */ + +static void +init_dollar_format_checking (int first_arg_num, tree params) +{ + tree oparams = params; + + dollar_first_arg_num = first_arg_num; + dollar_arguments_count = 0; + dollar_max_arg_used = 0; + dollar_format_warned = 0; + if (first_arg_num > 0) + { + while (params) + { + dollar_arguments_count++; + params = TREE_CHAIN (params); + } + } + if (dollar_arguments_alloc < dollar_arguments_count) + { + if (dollar_arguments_used) + free (dollar_arguments_used); + if (dollar_arguments_pointer_p) + free (dollar_arguments_pointer_p); + dollar_arguments_alloc = dollar_arguments_count; + dollar_arguments_used = XNEWVEC (char, dollar_arguments_alloc); + dollar_arguments_pointer_p = XNEWVEC (char, dollar_arguments_alloc); + } + if (dollar_arguments_alloc) + { + memset (dollar_arguments_used, 0, dollar_arguments_alloc); + if (first_arg_num > 0) + { + int i = 0; + params = oparams; + while (params) + { + dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params))) + == POINTER_TYPE); + params = TREE_CHAIN (params); + i++; + } + } + } +} + + +/* Look for a decimal number followed by a $ in *FORMAT. If DOLLAR_NEEDED + is set, it is an error if one is not found; otherwise, it is OK. If + such a number is found, check whether it is within range and mark that + numbered operand as being used for later checking. Returns the operand + number if found and within range, zero if no such number was found and + this is OK, or -1 on error. PARAMS points to the first operand of the + format; PARAM_PTR is made to point to the parameter referred to. If + a $ format is found, *FORMAT is updated to point just after it. */ + +static int +maybe_read_dollar_number (const char **format, + int dollar_needed, tree params, tree *param_ptr, + const format_kind_info *fki) +{ + int argnum; + int overflow_flag; + const char *fcp = *format; + if (!ISDIGIT (*fcp)) + { + if (dollar_needed) + { + warning (OPT_Wformat, "missing $ operand number in format"); + return -1; + } + else + return 0; + } + argnum = 0; + overflow_flag = 0; + while (ISDIGIT (*fcp)) + { + int nargnum; + nargnum = 10 * argnum + (*fcp - '0'); + if (nargnum < 0 || nargnum / 10 != argnum) + overflow_flag = 1; + argnum = nargnum; + fcp++; + } + if (*fcp != '$') + { + if (dollar_needed) + { + warning (OPT_Wformat, "missing $ operand number in format"); + return -1; + } + else + return 0; + } + *format = fcp + 1; + if (pedantic && !dollar_format_warned) + { + warning (OPT_Wformat, "%s does not support %%n$ operand number formats", + C_STD_NAME (STD_EXT)); + dollar_format_warned = 1; + } + if (overflow_flag || argnum == 0 + || (dollar_first_arg_num && argnum > dollar_arguments_count)) + { + warning (OPT_Wformat, "operand number out of range in format"); + return -1; + } + if (argnum > dollar_max_arg_used) + dollar_max_arg_used = argnum; + /* For vprintf-style functions we may need to allocate more memory to + track which arguments are used. */ + while (dollar_arguments_alloc < dollar_max_arg_used) + { + int nalloc; + nalloc = 2 * dollar_arguments_alloc + 16; + dollar_arguments_used = XRESIZEVEC (char, dollar_arguments_used, + nalloc); + dollar_arguments_pointer_p = XRESIZEVEC (char, dollar_arguments_pointer_p, + nalloc); + memset (dollar_arguments_used + dollar_arguments_alloc, 0, + nalloc - dollar_arguments_alloc); + dollar_arguments_alloc = nalloc; + } + if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE) + && dollar_arguments_used[argnum - 1] == 1) + { + dollar_arguments_used[argnum - 1] = 2; + warning (OPT_Wformat, "format argument %d used more than once in %s format", + argnum, fki->name); + } + else + dollar_arguments_used[argnum - 1] = 1; + if (dollar_first_arg_num) + { + int i; + *param_ptr = params; + for (i = 1; i < argnum && *param_ptr != 0; i++) + *param_ptr = TREE_CHAIN (*param_ptr); + + /* This case shouldn't be caught here. */ + gcc_assert (*param_ptr); + } + else + *param_ptr = 0; + return argnum; +} + +/* Ensure that FORMAT does not start with a decimal number followed by + a $; give a diagnostic and return true if it does, false otherwise. */ + +static bool +avoid_dollar_number (const char *format) +{ + if (!ISDIGIT (*format)) + return false; + while (ISDIGIT (*format)) + format++; + if (*format == '$') + { + warning (OPT_Wformat, "$ operand number used after format without operand number"); + return true; + } + return false; +} + + +/* Finish the checking for a format string that used $ operand number formats + instead of non-$ formats. We check for unused operands before used ones + (a serious error, since the implementation of the format function + can't know what types to pass to va_arg to find the later arguments). + and for unused operands at the end of the format (if we know how many + arguments the format had, so not for vprintf). If there were operand + numbers out of range on a non-vprintf-style format, we won't have reached + here. If POINTER_GAP_OK, unused arguments are OK if all arguments are + pointers. */ + +static void +finish_dollar_format_checking (format_check_results *res, int pointer_gap_ok) +{ + int i; + bool found_pointer_gap = false; + for (i = 0; i < dollar_max_arg_used; i++) + { + if (!dollar_arguments_used[i]) + { + if (pointer_gap_ok && (dollar_first_arg_num == 0 + || dollar_arguments_pointer_p[i])) + found_pointer_gap = true; + else + warning (OPT_Wformat, + "format argument %d unused before used argument %d in $-style format", + i + 1, dollar_max_arg_used); + } + } + if (found_pointer_gap + || (dollar_first_arg_num + && dollar_max_arg_used < dollar_arguments_count)) + { + res->number_other--; + res->number_dollar_extra_args++; + } +} + + +/* Retrieve the specification for a format flag. SPEC contains the + specifications for format flags for the applicable kind of format. + FLAG is the flag in question. If PREDICATES is NULL, the basic + spec for that flag must be retrieved and must exist. If + PREDICATES is not NULL, it is a string listing possible predicates + for the spec entry; if an entry predicated on any of these is + found, it is returned, otherwise NULL is returned. */ + +static const format_flag_spec * +get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates) +{ + int i; + for (i = 0; spec[i].flag_char != 0; i++) + { + if (spec[i].flag_char != flag) + continue; + if (predicates != NULL) + { + if (spec[i].predicate != 0 + && strchr (predicates, spec[i].predicate) != 0) + return &spec[i]; + } + else if (spec[i].predicate == 0) + return &spec[i]; + } + gcc_assert (predicates); + return NULL; +} + + +/* Check the argument list of a call to printf, scanf, etc. + INFO points to the function_format_info structure. + PARAMS is the list of argument values. */ + +static void +check_format_info (function_format_info *info, tree params) +{ + format_check_context format_ctx; + unsigned HOST_WIDE_INT arg_num; + tree format_tree; + format_check_results res; + /* Skip to format argument. If the argument isn't available, there's + no work for us to do; prototype checking will catch the problem. */ + for (arg_num = 1; ; ++arg_num) + { + if (params == 0) + return; + if (arg_num == info->format_num) + break; + params = TREE_CHAIN (params); + } + format_tree = TREE_VALUE (params); + params = TREE_CHAIN (params); + if (format_tree == 0) + return; + + res.number_non_literal = 0; + res.number_extra_args = 0; + res.number_dollar_extra_args = 0; + res.number_wide = 0; + res.number_empty = 0; + res.number_unterminated = 0; + res.number_other = 0; + + format_ctx.res = &res; + format_ctx.info = info; + format_ctx.params = params; + + check_function_arguments_recurse (check_format_arg, &format_ctx, + format_tree, arg_num); + + if (res.number_non_literal > 0) + { + /* Functions taking a va_list normally pass a non-literal format + string. These functions typically are declared with + first_arg_num == 0, so avoid warning in those cases. */ + if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT)) + { + /* For strftime-like formats, warn for not checking the format + string; but there are no arguments to check. */ + warning (OPT_Wformat_nonliteral, + "format not a string literal, format string not checked"); + } + else if (info->first_arg_num != 0) + { + /* If there are no arguments for the format at all, we may have + printf (foo) which is likely to be a security hole. */ + while (arg_num + 1 < info->first_arg_num) + { + if (params == 0) + break; + params = TREE_CHAIN (params); + ++arg_num; + } + if (params == 0 && warn_format_security) + warning (OPT_Wformat_security, + "format not a string literal and no format arguments"); + else if (params == 0 && warn_format_nonliteral) + warning (OPT_Wformat_nonliteral, + "format not a string literal and no format arguments"); + else + warning (OPT_Wformat_nonliteral, + "format not a string literal, argument types not checked"); + } + } + + /* If there were extra arguments to the format, normally warn. However, + the standard does say extra arguments are ignored, so in the specific + case where we have multiple leaves (conditional expressions or + ngettext) allow extra arguments if at least one leaf didn't have extra + arguments, but was otherwise OK (either non-literal or checked OK). + If the format is an empty string, this should be counted similarly to the + case of extra format arguments. */ + if (res.number_extra_args > 0 && res.number_non_literal == 0 + && res.number_other == 0) + warning (OPT_Wformat_extra_args, "too many arguments for format"); + if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0 + && res.number_other == 0) + warning (OPT_Wformat_extra_args, "unused arguments in $-style format"); + if (res.number_empty > 0 && res.number_non_literal == 0 + && res.number_other == 0) + warning (OPT_Wformat_zero_length, "zero-length %s format string", + format_types[info->format_type].name); + + if (res.number_wide > 0) + warning (OPT_Wformat, "format is a wide character string"); + + if (res.number_unterminated > 0) + warning (OPT_Wformat, "unterminated format string"); +} + +/* Callback from check_function_arguments_recurse to check a + format string. FORMAT_TREE is the format parameter. ARG_NUM + is the number of the format argument. CTX points to a + format_check_context. */ + +static void +check_format_arg (void *ctx, tree format_tree, + unsigned HOST_WIDE_INT arg_num) +{ + format_check_context *format_ctx = (format_check_context *) ctx; + format_check_results *res = format_ctx->res; + function_format_info *info = format_ctx->info; + tree params = format_ctx->params; + + int format_length; + HOST_WIDE_INT offset; + const char *format_chars; + tree array_size = 0; + tree array_init; + alloc_pool fwt_pool; + + if (integer_zerop (format_tree)) + { + /* Skip to first argument to check, so we can see if this format + has any arguments (it shouldn't). */ + while (arg_num + 1 < info->first_arg_num) + { + if (params == 0) + return; + params = TREE_CHAIN (params); + ++arg_num; + } + + if (params == 0) + res->number_other++; + else + res->number_extra_args++; + + return; + } + + offset = 0; + if (TREE_CODE (format_tree) == POINTER_PLUS_EXPR) + { + tree arg0, arg1; + + arg0 = TREE_OPERAND (format_tree, 0); + arg1 = TREE_OPERAND (format_tree, 1); + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + if (TREE_CODE (arg1) == INTEGER_CST) + format_tree = arg0; + else + { + res->number_non_literal++; + return; + } + if (!host_integerp (arg1, 0) + || (offset = tree_low_cst (arg1, 0)) < 0) + { + res->number_non_literal++; + return; + } + } + if (TREE_CODE (format_tree) != ADDR_EXPR) + { + res->number_non_literal++; + return; + } + format_tree = TREE_OPERAND (format_tree, 0); + if (TREE_CODE (format_tree) == ARRAY_REF + && host_integerp (TREE_OPERAND (format_tree, 1), 0) + && (offset += tree_low_cst (TREE_OPERAND (format_tree, 1), 0)) >= 0) + format_tree = TREE_OPERAND (format_tree, 0); + if (TREE_CODE (format_tree) == VAR_DECL + && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE + && (array_init = decl_constant_value (format_tree)) != format_tree + && TREE_CODE (array_init) == STRING_CST) + { + /* Extract the string constant initializer. Note that this may include + a trailing NUL character that is not in the array (e.g. + const char a[3] = "foo";). */ + array_size = DECL_SIZE_UNIT (format_tree); + format_tree = array_init; + } + if (TREE_CODE (format_tree) != STRING_CST) + { + res->number_non_literal++; + return; + } + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree))) != char_type_node) + { + res->number_wide++; + return; + } + format_chars = TREE_STRING_POINTER (format_tree); + format_length = TREE_STRING_LENGTH (format_tree); + if (array_size != 0) + { + /* Variable length arrays can't be initialized. */ + gcc_assert (TREE_CODE (array_size) == INTEGER_CST); + + if (host_integerp (array_size, 0)) + { + HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size); + if (array_size_value > 0 + && array_size_value == (int) array_size_value + && format_length > array_size_value) + format_length = array_size_value; + } + } + if (offset) + { + if (offset >= format_length) + { + res->number_non_literal++; + return; + } + format_chars += offset; + format_length -= offset; + } + if (format_length < 1 || format_chars[--format_length] != 0) + { + res->number_unterminated++; + return; + } + if (format_length == 0) + { + res->number_empty++; + return; + } + + /* Skip to first argument to check. */ + while (arg_num + 1 < info->first_arg_num) + { + if (params == 0) + return; + params = TREE_CHAIN (params); + ++arg_num; + } + /* Provisionally increment res->number_other; check_format_info_main + will decrement it if it finds there are extra arguments, but this way + need not adjust it for every return. */ + res->number_other++; + fwt_pool = create_alloc_pool ("format_wanted_type pool", + sizeof (format_wanted_type), 10); + check_format_info_main (res, info, format_chars, format_length, + params, arg_num, fwt_pool); + free_alloc_pool (fwt_pool); +} + + +/* Do the main part of checking a call to a format function. FORMAT_CHARS + is the NUL-terminated format string (which at this point may contain + internal NUL characters); FORMAT_LENGTH is its length (excluding the + terminating NUL character). ARG_NUM is one less than the number of + the first format argument to check; PARAMS points to that format + argument in the list of arguments. */ + +static void +check_format_info_main (format_check_results *res, + function_format_info *info, const char *format_chars, + int format_length, tree params, + unsigned HOST_WIDE_INT arg_num, alloc_pool fwt_pool) +{ + const char *orig_format_chars = format_chars; + tree first_fillin_param = params; + + const format_kind_info *fki = &format_types[info->format_type]; + const format_flag_spec *flag_specs = fki->flag_specs; + const format_flag_pair *bad_flag_pairs = fki->bad_flag_pairs; + + /* -1 if no conversions taking an operand have been found; 0 if one has + and it didn't use $; 1 if $ formats are in use. */ + int has_operand_number = -1; + + init_dollar_format_checking (info->first_arg_num, first_fillin_param); + + while (1) + { + int i; + int suppressed = FALSE; + const char *length_chars = NULL; + enum format_lengths length_chars_val = FMT_LEN_none; + enum format_std_version length_chars_std = STD_C89; + int format_char; + tree cur_param; + tree wanted_type; + int main_arg_num = 0; + tree main_arg_params = 0; + enum format_std_version wanted_type_std; + const char *wanted_type_name; + format_wanted_type width_wanted_type; + format_wanted_type precision_wanted_type; + format_wanted_type main_wanted_type; + format_wanted_type *first_wanted_type = NULL; + format_wanted_type *last_wanted_type = NULL; + const format_length_info *fli = NULL; + const format_char_info *fci = NULL; + char flag_chars[256]; + int alloc_flag = 0; + int scalar_identity_flag = 0; + const char *format_start = format_chars; + if (*format_chars == 0) + { + if (format_chars - orig_format_chars != format_length) + warning (OPT_Wformat_contains_nul, "embedded %<\\0%> in format"); + if (info->first_arg_num != 0 && params != 0 + && has_operand_number <= 0) + { + res->number_other--; + res->number_extra_args++; + } + if (has_operand_number > 0) + finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK); + return; + } + if (*format_chars++ != '%') + continue; + if (*format_chars == 0) + { + warning (OPT_Wformat, "spurious trailing %<%%%> in format"); + continue; + } + if (*format_chars == '%') + { + ++format_chars; + continue; + } + flag_chars[0] = 0; + + if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0) + { + /* Possibly read a $ operand number at the start of the format. + If one was previously used, one is required here. If one + is not used here, we can't immediately conclude this is a + format without them, since it could be printf %m or scanf %*. */ + int opnum; + opnum = maybe_read_dollar_number (&format_chars, 0, + first_fillin_param, + &main_arg_params, fki); + if (opnum == -1) + return; + else if (opnum > 0) + { + has_operand_number = 1; + main_arg_num = opnum + info->first_arg_num - 1; + } + } + else if (fki->flags & FMT_FLAG_USE_DOLLAR) + { + if (avoid_dollar_number (format_chars)) + return; + } + + /* Read any format flags, but do not yet validate them beyond removing + duplicates, since in general validation depends on the rest of + the format. */ + while (*format_chars != 0 + && strchr (fki->flag_chars, *format_chars) != 0) + { + const format_flag_spec *s = get_flag_spec (flag_specs, + *format_chars, NULL); + if (strchr (flag_chars, *format_chars) != 0) + { + warning (OPT_Wformat, "repeated %s in format", _(s->name)); + } + else + { + i = strlen (flag_chars); + flag_chars[i++] = *format_chars; + flag_chars[i] = 0; + } + if (s->skip_next_char) + { + ++format_chars; + if (*format_chars == 0) + { + warning (OPT_Wformat, "missing fill character at end of strfmon format"); + return; + } + } + ++format_chars; + } + + /* Read any format width, possibly * or *m$. */ + if (fki->width_char != 0) + { + if (fki->width_type != NULL && *format_chars == '*') + { + i = strlen (flag_chars); + flag_chars[i++] = fki->width_char; + flag_chars[i] = 0; + /* "...a field width...may be indicated by an asterisk. + In this case, an int argument supplies the field width..." */ + ++format_chars; + if (has_operand_number != 0) + { + int opnum; + opnum = maybe_read_dollar_number (&format_chars, + has_operand_number == 1, + first_fillin_param, + ¶ms, fki); + if (opnum == -1) + return; + else if (opnum > 0) + { + has_operand_number = 1; + arg_num = opnum + info->first_arg_num - 1; + } + else + has_operand_number = 0; + } + else + { + if (avoid_dollar_number (format_chars)) + return; + } + if (info->first_arg_num != 0) + { + if (params == 0) + { + warning (OPT_Wformat, "too few arguments for format"); + return; + } + cur_param = TREE_VALUE (params); + if (has_operand_number <= 0) + { + params = TREE_CHAIN (params); + ++arg_num; + } + width_wanted_type.wanted_type = *fki->width_type; + width_wanted_type.wanted_type_name = NULL; + width_wanted_type.pointer_count = 0; + width_wanted_type.char_lenient_flag = 0; + width_wanted_type.scalar_identity_flag = 0; + width_wanted_type.writing_in_flag = 0; + width_wanted_type.reading_from_flag = 0; + width_wanted_type.name = _("field width"); + width_wanted_type.param = cur_param; + width_wanted_type.arg_num = arg_num; + width_wanted_type.next = NULL; + if (last_wanted_type != 0) + last_wanted_type->next = &width_wanted_type; + if (first_wanted_type == 0) + first_wanted_type = &width_wanted_type; + last_wanted_type = &width_wanted_type; + } + } + else + { + /* Possibly read a numeric width. If the width is zero, + we complain if appropriate. */ + int non_zero_width_char = FALSE; + int found_width = FALSE; + while (ISDIGIT (*format_chars)) + { + found_width = TRUE; + if (*format_chars != '0') + non_zero_width_char = TRUE; + ++format_chars; + } + if (found_width && !non_zero_width_char && + (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD)) + warning (OPT_Wformat, "zero width in %s format", fki->name); + if (found_width) + { + i = strlen (flag_chars); + flag_chars[i++] = fki->width_char; + flag_chars[i] = 0; + } + } + } + + /* Read any format left precision (must be a number, not *). */ + if (fki->left_precision_char != 0 && *format_chars == '#') + { + ++format_chars; + i = strlen (flag_chars); + flag_chars[i++] = fki->left_precision_char; + flag_chars[i] = 0; + if (!ISDIGIT (*format_chars)) + warning (OPT_Wformat, "empty left precision in %s format", fki->name); + while (ISDIGIT (*format_chars)) + ++format_chars; + } + + /* Read any format precision, possibly * or *m$. */ + if (fki->precision_char != 0 && *format_chars == '.') + { + ++format_chars; + i = strlen (flag_chars); + flag_chars[i++] = fki->precision_char; + flag_chars[i] = 0; + if (fki->precision_type != NULL && *format_chars == '*') + { + /* "...a...precision...may be indicated by an asterisk. + In this case, an int argument supplies the...precision." */ + ++format_chars; + if (has_operand_number != 0) + { + int opnum; + opnum = maybe_read_dollar_number (&format_chars, + has_operand_number == 1, + first_fillin_param, + ¶ms, fki); + if (opnum == -1) + return; + else if (opnum > 0) + { + has_operand_number = 1; + arg_num = opnum + info->first_arg_num - 1; + } + else + has_operand_number = 0; + } + else + { + if (avoid_dollar_number (format_chars)) + return; + } + if (info->first_arg_num != 0) + { + if (params == 0) + { + warning (OPT_Wformat, "too few arguments for format"); + return; + } + cur_param = TREE_VALUE (params); + if (has_operand_number <= 0) + { + params = TREE_CHAIN (params); + ++arg_num; + } + precision_wanted_type.wanted_type = *fki->precision_type; + precision_wanted_type.wanted_type_name = NULL; + precision_wanted_type.pointer_count = 0; + precision_wanted_type.char_lenient_flag = 0; + precision_wanted_type.scalar_identity_flag = 0; + precision_wanted_type.writing_in_flag = 0; + precision_wanted_type.reading_from_flag = 0; + precision_wanted_type.name = _("field precision"); + precision_wanted_type.param = cur_param; + precision_wanted_type.arg_num = arg_num; + precision_wanted_type.next = NULL; + if (last_wanted_type != 0) + last_wanted_type->next = &precision_wanted_type; + if (first_wanted_type == 0) + first_wanted_type = &precision_wanted_type; + last_wanted_type = &precision_wanted_type; + } + } + else + { + if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK) + && !ISDIGIT (*format_chars)) + warning (OPT_Wformat, "empty precision in %s format", fki->name); + while (ISDIGIT (*format_chars)) + ++format_chars; + } + } + + if (fki->alloc_char && fki->alloc_char == *format_chars) + { + i = strlen (flag_chars); + flag_chars[i++] = fki->alloc_char; + flag_chars[i] = 0; + format_chars++; + } + + /* Handle the scanf allocation kludge. */ + if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) + { + if (*format_chars == 'a' && !flag_isoc99) + { + if (format_chars[1] == 's' || format_chars[1] == 'S' + || format_chars[1] == '[') + { + /* 'a' is used as a flag. */ + i = strlen (flag_chars); + flag_chars[i++] = 'a'; + flag_chars[i] = 0; + format_chars++; + } + } + } + + /* Read any length modifier, if this kind of format has them. */ + fli = fki->length_char_specs; + length_chars = NULL; + length_chars_val = FMT_LEN_none; + length_chars_std = STD_C89; + scalar_identity_flag = 0; + if (fli) + { + while (fli->name != 0 + && strncmp (fli->name, format_chars, strlen (fli->name))) + fli++; + if (fli->name != 0) + { + format_chars += strlen (fli->name); + if (fli->double_name != 0 && fli->name[0] == *format_chars) + { + format_chars++; + length_chars = fli->double_name; + length_chars_val = fli->double_index; + length_chars_std = fli->double_std; + } + else + { + length_chars = fli->name; + length_chars_val = fli->index; + length_chars_std = fli->std; + scalar_identity_flag = fli->scalar_identity_flag; + } + i = strlen (flag_chars); + flag_chars[i++] = fki->length_code_char; + flag_chars[i] = 0; + } + if (pedantic) + { + /* Warn if the length modifier is non-standard. */ + if (ADJ_STD (length_chars_std) > C_STD_VER) + warning (OPT_Wformat, + "%s does not support the %qs %s length modifier", + C_STD_NAME (length_chars_std), length_chars, + fki->name); + } + } + + /* Read any modifier (strftime E/O). */ + if (fki->modifier_chars != NULL) + { + while (*format_chars != 0 + && strchr (fki->modifier_chars, *format_chars) != 0) + { + if (strchr (flag_chars, *format_chars) != 0) + { + const format_flag_spec *s = get_flag_spec (flag_specs, + *format_chars, NULL); + warning (OPT_Wformat, "repeated %s in format", _(s->name)); + } + else + { + i = strlen (flag_chars); + flag_chars[i++] = *format_chars; + flag_chars[i] = 0; + } + ++format_chars; + } + } + + format_char = *format_chars; + if (format_char == 0 + || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK) + && format_char == '%')) + { + warning (OPT_Wformat, "conversion lacks type at end of format"); + continue; + } + format_chars++; + fci = fki->conversion_specs; + while (fci->format_chars != 0 + && strchr (fci->format_chars, format_char) == 0) + ++fci; + if (fci->format_chars == 0) + { + if (ISGRAPH (format_char)) + warning (OPT_Wformat, "unknown conversion type character %qc in format", + format_char); + else + warning (OPT_Wformat, "unknown conversion type character 0x%x in format", + format_char); + continue; + } + if (pedantic) + { + if (ADJ_STD (fci->std) > C_STD_VER) + warning (OPT_Wformat, "%s does not support the %<%%%c%> %s format", + C_STD_NAME (fci->std), format_char, fki->name); + } + + /* Validate the individual flags used, removing any that are invalid. */ + { + int d = 0; + for (i = 0; flag_chars[i] != 0; i++) + { + const format_flag_spec *s = get_flag_spec (flag_specs, + flag_chars[i], NULL); + flag_chars[i - d] = flag_chars[i]; + if (flag_chars[i] == fki->length_code_char) + continue; + if (strchr (fci->flag_chars, flag_chars[i]) == 0) + { + warning (OPT_Wformat, "%s used with %<%%%c%> %s format", + _(s->name), format_char, fki->name); + d++; + continue; + } + if (pedantic) + { + const format_flag_spec *t; + if (ADJ_STD (s->std) > C_STD_VER) + warning (OPT_Wformat, "%s does not support %s", + C_STD_NAME (s->std), _(s->long_name)); + t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2); + if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std)) + { + const char *long_name = (t->long_name != NULL + ? t->long_name + : s->long_name); + if (ADJ_STD (t->std) > C_STD_VER) + warning (OPT_Wformat, + "%s does not support %s with the %<%%%c%> %s format", + C_STD_NAME (t->std), _(long_name), + format_char, fki->name); + } + } + } + flag_chars[i - d] = 0; + } + + if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) + && strchr (flag_chars, 'a') != 0) + alloc_flag = 1; + if (fki->alloc_char && strchr (flag_chars, fki->alloc_char) != 0) + alloc_flag = 1; + + if (fki->suppression_char + && strchr (flag_chars, fki->suppression_char) != 0) + suppressed = 1; + + /* Validate the pairs of flags used. */ + for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++) + { + const format_flag_spec *s, *t; + if (strchr (flag_chars, bad_flag_pairs[i].flag_char1) == 0) + continue; + if (strchr (flag_chars, bad_flag_pairs[i].flag_char2) == 0) + continue; + if (bad_flag_pairs[i].predicate != 0 + && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0) + continue; + s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL); + t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL); + if (bad_flag_pairs[i].ignored) + { + if (bad_flag_pairs[i].predicate != 0) + warning (OPT_Wformat, + "%s ignored with %s and %<%%%c%> %s format", + _(s->name), _(t->name), format_char, + fki->name); + else + warning (OPT_Wformat, "%s ignored with %s in %s format", + _(s->name), _(t->name), fki->name); + } + else + { + if (bad_flag_pairs[i].predicate != 0) + warning (OPT_Wformat, + "use of %s and %s together with %<%%%c%> %s format", + _(s->name), _(t->name), format_char, + fki->name); + else + warning (OPT_Wformat, "use of %s and %s together in %s format", + _(s->name), _(t->name), fki->name); + } + } + + /* Give Y2K warnings. */ + if (warn_format_y2k) + { + int y2k_level = 0; + if (strchr (fci->flags2, '4') != 0) + if (strchr (flag_chars, 'E') != 0) + y2k_level = 3; + else + y2k_level = 2; + else if (strchr (fci->flags2, '3') != 0) + y2k_level = 3; + else if (strchr (fci->flags2, '2') != 0) + y2k_level = 2; + if (y2k_level == 3) + warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of " + "year in some locales", format_char); + else if (y2k_level == 2) + warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of " + "year", format_char); + } + + if (strchr (fci->flags2, '[') != 0) + { + /* Skip over scan set, in case it happens to have '%' in it. */ + if (*format_chars == '^') + ++format_chars; + /* Find closing bracket; if one is hit immediately, then + it's part of the scan set rather than a terminator. */ + if (*format_chars == ']') + ++format_chars; + while (*format_chars && *format_chars != ']') + ++format_chars; + if (*format_chars != ']') + /* The end of the format string was reached. */ + warning (OPT_Wformat, "no closing %<]%> for %<%%[%> format"); + } + + wanted_type = 0; + wanted_type_name = 0; + if (fki->flags & (int) FMT_FLAG_ARG_CONVERT) + { + wanted_type = (fci->types[length_chars_val].type + ? *fci->types[length_chars_val].type : 0); + wanted_type_name = fci->types[length_chars_val].name; + wanted_type_std = fci->types[length_chars_val].std; + if (wanted_type == 0) + { + warning (OPT_Wformat, + "use of %qs length modifier with %qc type character", + length_chars, format_char); + /* Heuristic: skip one argument when an invalid length/type + combination is encountered. */ + arg_num++; + if (params == 0) + { + warning (OPT_Wformat, "too few arguments for format"); + return; + } + params = TREE_CHAIN (params); + continue; + } + else if (pedantic + /* Warn if non-standard, provided it is more non-standard + than the length and type characters that may already + have been warned for. */ + && ADJ_STD (wanted_type_std) > ADJ_STD (length_chars_std) + && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std)) + { + if (ADJ_STD (wanted_type_std) > C_STD_VER) + warning (OPT_Wformat, + "%s does not support the %<%%%s%c%> %s format", + C_STD_NAME (wanted_type_std), length_chars, + format_char, fki->name); + } + } + + main_wanted_type.next = NULL; + + /* Finally. . .check type of argument against desired type! */ + if (info->first_arg_num == 0) + continue; + if ((fci->pointer_count == 0 && wanted_type == void_type_node) + || suppressed) + { + if (main_arg_num != 0) + { + if (suppressed) + warning (OPT_Wformat, "operand number specified with " + "suppressed assignment"); + else + warning (OPT_Wformat, "operand number specified for format " + "taking no argument"); + } + } + else + { + format_wanted_type *wanted_type_ptr; + + if (main_arg_num != 0) + { + arg_num = main_arg_num; + params = main_arg_params; + } + else + { + ++arg_num; + if (has_operand_number > 0) + { + warning (OPT_Wformat, "missing $ operand number in format"); + return; + } + else + has_operand_number = 0; + } + + wanted_type_ptr = &main_wanted_type; + while (fci) + { + if (params == 0) + { + warning (OPT_Wformat, "too few arguments for format"); + return; + } + + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + + wanted_type_ptr->wanted_type = wanted_type; + wanted_type_ptr->wanted_type_name = wanted_type_name; + wanted_type_ptr->pointer_count = fci->pointer_count + alloc_flag; + wanted_type_ptr->char_lenient_flag = 0; + if (strchr (fci->flags2, 'c') != 0) + wanted_type_ptr->char_lenient_flag = 1; + wanted_type_ptr->scalar_identity_flag = 0; + if (scalar_identity_flag) + wanted_type_ptr->scalar_identity_flag = 1; + wanted_type_ptr->writing_in_flag = 0; + wanted_type_ptr->reading_from_flag = 0; + if (alloc_flag) + wanted_type_ptr->writing_in_flag = 1; + else + { + if (strchr (fci->flags2, 'W') != 0) + wanted_type_ptr->writing_in_flag = 1; + if (strchr (fci->flags2, 'R') != 0) + wanted_type_ptr->reading_from_flag = 1; + } + wanted_type_ptr->name = NULL; + wanted_type_ptr->param = cur_param; + wanted_type_ptr->arg_num = arg_num; + wanted_type_ptr->next = NULL; + if (last_wanted_type != 0) + last_wanted_type->next = wanted_type_ptr; + if (first_wanted_type == 0) + first_wanted_type = wanted_type_ptr; + last_wanted_type = wanted_type_ptr; + + fci = fci->chain; + if (fci) + { + wanted_type_ptr = (format_wanted_type *) + pool_alloc (fwt_pool); + arg_num++; + wanted_type = *fci->types[length_chars_val].type; + wanted_type_name = fci->types[length_chars_val].name; + } + } + } + + if (first_wanted_type != 0) + check_format_types (first_wanted_type, format_start, + format_chars - format_start); + } +} + + +/* Check the argument types from a single format conversion (possibly + including width and precision arguments). */ +static void +check_format_types (format_wanted_type *types, const char *format_start, + int format_length) +{ + for (; types != 0; types = types->next) + { + tree cur_param; + tree cur_type; + tree orig_cur_type; + tree wanted_type; + int arg_num; + int i; + int char_type_flag; + cur_param = types->param; + cur_type = TREE_TYPE (cur_param); + if (cur_type == error_mark_node) + continue; + orig_cur_type = cur_type; + char_type_flag = 0; + wanted_type = types->wanted_type; + arg_num = types->arg_num; + + /* The following should not occur here. */ + gcc_assert (wanted_type); + gcc_assert (wanted_type != void_type_node || types->pointer_count); + + if (types->pointer_count == 0) + wanted_type = lang_hooks.types.type_promotes_to (wanted_type); + + wanted_type = TYPE_MAIN_VARIANT (wanted_type); + + STRIP_NOPS (cur_param); + + /* Check the types of any additional pointer arguments + that precede the "real" argument. */ + for (i = 0; i < types->pointer_count; ++i) + { + if (TREE_CODE (cur_type) == POINTER_TYPE) + { + cur_type = TREE_TYPE (cur_type); + if (cur_type == error_mark_node) + break; + + /* Check for writing through a NULL pointer. */ + if (types->writing_in_flag + && i == 0 + && cur_param != 0 + && integer_zerop (cur_param)) + warning (OPT_Wformat, "writing through null pointer " + "(argument %d)", arg_num); + + /* Check for reading through a NULL pointer. */ + if (types->reading_from_flag + && i == 0 + && cur_param != 0 + && integer_zerop (cur_param)) + warning (OPT_Wformat, "reading through null pointer " + "(argument %d)", arg_num); + + if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR) + cur_param = TREE_OPERAND (cur_param, 0); + else + cur_param = 0; + + /* See if this is an attempt to write into a const type with + scanf or with printf "%n". Note: the writing in happens + at the first indirection only, if for example + void * const * is passed to scanf %p; passing + const void ** is simply passing an incompatible type. */ + if (types->writing_in_flag + && i == 0 + && (TYPE_READONLY (cur_type) + || (cur_param != 0 + && (CONSTANT_CLASS_P (cur_param) + || (DECL_P (cur_param) + && TREE_READONLY (cur_param)))))) + warning (OPT_Wformat, "writing into constant object " + "(argument %d)", arg_num); + + /* If there are extra type qualifiers beyond the first + indirection, then this makes the types technically + incompatible. */ + if (i > 0 + && pedantic + && (TYPE_READONLY (cur_type) + || TYPE_VOLATILE (cur_type) + || TYPE_RESTRICT (cur_type))) + warning (OPT_Wformat, "extra type qualifiers in format " + "argument (argument %d)", + arg_num); + + } + else + { + format_type_warning (types->name, format_start, format_length, + wanted_type, types->pointer_count, + types->wanted_type_name, orig_cur_type, + arg_num); + break; + } + } + + if (i < types->pointer_count) + continue; + + cur_type = TYPE_MAIN_VARIANT (cur_type); + + /* Check whether the argument type is a character type. This leniency + only applies to certain formats, flagged with 'c'. + */ + if (types->char_lenient_flag) + char_type_flag = (cur_type == char_type_node + || cur_type == signed_char_type_node + || cur_type == unsigned_char_type_node); + + /* Check the type of the "real" argument, if there's a type we want. */ + if (lang_hooks.types_compatible_p (wanted_type, cur_type)) + continue; + /* If we want 'void *', allow any pointer type. + (Anything else would already have got a warning.) + With -pedantic, only allow pointers to void and to character + types. */ + if (wanted_type == void_type_node + && (!pedantic || (i == 1 && char_type_flag))) + continue; + /* Don't warn about differences merely in signedness, unless + -pedantic. With -pedantic, warn if the type is a pointer + target and not a character type, and for character types at + a second level of indirection. */ + if (TREE_CODE (wanted_type) == INTEGER_TYPE + && TREE_CODE (cur_type) == INTEGER_TYPE + && (!pedantic || i == 0 || (i == 1 && char_type_flag)) + && (TYPE_UNSIGNED (wanted_type) + ? wanted_type == c_common_unsigned_type (cur_type) + : wanted_type == c_common_signed_type (cur_type))) + continue; + /* Likewise, "signed char", "unsigned char" and "char" are + equivalent but the above test won't consider them equivalent. */ + if (wanted_type == char_type_node + && (!pedantic || i < 2) + && char_type_flag) + continue; + if (types->scalar_identity_flag + && (TREE_CODE (cur_type) == TREE_CODE (wanted_type) + || (INTEGRAL_TYPE_P (cur_type) + && INTEGRAL_TYPE_P (wanted_type))) + && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type)) + continue; + /* Now we have a type mismatch. */ + format_type_warning (types->name, format_start, format_length, + wanted_type, types->pointer_count, + types->wanted_type_name, orig_cur_type, arg_num); + } +} + + +/* Give a warning about a format argument of different type from that + expected. DESCR is a description such as "field precision", or + NULL for an ordinary format. For an ordinary format, FORMAT_START + points to where the format starts in the format string and + FORMAT_LENGTH is its length. WANTED_TYPE is the type the argument + should have after POINTER_COUNT pointer dereferences. + WANTED_NAME_NAME is a possibly more friendly name of WANTED_TYPE, + or NULL if the ordinary name of the type should be used. ARG_TYPE + is the type of the actual argument. ARG_NUM is the number of that + argument. */ +static void +format_type_warning (const char *descr, const char *format_start, + int format_length, tree wanted_type, int pointer_count, + const char *wanted_type_name, tree arg_type, int arg_num) +{ + char *p; + /* If ARG_TYPE is a typedef with a misleading name (for example, + size_t but not the standard size_t expected by printf %zu), avoid + printing the typedef name. */ + if (wanted_type_name + && TYPE_NAME (arg_type) + && TREE_CODE (TYPE_NAME (arg_type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (arg_type)) + && !strcmp (wanted_type_name, + lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2))) + arg_type = TYPE_MAIN_VARIANT (arg_type); + /* The format type and name exclude any '*' for pointers, so those + must be formatted manually. For all the types we currently have, + this is adequate, but formats taking pointers to functions or + arrays would require the full type to be built up in order to + print it with %T. */ + p = (char *) alloca (pointer_count + 2); + if (pointer_count == 0) + p[0] = 0; + else if (c_dialect_cxx ()) + { + memset (p, '*', pointer_count); + p[pointer_count] = 0; + } + else + { + p[0] = ' '; + memset (p + 1, '*', pointer_count); + p[pointer_count + 1] = 0; + } + if (wanted_type_name) + { + if (descr) + warning (OPT_Wformat, "%s should have type %<%s%s%>, " + "but argument %d has type %qT", + descr, wanted_type_name, p, arg_num, arg_type); + else + warning (OPT_Wformat, "format %q.*s expects type %<%s%s%>, " + "but argument %d has type %qT", + format_length, format_start, wanted_type_name, p, + arg_num, arg_type); + } + else + { + if (descr) + warning (OPT_Wformat, "%s should have type %<%T%s%>, " + "but argument %d has type %qT", + descr, wanted_type, p, arg_num, arg_type); + else + warning (OPT_Wformat, "format %q.*s expects type %<%T%s%>, " + "but argument %d has type %qT", + format_length, format_start, wanted_type, p, arg_num, arg_type); + } +} + + +/* Given a format_char_info array FCI, and a character C, this function + returns the index into the conversion_specs where that specifier's + data is located. The character must exist. */ +static unsigned int +find_char_info_specifier_index (const format_char_info *fci, int c) +{ + unsigned i; + + for (i = 0; fci->format_chars; i++, fci++) + if (strchr (fci->format_chars, c)) + return i; + + /* We shouldn't be looking for a non-existent specifier. */ + gcc_unreachable (); +} + +/* Given a format_length_info array FLI, and a character C, this + function returns the index into the conversion_specs where that + modifier's data is located. The character must exist. */ +static unsigned int +find_length_info_modifier_index (const format_length_info *fli, int c) +{ + unsigned i; + + for (i = 0; fli->name; i++, fli++) + if (strchr (fli->name, c)) + return i; + + /* We shouldn't be looking for a non-existent modifier. */ + gcc_unreachable (); +} + +/* Determine the type of HOST_WIDE_INT in the code being compiled for + use in GCC's __asm_fprintf__ custom format attribute. You must + have set dynamic_format_types before calling this function. */ +static void +init_dynamic_asm_fprintf_info (void) +{ + static tree hwi; + + if (!hwi) + { + format_length_info *new_asm_fprintf_length_specs; + unsigned int i; + + /* Find the underlying type for HOST_WIDE_INT. For the %w + length modifier to work, one must have issued: "typedef + HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code + prior to using that modifier. */ + hwi = maybe_get_identifier ("__gcc_host_wide_int__"); + if (!hwi) + { + error ("%<__gcc_host_wide_int__%> is not defined as a type"); + return; + } + hwi = identifier_global_value (hwi); + if (!hwi || TREE_CODE (hwi) != TYPE_DECL) + { + error ("%<__gcc_host_wide_int__%> is not defined as a type"); + return; + } + hwi = DECL_ORIGINAL_TYPE (hwi); + gcc_assert (hwi); + if (hwi != long_integer_type_node && hwi != long_long_integer_type_node) + { + error ("%<__gcc_host_wide_int__%> is not defined as %" + " or %"); + return; + } + + /* Create a new (writable) copy of asm_fprintf_length_specs. */ + new_asm_fprintf_length_specs = (format_length_info *) + xmemdup (asm_fprintf_length_specs, + sizeof (asm_fprintf_length_specs), + sizeof (asm_fprintf_length_specs)); + + /* HOST_WIDE_INT must be one of 'long' or 'long long'. */ + i = find_length_info_modifier_index (new_asm_fprintf_length_specs, 'w'); + if (hwi == long_integer_type_node) + new_asm_fprintf_length_specs[i].index = FMT_LEN_l; + else if (hwi == long_long_integer_type_node) + new_asm_fprintf_length_specs[i].index = FMT_LEN_ll; + else + gcc_unreachable (); + + /* Assign the new data for use. */ + dynamic_format_types[asm_fprintf_format_type].length_char_specs = + new_asm_fprintf_length_specs; + } +} + +/* Determine the type of a "locus" in the code being compiled for use + in GCC's __gcc_gfc__ custom format attribute. You must have set + dynamic_format_types before calling this function. */ +static void +init_dynamic_gfc_info (void) +{ + static tree locus; + + if (!locus) + { + static format_char_info *gfc_fci; + + /* For the GCC __gcc_gfc__ custom format specifier to work, one + must have declared 'locus' prior to using this attribute. If + we haven't seen this declarations then you shouldn't use the + specifier requiring that type. */ + if ((locus = maybe_get_identifier ("locus"))) + { + locus = identifier_global_value (locus); + if (locus) + { + if (TREE_CODE (locus) != TYPE_DECL + || TREE_TYPE (locus) == error_mark_node) + { + error ("% is not defined as a type"); + locus = 0; + } + else + locus = TREE_TYPE (locus); + } + } + + /* Assign the new data for use. */ + + /* Handle the __gcc_gfc__ format specifics. */ + if (!gfc_fci) + dynamic_format_types[gcc_gfc_format_type].conversion_specs = + gfc_fci = (format_char_info *) + xmemdup (gcc_gfc_char_table, + sizeof (gcc_gfc_char_table), + sizeof (gcc_gfc_char_table)); + if (locus) + { + const unsigned i = find_char_info_specifier_index (gfc_fci, 'L'); + gfc_fci[i].types[0].type = &locus; + gfc_fci[i].pointer_count = 1; + } + } +} + +/* Determine the types of "tree" and "location_t" in the code being + compiled for use in GCC's diagnostic custom format attributes. You + must have set dynamic_format_types before calling this function. */ +static void +init_dynamic_diag_info (void) +{ + static tree t, loc, hwi; + + if (!loc || !t || !hwi) + { + static format_char_info *diag_fci, *tdiag_fci, *cdiag_fci, *cxxdiag_fci; + static format_length_info *diag_ls; + unsigned int i; + + /* For the GCC-diagnostics custom format specifiers to work, one + must have declared 'tree' and/or 'location_t' prior to using + those attributes. If we haven't seen these declarations then + you shouldn't use the specifiers requiring these types. + However we don't force a hard ICE because we may see only one + or the other type. */ + if ((loc = maybe_get_identifier ("location_t"))) + { + loc = identifier_global_value (loc); + if (loc) + { + if (TREE_CODE (loc) != TYPE_DECL) + { + error ("% is not defined as a type"); + loc = 0; + } + else + loc = TREE_TYPE (loc); + } + } + + /* We need to grab the underlying 'union tree_node' so peek into + an extra type level. */ + if ((t = maybe_get_identifier ("tree"))) + { + t = identifier_global_value (t); + if (t) + { + if (TREE_CODE (t) != TYPE_DECL) + { + error ("% is not defined as a type"); + t = 0; + } + else if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + error ("% is not defined as a pointer type"); + t = 0; + } + else + t = TREE_TYPE (TREE_TYPE (t)); + } + } + + /* Find the underlying type for HOST_WIDE_INT. For the %w + length modifier to work, one must have issued: "typedef + HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code + prior to using that modifier. */ + if ((hwi = maybe_get_identifier ("__gcc_host_wide_int__"))) + { + hwi = identifier_global_value (hwi); + if (hwi) + { + if (TREE_CODE (hwi) != TYPE_DECL) + { + error ("%<__gcc_host_wide_int__%> is not defined as a type"); + hwi = 0; + } + else + { + hwi = DECL_ORIGINAL_TYPE (hwi); + gcc_assert (hwi); + if (hwi != long_integer_type_node + && hwi != long_long_integer_type_node) + { + error ("%<__gcc_host_wide_int__%> is not defined" + " as % or %"); + hwi = 0; + } + } + } + } + + /* Assign the new data for use. */ + + /* All the GCC diag formats use the same length specs. */ + if (!diag_ls) + dynamic_format_types[gcc_diag_format_type].length_char_specs = + dynamic_format_types[gcc_tdiag_format_type].length_char_specs = + dynamic_format_types[gcc_cdiag_format_type].length_char_specs = + dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs = + diag_ls = (format_length_info *) + xmemdup (gcc_diag_length_specs, + sizeof (gcc_diag_length_specs), + sizeof (gcc_diag_length_specs)); + if (hwi) + { + /* HOST_WIDE_INT must be one of 'long' or 'long long'. */ + i = find_length_info_modifier_index (diag_ls, 'w'); + if (hwi == long_integer_type_node) + diag_ls[i].index = FMT_LEN_l; + else if (hwi == long_long_integer_type_node) + diag_ls[i].index = FMT_LEN_ll; + else + gcc_unreachable (); + } + + /* Handle the __gcc_diag__ format specifics. */ + if (!diag_fci) + dynamic_format_types[gcc_diag_format_type].conversion_specs = + diag_fci = (format_char_info *) + xmemdup (gcc_diag_char_table, + sizeof (gcc_diag_char_table), + sizeof (gcc_diag_char_table)); + if (t) + { + i = find_char_info_specifier_index (diag_fci, 'K'); + diag_fci[i].types[0].type = &t; + diag_fci[i].pointer_count = 1; + } + + /* Handle the __gcc_tdiag__ format specifics. */ + if (!tdiag_fci) + dynamic_format_types[gcc_tdiag_format_type].conversion_specs = + tdiag_fci = (format_char_info *) + xmemdup (gcc_tdiag_char_table, + sizeof (gcc_tdiag_char_table), + sizeof (gcc_tdiag_char_table)); + if (t) + { + /* All specifiers taking a tree share the same struct. */ + i = find_char_info_specifier_index (tdiag_fci, 'D'); + tdiag_fci[i].types[0].type = &t; + tdiag_fci[i].pointer_count = 1; + i = find_char_info_specifier_index (tdiag_fci, 'K'); + tdiag_fci[i].types[0].type = &t; + tdiag_fci[i].pointer_count = 1; + } + + /* Handle the __gcc_cdiag__ format specifics. */ + if (!cdiag_fci) + dynamic_format_types[gcc_cdiag_format_type].conversion_specs = + cdiag_fci = (format_char_info *) + xmemdup (gcc_cdiag_char_table, + sizeof (gcc_cdiag_char_table), + sizeof (gcc_cdiag_char_table)); + if (t) + { + /* All specifiers taking a tree share the same struct. */ + i = find_char_info_specifier_index (cdiag_fci, 'D'); + cdiag_fci[i].types[0].type = &t; + cdiag_fci[i].pointer_count = 1; + i = find_char_info_specifier_index (cdiag_fci, 'K'); + cdiag_fci[i].types[0].type = &t; + cdiag_fci[i].pointer_count = 1; + } + + /* Handle the __gcc_cxxdiag__ format specifics. */ + if (!cxxdiag_fci) + dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs = + cxxdiag_fci = (format_char_info *) + xmemdup (gcc_cxxdiag_char_table, + sizeof (gcc_cxxdiag_char_table), + sizeof (gcc_cxxdiag_char_table)); + if (t) + { + /* All specifiers taking a tree share the same struct. */ + i = find_char_info_specifier_index (cxxdiag_fci, 'D'); + cxxdiag_fci[i].types[0].type = &t; + cxxdiag_fci[i].pointer_count = 1; + i = find_char_info_specifier_index (cxxdiag_fci, 'K'); + cxxdiag_fci[i].types[0].type = &t; + cxxdiag_fci[i].pointer_count = 1; + } + } +} + +#ifdef TARGET_FORMAT_TYPES +extern const format_kind_info TARGET_FORMAT_TYPES[]; +#endif + +#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES +extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[]; +#endif +#ifdef TARGET_OVERRIDES_FORMAT_INIT + extern void TARGET_OVERRIDES_FORMAT_INIT (void); +#endif + +/* Attributes such as "printf" are equivalent to those such as + "gnu_printf" unless this is overridden by a target. */ +static const target_ovr_attr gnu_target_overrides_format_attributes[] = +{ + { "gnu_printf", "printf" }, + { "gnu_scanf", "scanf" }, + { "gnu_strftime", "strftime" }, + { "gnu_strfmon", "strfmon" }, + { NULL, NULL } +}; + +/* Translate to unified attribute name. This is used in decode_format_type and + decode_format_attr. In attr_name the user specified argument is passed. It + returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES + or the attr_name passed to this function, if there is no matching entry. */ +static const char * +convert_format_name_to_system_name (const char *attr_name) +{ + int i; + + if (attr_name == NULL || *attr_name == 0 + || strncmp (attr_name, "gcc_", 4) == 0) + return attr_name; +#ifdef TARGET_OVERRIDES_FORMAT_INIT + TARGET_OVERRIDES_FORMAT_INIT (); +#endif + +#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES + /* Check if format attribute is overridden by target. */ + if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL + && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0) + { + for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i) + { + if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, + attr_name)) + return attr_name; + if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst, + attr_name)) + return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src; + } + } +#endif + /* Otherwise default to gnu format. */ + for (i = 0; + gnu_target_overrides_format_attributes[i].named_attr_src != NULL; + ++i) + { + if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src, + attr_name)) + return attr_name; + if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst, + attr_name)) + return gnu_target_overrides_format_attributes[i].named_attr_src; + } + + return attr_name; +} + +/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute, + counting "name" and "__name__" as the same, false otherwise. */ +static bool +cmp_attribs (const char *tattr_name, const char *attr_name) +{ + int alen = strlen (attr_name); + int slen = (tattr_name ? strlen (tattr_name) : 0); + if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_' + && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_') + { + attr_name += 2; + alen -= 4; + } + if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0) + return false; + return true; +} + +/* Handle a "format" attribute; arguments as in + struct attribute_spec.handler. */ +tree +handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args, + int flags, bool *no_add_attrs) +{ + tree type = *node; + function_format_info info; + tree argument; + +#ifdef TARGET_FORMAT_TYPES + /* If the target provides additional format types, we need to + add them to FORMAT_TYPES at first use. */ + if (TARGET_FORMAT_TYPES != NULL && !dynamic_format_types) + { + dynamic_format_types = XNEWVEC (format_kind_info, + n_format_types + TARGET_N_FORMAT_TYPES); + memcpy (dynamic_format_types, format_types_orig, + sizeof (format_types_orig)); + memcpy (&dynamic_format_types[n_format_types], TARGET_FORMAT_TYPES, + TARGET_N_FORMAT_TYPES * sizeof (dynamic_format_types[0])); + + format_types = dynamic_format_types; + n_format_types += TARGET_N_FORMAT_TYPES; + } +#endif + + if (!decode_format_attr (args, &info, 0)) + { + *no_add_attrs = true; + return NULL_TREE; + } + + argument = TYPE_ARG_TYPES (type); + if (argument) + { + if (!check_format_string (argument, info.format_num, flags, + no_add_attrs)) + return NULL_TREE; + + if (info.first_arg_num != 0) + { + unsigned HOST_WIDE_INT arg_num = 1; + + /* Verify that first_arg_num points to the last arg, + the ... */ + while (argument) + arg_num++, argument = TREE_CHAIN (argument); + + if (arg_num != info.first_arg_num) + { + if (!(flags & (int) ATTR_FLAG_BUILT_IN)) + error ("args to be formatted is not %<...%>"); + *no_add_attrs = true; + return NULL_TREE; + } + } + } + + /* Check if this is a strftime variant. Just for this variant + FMT_FLAG_ARG_CONVERT is not set. */ + if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0 + && info.first_arg_num != 0) + { + error ("strftime formats cannot format arguments"); + *no_add_attrs = true; + return NULL_TREE; + } + + /* If this is a custom GCC-internal format type, we have to + initialize certain bits at runtime. */ + if (info.format_type == asm_fprintf_format_type + || info.format_type == gcc_gfc_format_type + || info.format_type == gcc_diag_format_type + || info.format_type == gcc_tdiag_format_type + || info.format_type == gcc_cdiag_format_type + || info.format_type == gcc_cxxdiag_format_type) + { + /* Our first time through, we have to make sure that our + format_type data is allocated dynamically and is modifiable. */ + if (!dynamic_format_types) + format_types = dynamic_format_types = (format_kind_info *) + xmemdup (format_types_orig, sizeof (format_types_orig), + sizeof (format_types_orig)); + + /* If this is format __asm_fprintf__, we have to initialize + GCC's notion of HOST_WIDE_INT for checking %wd. */ + if (info.format_type == asm_fprintf_format_type) + init_dynamic_asm_fprintf_info (); + /* If this is format __gcc_gfc__, we have to initialize GCC's + notion of 'locus' at runtime for %L. */ + else if (info.format_type == gcc_gfc_format_type) + init_dynamic_gfc_info (); + /* If this is one of the diagnostic attributes, then we have to + initialize 'location_t' and 'tree' at runtime. */ + else if (info.format_type == gcc_diag_format_type + || info.format_type == gcc_tdiag_format_type + || info.format_type == gcc_cdiag_format_type + || info.format_type == gcc_cxxdiag_format_type) + init_dynamic_diag_info (); + else + gcc_unreachable (); + } + + return NULL_TREE; +} diff --git a/gcc/c-family/c-format.h b/gcc/c-family/c-format.h new file mode 100644 index 0000000..9d01f0a --- /dev/null +++ b/gcc/c-family/c-format.h @@ -0,0 +1,326 @@ +/* Check calls to formatted I/O functions (-Wformat). + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2007, 2008 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 +. */ + +#ifndef GCC_C_FORMAT_H +#define GCC_C_FORMAT_H + +/* The meaningfully distinct length modifiers for format checking recognized + by GCC. */ +enum format_lengths +{ + FMT_LEN_none, + FMT_LEN_hh, + FMT_LEN_h, + FMT_LEN_l, + FMT_LEN_ll, + FMT_LEN_L, + FMT_LEN_z, + FMT_LEN_t, + FMT_LEN_j, + FMT_LEN_H, + FMT_LEN_D, + FMT_LEN_DD, + FMT_LEN_MAX +}; + + +/* The standard versions in which various format features appeared. */ +enum format_std_version +{ + STD_C89, + STD_C94, + STD_C9L, /* C99, but treat as C89 if -Wno-long-long. */ + STD_C99, + STD_EXT +}; + +/* Flags that may apply to a particular kind of format checked by GCC. */ +enum +{ + /* This format converts arguments of types determined by the + format string. */ + FMT_FLAG_ARG_CONVERT = 1, + /* The scanf allocation 'a' kludge applies to this format kind. */ + FMT_FLAG_SCANF_A_KLUDGE = 2, + /* A % during parsing a specifier is allowed to be a modified % rather + that indicating the format is broken and we are out-of-sync. */ + FMT_FLAG_FANCY_PERCENT_OK = 4, + /* With $ operand numbers, it is OK to reference the same argument more + than once. */ + FMT_FLAG_DOLLAR_MULTIPLE = 8, + /* This format type uses $ operand numbers (strfmon doesn't). */ + FMT_FLAG_USE_DOLLAR = 16, + /* Zero width is bad in this type of format (scanf). */ + FMT_FLAG_ZERO_WIDTH_BAD = 32, + /* Empty precision specification is OK in this type of format (printf). */ + FMT_FLAG_EMPTY_PREC_OK = 64, + /* Gaps are allowed in the arguments with $ operand numbers if all + arguments are pointers (scanf). */ + FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128 + /* Not included here: details of whether width or precision may occur + (controlled by width_char and precision_char); details of whether + '*' can be used for these (width_type and precision_type); details + of whether length modifiers can occur (length_char_specs). */ +}; + +/* Structure describing a length modifier supported in format checking, and + possibly a doubled version such as "hh". */ +typedef struct +{ + /* Name of the single-character length modifier. If prefixed by + a zero character, it describes a multi character length + modifier, like I64, I32, etc. */ + const char *name; + /* Index into a format_char_info.types array. */ + enum format_lengths index; + /* Standard version this length appears in. */ + enum format_std_version std; + /* Same, if the modifier can be repeated, or NULL if it can't. */ + const char *double_name; + enum format_lengths double_index; + enum format_std_version double_std; + + /* If this flag is set, just scalar width identity is checked, and + not the type identity itself. */ + int scalar_identity_flag; +} format_length_info; + + +/* Structure describing the combination of a conversion specifier + (or a set of specifiers which act identically) and a length modifier. */ +typedef struct +{ + /* The standard version this combination of length and type appeared in. + This is only relevant if greater than those for length and type + individually; otherwise it is ignored. */ + enum format_std_version std; + /* The name to use for the type, if different from that generated internally + (e.g., "signed size_t"). */ + const char *name; + /* The type itself. */ + tree *type; +} format_type_detail; + + +/* Macros to fill out tables of these. */ +#define NOARGUMENTS { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } +#define BADLEN { STD_C89, NULL, NULL } +#define NOLENGTHS { BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } + + +/* Structure describing a format conversion specifier (or a set of specifiers + which act identically), and the length modifiers used with it. */ +typedef struct format_char_info +{ + const char *format_chars; + int pointer_count; + enum format_std_version std; + /* Types accepted for each length modifier. */ + format_type_detail types[FMT_LEN_MAX]; + /* List of other modifier characters allowed with these specifiers. + This lists flags, and additionally "w" for width, "p" for precision + (right precision, for strfmon), "#" for left precision (strfmon), + "a" for scanf "a" allocation extension (not applicable in C99 mode), + "*" for scanf suppression, and "E" and "O" for those strftime + modifiers. */ + const char *flag_chars; + /* List of additional flags describing these conversion specifiers. + "c" for generic character pointers being allowed, "2" for strftime + two digit year formats, "3" for strftime formats giving two digit + years in some locales, "4" for "2" which becomes "3" with an "E" modifier, + "o" if use of strftime "O" is a GNU extension beyond C99, + "W" if the argument is a pointer which is dereferenced and written into, + "R" if the argument is a pointer which is dereferenced and read from, + "i" for printf integer formats where the '0' flag is ignored with + precision, and "[" for the starting character of a scanf scanset. */ + const char *flags2; + /* If this format conversion character consumes more than one argument, + CHAIN points to information about the next argument. For later + arguments, only POINTER_COUNT, TYPES, and the "c", "R", and "W" flags + in FLAGS2 are used. */ + const struct format_char_info *chain; +} format_char_info; + + +/* Structure describing a flag accepted by some kind of format. */ +typedef struct +{ + /* The flag character in question (0 for end of array). */ + int flag_char; + /* Zero if this entry describes the flag character in general, or a + nonzero character that may be found in flags2 if it describes the + flag when used with certain formats only. If the latter, only + the first such entry found that applies to the current conversion + specifier is used; the values of 'name' and 'long_name' it supplies + will be used, if non-NULL and the standard version is higher than + the unpredicated one, for any pedantic warning. For example, 'o' + for strftime formats (meaning 'O' is an extension over C99). */ + int predicate; + /* Nonzero if the next character after this flag in the format should + be skipped ('=' in strfmon), zero otherwise. */ + int skip_next_char; + /* The name to use for this flag in diagnostic messages. For example, + N_("'0' flag"), N_("field width"). */ + const char *name; + /* Long name for this flag in diagnostic messages; currently only used for + "ISO C does not support ...". For example, N_("the 'I' printf flag"). */ + const char *long_name; + /* The standard version in which it appeared. */ + enum format_std_version std; +} format_flag_spec; + + +/* Structure describing a combination of flags that is bad for some kind + of format. */ +typedef struct +{ + /* The first flag character in question (0 for end of array). */ + int flag_char1; + /* The second flag character. */ + int flag_char2; + /* Nonzero if the message should say that the first flag is ignored with + the second, zero if the combination should simply be objected to. */ + int ignored; + /* Zero if this entry applies whenever this flag combination occurs, + a nonzero character from flags2 if it only applies in some + circumstances (e.g. 'i' for printf formats ignoring 0 with precision). */ + int predicate; +} format_flag_pair; + + +/* Structure describing a particular kind of format processed by GCC. */ +typedef struct +{ + /* The name of this kind of format, for use in diagnostics. Also + the name of the attribute (without preceding and following __). */ + const char *name; + /* Specifications of the length modifiers accepted; possibly NULL. */ + const format_length_info *length_char_specs; + /* Details of the conversion specification characters accepted. */ + const format_char_info *conversion_specs; + /* String listing the flag characters that are accepted. */ + const char *flag_chars; + /* String listing modifier characters (strftime) accepted. May be NULL. */ + const char *modifier_chars; + /* Details of the flag characters, including pseudo-flags. */ + const format_flag_spec *flag_specs; + /* Details of bad combinations of flags. */ + const format_flag_pair *bad_flag_pairs; + /* Flags applicable to this kind of format. */ + int flags; + /* Flag character to treat a width as, or 0 if width not used. */ + int width_char; + /* Flag character to treat a left precision (strfmon) as, + or 0 if left precision not used. */ + int left_precision_char; + /* Flag character to treat a precision (for strfmon, right precision) as, + or 0 if precision not used. */ + int precision_char; + /* If a flag character has the effect of suppressing the conversion of + an argument ('*' in scanf), that flag character, otherwise 0. */ + int suppression_char; + /* Flag character to treat a length modifier as (ignored if length + modifiers not used). Need not be placed in flag_chars for conversion + specifiers, but is used to check for bad combinations such as length + modifier with assignment suppression in scanf. */ + int length_code_char; + /* Assignment-allocation flag character ('m' in scanf), otherwise 0. */ + int alloc_char; + /* Pointer to type of argument expected if '*' is used for a width, + or NULL if '*' not used for widths. */ + tree *width_type; + /* Pointer to type of argument expected if '*' is used for a precision, + or NULL if '*' not used for precisions. */ + tree *precision_type; +} format_kind_info; + +#define T_I &integer_type_node +#define T89_I { STD_C89, NULL, T_I } +#define T_L &long_integer_type_node +#define T89_L { STD_C89, NULL, T_L } +#define T_LL &long_long_integer_type_node +#define T9L_LL { STD_C9L, NULL, T_LL } +#define TEX_LL { STD_EXT, NULL, T_LL } +#define T_S &short_integer_type_node +#define T89_S { STD_C89, NULL, T_S } +#define T_UI &unsigned_type_node +#define T89_UI { STD_C89, NULL, T_UI } +#define T_UL &long_unsigned_type_node +#define T89_UL { STD_C89, NULL, T_UL } +#define T_ULL &long_long_unsigned_type_node +#define T9L_ULL { STD_C9L, NULL, T_ULL } +#define TEX_ULL { STD_EXT, NULL, T_ULL } +#define T_US &short_unsigned_type_node +#define T89_US { STD_C89, NULL, T_US } +#define T_F &float_type_node +#define T89_F { STD_C89, NULL, T_F } +#define T99_F { STD_C99, NULL, T_F } +#define T_D &double_type_node +#define T89_D { STD_C89, NULL, T_D } +#define T99_D { STD_C99, NULL, T_D } +#define T_LD &long_double_type_node +#define T89_LD { STD_C89, NULL, T_LD } +#define T99_LD { STD_C99, NULL, T_LD } +#define T_C &char_type_node +#define T89_C { STD_C89, NULL, T_C } +#define T_SC &signed_char_type_node +#define T99_SC { STD_C99, NULL, T_SC } +#define T_UC &unsigned_char_type_node +#define T99_UC { STD_C99, NULL, T_UC } +#define T_V &void_type_node +#define T89_V { STD_C89, NULL, T_V } +#define T_W &wchar_type_node +#define T94_W { STD_C94, "wchar_t", T_W } +#define TEX_W { STD_EXT, "wchar_t", T_W } +#define T_WI &wint_type_node +#define T94_WI { STD_C94, "wint_t", T_WI } +#define TEX_WI { STD_EXT, "wint_t", T_WI } +#define T_ST &size_type_node +#define T99_ST { STD_C99, "size_t", T_ST } +#define T_SST &signed_size_type_node +#define T99_SST { STD_C99, "signed size_t", T_SST } +#define T_PD &ptrdiff_type_node +#define T99_PD { STD_C99, "ptrdiff_t", T_PD } +#define T_UPD &unsigned_ptrdiff_type_node +#define T99_UPD { STD_C99, "unsigned ptrdiff_t", T_UPD } +#define T_IM &intmax_type_node +#define T99_IM { STD_C99, "intmax_t", T_IM } +#define T_UIM &uintmax_type_node +#define T99_UIM { STD_C99, "uintmax_t", T_UIM } +#define T_D32 &dfloat32_type_node +#define TEX_D32 { STD_EXT, "_Decimal32", T_D32 } +#define T_D64 &dfloat64_type_node +#define TEX_D64 { STD_EXT, "_Decimal64", T_D64 } +#define T_D128 &dfloat128_type_node +#define TEX_D128 { STD_EXT, "_Decimal128", T_D128 } + +/* Structure describing how format attributes such as "printf" are + interpreted as "gnu_printf" or "ms_printf" on a particular system. + TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific + defaults. */ +typedef struct +{ + /* The name of the to be copied format attribute. */ + const char *named_attr_src; + /* The name of the to be overridden format attribute. */ + const char *named_attr_dst; +} target_ovr_attr; + +#endif /* GCC_C_FORMAT_H */ diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c new file mode 100644 index 0000000..06963a0 --- /dev/null +++ b/gcc/c-family/c-gimplify.c @@ -0,0 +1,190 @@ +/* Tree lowering pass. This pass gimplifies the tree representation built + by the C-based front ends. The structure of gimplified, or + language-independent, trees is dictated by the grammar described in this + file. + Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. + Lowering of expressions contributed by Sebastian Pop + Re-written to support lowering of whole function trees, documentation + and miscellaneous cleanups by Diego Novillo + +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 "tree.h" +#include "c-common.h" +#include "gimple.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "tree-inline.h" +#include "diagnostic-core.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "flags.h" +#include "toplev.h" +#include "tree-dump.h" +#include "c-pretty-print.h" +#include "cgraph.h" + + +/* The gimplification pass converts the language-dependent trees + (ld-trees) emitted by the parser into language-independent trees + (li-trees) that are the target of SSA analysis and transformations. + + Language-independent trees are based on the SIMPLE intermediate + representation used in the McCAT compiler framework: + + "Designing the McCAT Compiler Based on a Family of Structured + Intermediate Representations," + L. Hendren, C. Donawa, M. Emami, G. Gao, Justiani, and B. Sridharan, + Proceedings of the 5th International Workshop on Languages and + Compilers for Parallel Computing, no. 757 in Lecture Notes in + Computer Science, New Haven, Connecticut, pp. 406-420, + Springer-Verlag, August 3-5, 1992. + + http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html + + Basically, we walk down gimplifying the nodes that we encounter. As we + walk back up, we check that they fit our constraints, and copy them + into temporaries if not. */ + +/* Gimplification of statement trees. */ + +/* Convert the tree representation of FNDECL from C frontend trees to + GENERIC. */ + +void +c_genericize (tree fndecl) +{ + FILE *dump_orig; + int local_dump_flags; + struct cgraph_node *cgn; + + /* Dump the C-specific tree IR. */ + dump_orig = dump_begin (TDI_original, &local_dump_flags); + if (dump_orig) + { + fprintf (dump_orig, "\n;; Function %s", + lang_hooks.decl_printable_name (fndecl, 2)); + fprintf (dump_orig, " (%s)\n", + (!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null" + : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)))); + fprintf (dump_orig, ";; enabled by -%s\n", dump_flag_name (TDI_original)); + fprintf (dump_orig, "\n"); + + if (local_dump_flags & TDF_RAW) + dump_node (DECL_SAVED_TREE (fndecl), + TDF_SLIM | local_dump_flags, dump_orig); + else + print_c_tree (dump_orig, DECL_SAVED_TREE (fndecl)); + fprintf (dump_orig, "\n"); + + dump_end (TDI_original, dump_orig); + } + + /* Dump all nested functions now. */ + cgn = cgraph_node (fndecl); + for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) + c_genericize (cgn->decl); +} + +static void +add_block_to_enclosing (tree block) +{ + unsigned i; + tree enclosing; + gimple bind; + VEC(gimple, heap) *stack = gimple_bind_expr_stack (); + + for (i = 0; VEC_iterate (gimple, stack, i, bind); i++) + if (gimple_bind_block (bind)) + break; + + enclosing = gimple_bind_block (bind); + BLOCK_SUBBLOCKS (enclosing) = chainon (BLOCK_SUBBLOCKS (enclosing), block); +} + +/* Genericize a scope by creating a new BIND_EXPR. + BLOCK is either a BLOCK representing the scope or a chain of _DECLs. + In the latter case, we need to create a new BLOCK and add it to the + BLOCK_SUBBLOCKS of the enclosing block. + BODY is a chain of C _STMT nodes for the contents of the scope, to be + genericized. */ + +tree +c_build_bind_expr (location_t loc, tree block, tree body) +{ + tree decls, bind; + + if (block == NULL_TREE) + decls = NULL_TREE; + else if (TREE_CODE (block) == BLOCK) + decls = BLOCK_VARS (block); + else + { + decls = block; + if (DECL_ARTIFICIAL (decls)) + block = NULL_TREE; + else + { + block = make_node (BLOCK); + BLOCK_VARS (block) = decls; + add_block_to_enclosing (block); + } + } + + if (!body) + body = build_empty_stmt (loc); + if (decls || block) + { + bind = build3 (BIND_EXPR, void_type_node, decls, body, block); + TREE_SIDE_EFFECTS (bind) = 1; + SET_EXPR_LOCATION (bind, loc); + } + else + bind = body; + + return bind; +} + +/* Gimplification of expression trees. */ + +/* Do C-specific gimplification on *EXPR_P. PRE_P and POST_P are as in + gimplify_expr. */ + +int +c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED, + gimple_seq *post_p ATTRIBUTE_UNUSED) +{ + enum tree_code code = TREE_CODE (*expr_p); + + /* This is handled mostly by gimplify.c, but we have to deal with + not warning about int x = x; as it is a GCC extension to turn off + this warning but only if warn_init_self is zero. */ + if (code == DECL_EXPR + && TREE_CODE (DECL_EXPR_DECL (*expr_p)) == VAR_DECL + && !DECL_EXTERNAL (DECL_EXPR_DECL (*expr_p)) + && !TREE_STATIC (DECL_EXPR_DECL (*expr_p)) + && (DECL_INITIAL (DECL_EXPR_DECL (*expr_p)) == DECL_EXPR_DECL (*expr_p)) + && !warn_init_self) + TREE_NO_WARNING (DECL_EXPR_DECL (*expr_p)) = 1; + + return GS_UNHANDLED; +} diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c new file mode 100644 index 0000000..5af574d --- /dev/null +++ b/gcc/c-family/c-lex.c @@ -0,0 +1,1058 @@ +/* Mainly the interface between cpplib and the C front ends. + Copyright (C) 1987, 1988, 1989, 1992, 1994, 1995, 1996, 1997 + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 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 "tree.h" +#include "input.h" +#include "output.h" +#include "c-common.h" +#include "flags.h" +#include "timevar.h" +#include "cpplib.h" +#include "c-pragma.h" +#include "toplev.h" +#include "intl.h" +#include "splay-tree.h" +#include "debug.h" +#include "target.h" + +/* We may keep statistics about how long which files took to compile. */ +static int header_time, body_time; +static splay_tree file_info_tree; + +int pending_lang_change; /* If we need to switch languages - C++ only */ +int c_header_level; /* depth in C headers - C++ only */ + +static tree interpret_integer (const cpp_token *, unsigned int); +static tree interpret_float (const cpp_token *, unsigned int); +static tree interpret_fixed (const cpp_token *, unsigned int); +static enum integer_type_kind narrowest_unsigned_type + (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int); +static enum integer_type_kind narrowest_signed_type + (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int); +static enum cpp_ttype lex_string (const cpp_token *, tree *, bool, bool); +static tree lex_charconst (const cpp_token *); +static void update_header_times (const char *); +static int dump_one_header (splay_tree_node, void *); +static void cb_line_change (cpp_reader *, const cpp_token *, int); +static void cb_ident (cpp_reader *, unsigned int, const cpp_string *); +static void cb_def_pragma (cpp_reader *, unsigned int); +static void cb_define (cpp_reader *, unsigned int, cpp_hashnode *); +static void cb_undef (cpp_reader *, unsigned int, cpp_hashnode *); + +void +init_c_lex (void) +{ + struct cpp_callbacks *cb; + struct c_fileinfo *toplevel; + + /* The get_fileinfo data structure must be initialized before + cpp_read_main_file is called. */ + toplevel = get_fileinfo (""); + if (flag_detailed_statistics) + { + header_time = 0; + body_time = get_run_time (); + toplevel->time = body_time; + } + + cb = cpp_get_callbacks (parse_in); + + cb->line_change = cb_line_change; + cb->ident = cb_ident; + cb->def_pragma = cb_def_pragma; + cb->valid_pch = c_common_valid_pch; + cb->read_pch = c_common_read_pch; + + /* Set the debug callbacks if we can use them. */ + if (debug_info_level == DINFO_LEVEL_VERBOSE + && (write_symbols == DWARF2_DEBUG + || write_symbols == VMS_AND_DWARF2_DEBUG)) + { + cb->define = cb_define; + cb->undef = cb_undef; + } +} + +struct c_fileinfo * +get_fileinfo (const char *name) +{ + splay_tree_node n; + struct c_fileinfo *fi; + + if (!file_info_tree) + file_info_tree = splay_tree_new ((splay_tree_compare_fn) strcmp, + 0, + (splay_tree_delete_value_fn) free); + + n = splay_tree_lookup (file_info_tree, (splay_tree_key) name); + if (n) + return (struct c_fileinfo *) n->value; + + fi = XNEW (struct c_fileinfo); + fi->time = 0; + fi->interface_only = 0; + fi->interface_unknown = 1; + splay_tree_insert (file_info_tree, (splay_tree_key) name, + (splay_tree_value) fi); + return fi; +} + +static void +update_header_times (const char *name) +{ + /* Changing files again. This means currently collected time + is charged against header time, and body time starts back at 0. */ + if (flag_detailed_statistics) + { + int this_time = get_run_time (); + struct c_fileinfo *file = get_fileinfo (name); + header_time += this_time - body_time; + file->time += this_time - body_time; + body_time = this_time; + } +} + +static int +dump_one_header (splay_tree_node n, void * ARG_UNUSED (dummy)) +{ + print_time ((const char *) n->key, + ((struct c_fileinfo *) n->value)->time); + return 0; +} + +void +dump_time_statistics (void) +{ + struct c_fileinfo *file = get_fileinfo (input_filename); + int this_time = get_run_time (); + file->time += this_time - body_time; + + fprintf (stderr, "\n******\n"); + print_time ("header files (total)", header_time); + print_time ("main file (total)", this_time - body_time); + fprintf (stderr, "ratio = %g : 1\n", + (double) header_time / (double) (this_time - body_time)); + fprintf (stderr, "\n******\n"); + + splay_tree_foreach (file_info_tree, dump_one_header, 0); +} + +static void +cb_ident (cpp_reader * ARG_UNUSED (pfile), + unsigned int ARG_UNUSED (line), + const cpp_string * ARG_UNUSED (str)) +{ +#ifdef ASM_OUTPUT_IDENT + if (!flag_no_ident) + { + /* Convert escapes in the string. */ + cpp_string cstr = { 0, 0 }; + if (cpp_interpret_string (pfile, str, 1, &cstr, CPP_STRING)) + { + ASM_OUTPUT_IDENT (asm_out_file, (const char *) cstr.text); + free (CONST_CAST (unsigned char *, cstr.text)); + } + } +#endif +} + +/* Called at the start of every non-empty line. TOKEN is the first + lexed token on the line. Used for diagnostic line numbers. */ +static void +cb_line_change (cpp_reader * ARG_UNUSED (pfile), const cpp_token *token, + int parsing_args) +{ + if (token->type != CPP_EOF && !parsing_args) + input_location = token->src_loc; +} + +void +fe_file_change (const struct line_map *new_map) +{ + if (new_map == NULL) + return; + + if (new_map->reason == LC_ENTER) + { + /* Don't stack the main buffer on the input stack; + we already did in compile_file. */ + if (!MAIN_FILE_P (new_map)) + { + unsigned int included_at = LAST_SOURCE_LINE_LOCATION (new_map - 1); + int line = 0; + if (included_at > BUILTINS_LOCATION) + line = SOURCE_LINE (new_map - 1, included_at); + + input_location = new_map->start_location; + (*debug_hooks->start_source_file) (line, new_map->to_file); +#ifndef NO_IMPLICIT_EXTERN_C + if (c_header_level) + ++c_header_level; + else if (new_map->sysp == 2) + { + c_header_level = 1; + ++pending_lang_change; + } +#endif + } + } + else if (new_map->reason == LC_LEAVE) + { +#ifndef NO_IMPLICIT_EXTERN_C + if (c_header_level && --c_header_level == 0) + { + if (new_map->sysp == 2) + warning (0, "badly nested C headers from preprocessor"); + --pending_lang_change; + } +#endif + input_location = new_map->start_location; + + (*debug_hooks->end_source_file) (new_map->to_line); + } + + update_header_times (new_map->to_file); + input_location = new_map->start_location; +} + +static void +cb_def_pragma (cpp_reader *pfile, source_location loc) +{ + /* Issue a warning message if we have been asked to do so. Ignore + unknown pragmas in system headers unless an explicit + -Wunknown-pragmas has been given. */ + if (warn_unknown_pragmas > in_system_header) + { + const unsigned char *space, *name; + const cpp_token *s; + location_t fe_loc = loc; + + space = name = (const unsigned char *) ""; + s = cpp_get_token (pfile); + if (s->type != CPP_EOF) + { + space = cpp_token_as_text (pfile, s); + s = cpp_get_token (pfile); + if (s->type == CPP_NAME) + name = cpp_token_as_text (pfile, s); + } + + warning_at (fe_loc, OPT_Wunknown_pragmas, "ignoring #pragma %s %s", + space, name); + } +} + +/* #define callback for DWARF and DWARF2 debug info. */ +static void +cb_define (cpp_reader *pfile, source_location loc, cpp_hashnode *node) +{ + const struct line_map *map = linemap_lookup (line_table, loc); + (*debug_hooks->define) (SOURCE_LINE (map, loc), + (const char *) cpp_macro_definition (pfile, node)); +} + +/* #undef callback for DWARF and DWARF2 debug info. */ +static void +cb_undef (cpp_reader * ARG_UNUSED (pfile), source_location loc, + cpp_hashnode *node) +{ + const struct line_map *map = linemap_lookup (line_table, loc); + (*debug_hooks->undef) (SOURCE_LINE (map, loc), + (const char *) NODE_NAME (node)); +} + +/* Read a token and return its type. Fill *VALUE with its value, if + applicable. Fill *CPP_FLAGS with the token's flags, if it is + non-NULL. */ + +enum cpp_ttype +c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, + int lex_flags) +{ + static bool no_more_pch; + const cpp_token *tok; + enum cpp_ttype type; + unsigned char add_flags = 0; + + timevar_push (TV_CPP); + retry: + tok = cpp_get_token_with_location (parse_in, loc); + type = tok->type; + + retry_after_at: + switch (type) + { + case CPP_PADDING: + goto retry; + + case CPP_NAME: + *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node)); + break; + + case CPP_NUMBER: + { + unsigned int flags = cpp_classify_number (parse_in, tok); + + switch (flags & CPP_N_CATEGORY) + { + case CPP_N_INVALID: + /* cpplib has issued an error. */ + *value = error_mark_node; + break; + + case CPP_N_INTEGER: + /* C++ uses '0' to mark virtual functions as pure. + Set PURE_ZERO to pass this information to the C++ parser. */ + if (tok->val.str.len == 1 && *tok->val.str.text == '0') + add_flags = PURE_ZERO; + *value = interpret_integer (tok, flags); + break; + + case CPP_N_FLOATING: + *value = interpret_float (tok, flags); + break; + + default: + gcc_unreachable (); + } + } + break; + + case CPP_ATSIGN: + /* An @ may give the next token special significance in Objective-C. */ + if (c_dialect_objc ()) + { + location_t atloc = *loc; + location_t newloc; + + retry_at: + tok = cpp_get_token_with_location (parse_in, &newloc); + type = tok->type; + switch (type) + { + case CPP_PADDING: + goto retry_at; + + case CPP_STRING: + case CPP_WSTRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_UTF8STRING: + type = lex_string (tok, value, true, true); + break; + + case CPP_NAME: + *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node)); + if (objc_is_reserved_word (*value)) + { + type = CPP_AT_NAME; + break; + } + /* FALLTHROUGH */ + + default: + /* ... or not. */ + error_at (atloc, "stray %<@%> in program"); + *loc = newloc; + goto retry_after_at; + } + break; + } + + /* FALLTHROUGH */ + case CPP_HASH: + case CPP_PASTE: + { + unsigned char name[8]; + + *cpp_spell_token (parse_in, tok, name, true) = 0; + + error ("stray %qs in program", name); + } + + goto retry; + + case CPP_OTHER: + { + cppchar_t c = tok->val.str.text[0]; + + if (c == '"' || c == '\'') + error ("missing terminating %c character", (int) c); + else if (ISGRAPH (c)) + error ("stray %qc in program", (int) c); + else + error ("stray %<\\%o%> in program", (int) c); + } + goto retry; + + case CPP_CHAR: + case CPP_WCHAR: + case CPP_CHAR16: + case CPP_CHAR32: + *value = lex_charconst (tok); + break; + + case CPP_STRING: + case CPP_WSTRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_UTF8STRING: + if ((lex_flags & C_LEX_STRING_NO_JOIN) == 0) + { + type = lex_string (tok, value, false, + (lex_flags & C_LEX_STRING_NO_TRANSLATE) == 0); + break; + } + *value = build_string (tok->val.str.len, (const char *) tok->val.str.text); + break; + + case CPP_PRAGMA: + *value = build_int_cst (NULL, tok->val.pragma); + break; + + /* These tokens should not be visible outside cpplib. */ + case CPP_HEADER_NAME: + case CPP_MACRO_ARG: + gcc_unreachable (); + + /* CPP_COMMENT will appear when compiling with -C and should be + ignored. */ + case CPP_COMMENT: + goto retry; + + default: + *value = NULL_TREE; + break; + } + + if (cpp_flags) + *cpp_flags = tok->flags | add_flags; + + if (!no_more_pch) + { + no_more_pch = true; + c_common_no_more_pch (); + } + + timevar_pop (TV_CPP); + + return type; +} + +/* Returns the narrowest C-visible unsigned type, starting with the + minimum specified by FLAGS, that can fit HIGH:LOW, or itk_none if + there isn't one. */ + +static enum integer_type_kind +narrowest_unsigned_type (unsigned HOST_WIDE_INT low, + unsigned HOST_WIDE_INT high, + unsigned int flags) +{ + int itk; + + if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) + itk = itk_unsigned_int; + else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) + itk = itk_unsigned_long; + else + itk = itk_unsigned_long_long; + + for (; itk < itk_none; itk += 2 /* skip unsigned types */) + { + tree upper; + + if (integer_types[itk] == NULL_TREE) + continue; + upper = TYPE_MAX_VALUE (integer_types[itk]); + + if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) > high + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) == high + && TREE_INT_CST_LOW (upper) >= low)) + return (enum integer_type_kind) itk; + } + + return itk_none; +} + +/* Ditto, but narrowest signed type. */ +static enum integer_type_kind +narrowest_signed_type (unsigned HOST_WIDE_INT low, + unsigned HOST_WIDE_INT high, unsigned int flags) +{ + int itk; + + if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) + itk = itk_int; + else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) + itk = itk_long; + else + itk = itk_long_long; + + + for (; itk < itk_none; itk += 2 /* skip signed types */) + { + tree upper; + + if (integer_types[itk] == NULL_TREE) + continue; + upper = TYPE_MAX_VALUE (integer_types[itk]); + + if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) > high + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) == high + && TREE_INT_CST_LOW (upper) >= low)) + return (enum integer_type_kind) itk; + } + + return itk_none; +} + +/* Interpret TOKEN, an integer with FLAGS as classified by cpplib. */ +static tree +interpret_integer (const cpp_token *token, unsigned int flags) +{ + tree value, type; + enum integer_type_kind itk; + cpp_num integer; + cpp_options *options = cpp_get_options (parse_in); + + integer = cpp_interpret_integer (parse_in, token, flags); + integer = cpp_num_sign_extend (integer, options->precision); + + /* The type of a constant with a U suffix is straightforward. */ + if (flags & CPP_N_UNSIGNED) + itk = narrowest_unsigned_type (integer.low, integer.high, flags); + else + { + /* The type of a potentially-signed integer constant varies + depending on the base it's in, the standard in use, and the + length suffixes. */ + enum integer_type_kind itk_u + = narrowest_unsigned_type (integer.low, integer.high, flags); + enum integer_type_kind itk_s + = narrowest_signed_type (integer.low, integer.high, flags); + + /* In both C89 and C99, octal and hex constants may be signed or + unsigned, whichever fits tighter. We do not warn about this + choice differing from the traditional choice, as the constant + is probably a bit pattern and either way will work. */ + if ((flags & CPP_N_RADIX) != CPP_N_DECIMAL) + itk = MIN (itk_u, itk_s); + else + { + /* In C99, decimal constants are always signed. + In C89, decimal constants that don't fit in long have + undefined behavior; we try to make them unsigned long. + In GCC's extended C89, that last is true of decimal + constants that don't fit in long long, too. */ + + itk = itk_s; + if (itk_s > itk_u && itk_s > itk_long) + { + if (!flag_isoc99) + { + if (itk_u < itk_unsigned_long) + itk_u = itk_unsigned_long; + itk = itk_u; + warning (0, "this decimal constant is unsigned only in ISO C90"); + } + else + warning (OPT_Wtraditional, + "this decimal constant would be unsigned in ISO C90"); + } + } + } + + if (itk == itk_none) + /* cpplib has already issued a warning for overflow. */ + type = ((flags & CPP_N_UNSIGNED) + ? widest_unsigned_literal_type_node + : widest_integer_literal_type_node); + else + { + type = integer_types[itk]; + if (itk > itk_unsigned_long + && (flags & CPP_N_WIDTH) != CPP_N_LARGE) + emit_diagnostic + ((c_dialect_cxx () ? cxx_dialect == cxx98 : !flag_isoc99) + ? DK_PEDWARN : DK_WARNING, + input_location, OPT_Wlong_long, + (flags & CPP_N_UNSIGNED) + ? "integer constant is too large for % type" + : "integer constant is too large for % type"); + } + + value = build_int_cst_wide (type, integer.low, integer.high); + + /* Convert imaginary to a complex type. */ + if (flags & CPP_N_IMAGINARY) + value = build_complex (NULL_TREE, build_int_cst (type, 0), value); + + return value; +} + +/* Interpret TOKEN, a floating point number with FLAGS as classified + by cpplib. */ +static tree +interpret_float (const cpp_token *token, unsigned int flags) +{ + tree type; + tree const_type; + tree value; + REAL_VALUE_TYPE real; + REAL_VALUE_TYPE real_trunc; + char *copy; + size_t copylen; + + /* Default (no suffix) depends on whether the FLOAT_CONST_DECIMAL64 + pragma has been used and is either double or _Decimal64. Types + that are not allowed with decimal float default to double. */ + if (flags & CPP_N_DEFAULT) + { + flags ^= CPP_N_DEFAULT; + flags |= CPP_N_MEDIUM; + + if (((flags & CPP_N_HEX) == 0) && ((flags & CPP_N_IMAGINARY) == 0)) + { + warning (OPT_Wunsuffixed_float_constants, + "unsuffixed float constant"); + if (float_const_decimal64_p ()) + flags |= CPP_N_DFLOAT; + } + } + + /* Decode _Fract and _Accum. */ + if (flags & CPP_N_FRACT || flags & CPP_N_ACCUM) + return interpret_fixed (token, flags); + + /* Decode type based on width and properties. */ + if (flags & CPP_N_DFLOAT) + if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) + type = dfloat128_type_node; + else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) + type = dfloat32_type_node; + else + type = dfloat64_type_node; + else + if (flags & CPP_N_WIDTH_MD) + { + char suffix; + enum machine_mode mode; + + if ((flags & CPP_N_WIDTH_MD) == CPP_N_MD_W) + suffix = 'w'; + else + suffix = 'q'; + + mode = targetm.c.mode_for_suffix (suffix); + if (mode == VOIDmode) + { + error ("unsupported non-standard suffix on floating constant"); + + return error_mark_node; + } + else + pedwarn (input_location, OPT_pedantic, "non-standard suffix on floating constant"); + + type = c_common_type_for_mode (mode, 0); + gcc_assert (type); + } + else if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) + type = long_double_type_node; + else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL + || flag_single_precision_constant) + type = float_type_node; + else + type = double_type_node; + + const_type = excess_precision_type (type); + if (!const_type) + const_type = type; + + /* Copy the constant to a nul-terminated buffer. If the constant + has any suffixes, cut them off; REAL_VALUE_ATOF/ REAL_VALUE_HTOF + can't handle them. */ + copylen = token->val.str.len; + if (flags & CPP_N_DFLOAT) + copylen -= 2; + else + { + if ((flags & CPP_N_WIDTH) != CPP_N_MEDIUM) + /* Must be an F or L or machine defined suffix. */ + copylen--; + if (flags & CPP_N_IMAGINARY) + /* I or J suffix. */ + copylen--; + } + + copy = (char *) alloca (copylen + 1); + memcpy (copy, token->val.str.text, copylen); + copy[copylen] = '\0'; + + real_from_string3 (&real, copy, TYPE_MODE (const_type)); + if (const_type != type) + /* Diagnosing if the result of converting the value with excess + precision to the semantic type would overflow (with associated + double rounding) is more appropriate than diagnosing if the + result of converting the string directly to the semantic type + would overflow. */ + real_convert (&real_trunc, TYPE_MODE (type), &real); + + /* Both C and C++ require a diagnostic for a floating constant + outside the range of representable values of its type. Since we + have __builtin_inf* to produce an infinity, this is now a + mandatory pedwarn if the target does not support infinities. */ + if (REAL_VALUE_ISINF (real) + || (const_type != type && REAL_VALUE_ISINF (real_trunc))) + { + if (!MODE_HAS_INFINITIES (TYPE_MODE (type))) + pedwarn (input_location, 0, "floating constant exceeds range of %qT", type); + else + warning (OPT_Woverflow, "floating constant exceeds range of %qT", type); + } + /* We also give a warning if the value underflows. */ + else if (REAL_VALUES_EQUAL (real, dconst0) + || (const_type != type && REAL_VALUES_EQUAL (real_trunc, dconst0))) + { + REAL_VALUE_TYPE realvoidmode; + int overflow = real_from_string (&realvoidmode, copy); + if (overflow < 0 || !REAL_VALUES_EQUAL (realvoidmode, dconst0)) + warning (OPT_Woverflow, "floating constant truncated to zero"); + } + + /* Create a node with determined type and value. */ + value = build_real (const_type, real); + if (flags & CPP_N_IMAGINARY) + value = build_complex (NULL_TREE, convert (const_type, integer_zero_node), + value); + + if (type != const_type) + value = build1 (EXCESS_PRECISION_EXPR, type, value); + + return value; +} + +/* Interpret TOKEN, a fixed-point number with FLAGS as classified + by cpplib. */ + +static tree +interpret_fixed (const cpp_token *token, unsigned int flags) +{ + tree type; + tree value; + FIXED_VALUE_TYPE fixed; + char *copy; + size_t copylen; + + copylen = token->val.str.len; + + if (flags & CPP_N_FRACT) /* _Fract. */ + { + if (flags & CPP_N_UNSIGNED) /* Unsigned _Fract. */ + { + if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) + { + type = unsigned_long_long_fract_type_node; + copylen -= 4; + } + else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) + { + type = unsigned_long_fract_type_node; + copylen -= 3; + } + else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) + { + type = unsigned_short_fract_type_node; + copylen -= 3; + } + else + { + type = unsigned_fract_type_node; + copylen -= 2; + } + } + else /* Signed _Fract. */ + { + if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) + { + type = long_long_fract_type_node; + copylen -= 3; + } + else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) + { + type = long_fract_type_node; + copylen -= 2; + } + else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) + { + type = short_fract_type_node; + copylen -= 2; + } + else + { + type = fract_type_node; + copylen --; + } + } + } + else /* _Accum. */ + { + if (flags & CPP_N_UNSIGNED) /* Unsigned _Accum. */ + { + if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) + { + type = unsigned_long_long_accum_type_node; + copylen -= 4; + } + else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) + { + type = unsigned_long_accum_type_node; + copylen -= 3; + } + else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) + { + type = unsigned_short_accum_type_node; + copylen -= 3; + } + else + { + type = unsigned_accum_type_node; + copylen -= 2; + } + } + else /* Signed _Accum. */ + { + if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) + { + type = long_long_accum_type_node; + copylen -= 3; + } + else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) + { + type = long_accum_type_node; + copylen -= 2; + } + else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) + { + type = short_accum_type_node; + copylen -= 2; + } + else + { + type = accum_type_node; + copylen --; + } + } + } + + copy = (char *) alloca (copylen + 1); + memcpy (copy, token->val.str.text, copylen); + copy[copylen] = '\0'; + + fixed_from_string (&fixed, copy, TYPE_MODE (type)); + + /* Create a node with determined type and value. */ + value = build_fixed (type, fixed); + + return value; +} + +/* Convert a series of STRING, WSTRING, STRING16, STRING32 and/or + UTF8STRING tokens into a tree, performing string constant + concatenation. TOK is the first of these. VALP is the location + to write the string into. OBJC_STRING indicates whether an '@' token + preceded the incoming token. + Returns the CPP token type of the result (CPP_STRING, CPP_WSTRING, + CPP_STRING32, CPP_STRING16, CPP_UTF8STRING, or CPP_OBJC_STRING). + + This is unfortunately more work than it should be. If any of the + strings in the series has an L prefix, the result is a wide string + (6.4.5p4). Whether or not the result is a wide string affects the + meaning of octal and hexadecimal escapes (6.4.4.4p6,9). But escape + sequences do not continue across the boundary between two strings in + a series (6.4.5p7), so we must not lose the boundaries. Therefore + cpp_interpret_string takes a vector of cpp_string structures, which + we must arrange to provide. */ + +static enum cpp_ttype +lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate) +{ + tree value; + size_t concats = 0; + struct obstack str_ob; + cpp_string istr; + enum cpp_ttype type = tok->type; + + /* Try to avoid the overhead of creating and destroying an obstack + for the common case of just one string. */ + cpp_string str = tok->val.str; + cpp_string *strs = &str; + + retry: + tok = cpp_get_token (parse_in); + switch (tok->type) + { + case CPP_PADDING: + goto retry; + case CPP_ATSIGN: + if (c_dialect_objc ()) + { + objc_string = true; + goto retry; + } + /* FALLTHROUGH */ + + default: + break; + + case CPP_WSTRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_UTF8STRING: + if (type != tok->type) + { + if (type == CPP_STRING) + type = tok->type; + else + error ("unsupported non-standard concatenation of string literals"); + } + + case CPP_STRING: + if (!concats) + { + gcc_obstack_init (&str_ob); + obstack_grow (&str_ob, &str, sizeof (cpp_string)); + } + + concats++; + obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string)); + goto retry; + } + + /* We have read one more token than we want. */ + _cpp_backup_tokens (parse_in, 1); + if (concats) + strs = XOBFINISH (&str_ob, cpp_string *); + + if (concats && !objc_string && !in_system_header) + warning (OPT_Wtraditional, + "traditional C rejects string constant concatenation"); + + if ((translate + ? cpp_interpret_string : cpp_interpret_string_notranslate) + (parse_in, strs, concats + 1, &istr, type)) + { + value = build_string (istr.len, (const char *) istr.text); + free (CONST_CAST (unsigned char *, istr.text)); + } + else + { + /* Callers cannot generally handle error_mark_node in this context, + so return the empty string instead. cpp_interpret_string has + issued an error. */ + 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; + } + *valp = fix_string_type (value); + + if (concats) + obstack_free (&str_ob, 0); + + return objc_string ? CPP_OBJC_STRING : type; +} + +/* Converts a (possibly wide) character constant token into a tree. */ +static tree +lex_charconst (const cpp_token *token) +{ + cppchar_t result; + tree type, value; + unsigned int chars_seen; + int unsignedp = 0; + + result = cpp_interpret_charconst (parse_in, token, + &chars_seen, &unsignedp); + + if (token->type == CPP_WCHAR) + type = wchar_type_node; + else if (token->type == CPP_CHAR32) + type = char32_type_node; + else if (token->type == CPP_CHAR16) + type = char16_type_node; + /* In C, a character constant has type 'int'. + In C++ 'char', but multi-char charconsts have type 'int'. */ + else if (!c_dialect_cxx () || chars_seen > 1) + type = integer_type_node; + else + type = char_type_node; + + /* Cast to cppchar_signed_t to get correct sign-extension of RESULT + before possibly widening to HOST_WIDE_INT for build_int_cst. */ + if (unsignedp || (cppchar_signed_t) result >= 0) + value = build_int_cst_wide (type, result, 0); + else + value = build_int_cst_wide (type, (cppchar_signed_t) result, -1); + + return value; +} diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c new file mode 100644 index 0000000..31970bd --- /dev/null +++ b/gcc/c-family/c-omp.c @@ -0,0 +1,531 @@ +/* This file contains routines to construct GNU OpenMP constructs, + called from parsing in the C and C++ front ends. + + Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + Contributed by Richard Henderson , + Diego Novillo . + +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 "tree.h" +#include "c-common.h" +#include "toplev.h" +#include "gimple.h" /* For create_tmp_var_raw. */ +#include "langhooks.h" + + +/* Complete a #pragma omp master construct. STMT is the structured-block + that follows the pragma. LOC is the l*/ + +tree +c_finish_omp_master (location_t loc, tree stmt) +{ + tree t = add_stmt (build1 (OMP_MASTER, void_type_node, stmt)); + SET_EXPR_LOCATION (t, loc); + return t; +} + +/* Complete a #pragma omp critical construct. STMT is the structured-block + that follows the pragma, NAME is the identifier in the pragma, or null + if it was omitted. LOC is the location of the #pragma. */ + +tree +c_finish_omp_critical (location_t loc, tree body, tree name) +{ + tree stmt = make_node (OMP_CRITICAL); + TREE_TYPE (stmt) = void_type_node; + OMP_CRITICAL_BODY (stmt) = body; + OMP_CRITICAL_NAME (stmt) = name; + SET_EXPR_LOCATION (stmt, loc); + return add_stmt (stmt); +} + +/* Complete a #pragma omp ordered construct. STMT is the structured-block + that follows the pragma. LOC is the location of the #pragma. */ + +tree +c_finish_omp_ordered (location_t loc, tree stmt) +{ + tree t = build1 (OMP_ORDERED, void_type_node, stmt); + SET_EXPR_LOCATION (t, loc); + return add_stmt (t); +} + + +/* Complete a #pragma omp barrier construct. LOC is the location of + the #pragma. */ + +void +c_finish_omp_barrier (location_t loc) +{ + tree x; + + x = built_in_decls[BUILT_IN_GOMP_BARRIER]; + x = build_call_expr_loc (loc, x, 0); + add_stmt (x); +} + + +/* Complete a #pragma omp taskwait construct. LOC is the location of the + pragma. */ + +void +c_finish_omp_taskwait (location_t loc) +{ + tree x; + + x = built_in_decls[BUILT_IN_GOMP_TASKWAIT]; + x = build_call_expr_loc (loc, x, 0); + add_stmt (x); +} + + +/* Complete a #pragma omp atomic construct. The expression to be + implemented atomically is LHS code= RHS. LOC is the location of + the atomic statement. The value returned is either error_mark_node + (if the construct was erroneous) or an OMP_ATOMIC node which should + be added to the current statement tree with add_stmt.*/ + +tree +c_finish_omp_atomic (location_t loc, enum tree_code code, tree lhs, tree rhs) +{ + tree x, type, addr; + + if (lhs == error_mark_node || rhs == error_mark_node) + return error_mark_node; + + /* ??? According to one reading of the OpenMP spec, complex type are + supported, but there are no atomic stores for any architecture. + But at least icc 9.0 doesn't support complex types here either. + And lets not even talk about vector types... */ + type = TREE_TYPE (lhs); + if (!INTEGRAL_TYPE_P (type) + && !POINTER_TYPE_P (type) + && !SCALAR_FLOAT_TYPE_P (type)) + { + error_at (loc, "invalid expression type for %<#pragma omp atomic%>"); + return error_mark_node; + } + + /* ??? Validate that rhs does not overlap lhs. */ + + /* Take and save the address of the lhs. From then on we'll reference it + via indirection. */ + addr = build_unary_op (loc, ADDR_EXPR, lhs, 0); + if (addr == error_mark_node) + return error_mark_node; + addr = save_expr (addr); + if (TREE_CODE (addr) != SAVE_EXPR + && (TREE_CODE (addr) != ADDR_EXPR + || TREE_CODE (TREE_OPERAND (addr, 0)) != VAR_DECL)) + { + /* Make sure LHS is simple enough so that goa_lhs_expr_p can recognize + it even after unsharing function body. */ + tree var = create_tmp_var_raw (TREE_TYPE (addr), NULL); + DECL_CONTEXT (var) = current_function_decl; + addr = build4 (TARGET_EXPR, TREE_TYPE (addr), var, addr, NULL, NULL); + } + lhs = build_indirect_ref (loc, addr, RO_NULL); + + /* There are lots of warnings, errors, and conversions that need to happen + in the course of interpreting a statement. Use the normal mechanisms + to do this, and then take it apart again. */ + x = build_modify_expr (input_location, lhs, NULL_TREE, code, + input_location, rhs, NULL_TREE); + if (x == error_mark_node) + return error_mark_node; + gcc_assert (TREE_CODE (x) == MODIFY_EXPR); + rhs = TREE_OPERAND (x, 1); + + /* Punt the actual generation of atomic operations to common code. */ + x = build2 (OMP_ATOMIC, void_type_node, addr, rhs); + SET_EXPR_LOCATION (x, loc); + return x; +} + + +/* Complete a #pragma omp flush construct. We don't do anything with + the variable list that the syntax allows. LOC is the location of + the #pragma. */ + +void +c_finish_omp_flush (location_t loc) +{ + tree x; + + x = built_in_decls[BUILT_IN_SYNCHRONIZE]; + x = build_call_expr_loc (loc, x, 0); + add_stmt (x); +} + + +/* Check and canonicalize #pragma omp for increment expression. + Helper function for c_finish_omp_for. */ + +static tree +check_omp_for_incr_expr (location_t loc, tree exp, tree decl) +{ + tree t; + + if (!INTEGRAL_TYPE_P (TREE_TYPE (exp)) + || TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (decl))) + return error_mark_node; + + if (exp == decl) + return build_int_cst (TREE_TYPE (exp), 0); + + switch (TREE_CODE (exp)) + { + CASE_CONVERT: + t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl); + if (t != error_mark_node) + return fold_convert_loc (loc, TREE_TYPE (exp), t); + break; + case MINUS_EXPR: + t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl); + if (t != error_mark_node) + return fold_build2_loc (loc, MINUS_EXPR, + TREE_TYPE (exp), t, TREE_OPERAND (exp, 1)); + break; + case PLUS_EXPR: + t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl); + if (t != error_mark_node) + return fold_build2_loc (loc, PLUS_EXPR, + TREE_TYPE (exp), t, TREE_OPERAND (exp, 1)); + t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 1), decl); + if (t != error_mark_node) + return fold_build2_loc (loc, PLUS_EXPR, + TREE_TYPE (exp), TREE_OPERAND (exp, 0), t); + break; + default: + break; + } + + return error_mark_node; +} + +/* Validate and emit code for the OpenMP directive #pragma omp for. + DECLV is a vector of iteration variables, for each collapsed loop. + INITV, CONDV and INCRV are vectors containing initialization + expressions, controlling predicates and increment expressions. + BODY is the body of the loop and PRE_BODY statements that go before + the loop. */ + +tree +c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv, + tree incrv, tree body, tree pre_body) +{ + location_t elocus; + bool fail = false; + int i; + + gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv)); + gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv)); + gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (incrv)); + for (i = 0; i < TREE_VEC_LENGTH (declv); i++) + { + tree decl = TREE_VEC_ELT (declv, i); + tree init = TREE_VEC_ELT (initv, i); + tree cond = TREE_VEC_ELT (condv, i); + tree incr = TREE_VEC_ELT (incrv, i); + + elocus = locus; + if (EXPR_HAS_LOCATION (init)) + elocus = EXPR_LOCATION (init); + + /* Validate the iteration variable. */ + if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)) + && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE) + { + error_at (elocus, "invalid type for iteration variable %qE", decl); + fail = true; + } + + /* In the case of "for (int i = 0...)", init will be a decl. It should + have a DECL_INITIAL that we can turn into an assignment. */ + if (init == decl) + { + elocus = DECL_SOURCE_LOCATION (decl); + + init = DECL_INITIAL (decl); + if (init == NULL) + { + error_at (elocus, "%qE is not initialized", decl); + init = integer_zero_node; + fail = true; + } + + init = build_modify_expr (elocus, decl, NULL_TREE, NOP_EXPR, + /* FIXME diagnostics: This should + be the location of the INIT. */ + elocus, + init, + NULL_TREE); + } + gcc_assert (TREE_CODE (init) == MODIFY_EXPR); + gcc_assert (TREE_OPERAND (init, 0) == decl); + + if (cond == NULL_TREE) + { + error_at (elocus, "missing controlling predicate"); + fail = true; + } + else + { + bool cond_ok = false; + + if (EXPR_HAS_LOCATION (cond)) + elocus = EXPR_LOCATION (cond); + + if (TREE_CODE (cond) == LT_EXPR + || TREE_CODE (cond) == LE_EXPR + || TREE_CODE (cond) == GT_EXPR + || TREE_CODE (cond) == GE_EXPR + || TREE_CODE (cond) == NE_EXPR + || TREE_CODE (cond) == EQ_EXPR) + { + tree op0 = TREE_OPERAND (cond, 0); + tree op1 = TREE_OPERAND (cond, 1); + + /* 2.5.1. The comparison in the condition is computed in + the type of DECL, otherwise the behavior is undefined. + + For example: + long n; int i; + i < n; + + according to ISO will be evaluated as: + (long)i < n; + + We want to force: + i < (int)n; */ + if (TREE_CODE (op0) == NOP_EXPR + && decl == TREE_OPERAND (op0, 0)) + { + TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0); + TREE_OPERAND (cond, 1) + = fold_build1_loc (elocus, NOP_EXPR, TREE_TYPE (decl), + TREE_OPERAND (cond, 1)); + } + else if (TREE_CODE (op1) == NOP_EXPR + && decl == TREE_OPERAND (op1, 0)) + { + TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0); + TREE_OPERAND (cond, 0) + = fold_build1_loc (elocus, NOP_EXPR, TREE_TYPE (decl), + TREE_OPERAND (cond, 0)); + } + + if (decl == TREE_OPERAND (cond, 0)) + cond_ok = true; + else if (decl == TREE_OPERAND (cond, 1)) + { + TREE_SET_CODE (cond, + swap_tree_comparison (TREE_CODE (cond))); + TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0); + TREE_OPERAND (cond, 0) = decl; + cond_ok = true; + } + + if (TREE_CODE (cond) == NE_EXPR + || TREE_CODE (cond) == EQ_EXPR) + { + if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))) + cond_ok = false; + else if (operand_equal_p (TREE_OPERAND (cond, 1), + TYPE_MIN_VALUE (TREE_TYPE (decl)), + 0)) + TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR + ? GT_EXPR : LE_EXPR); + else if (operand_equal_p (TREE_OPERAND (cond, 1), + TYPE_MAX_VALUE (TREE_TYPE (decl)), + 0)) + TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR + ? LT_EXPR : GE_EXPR); + else + cond_ok = false; + } + } + + if (!cond_ok) + { + error_at (elocus, "invalid controlling predicate"); + fail = true; + } + } + + if (incr == NULL_TREE) + { + error_at (elocus, "missing increment expression"); + fail = true; + } + else + { + bool incr_ok = false; + + if (EXPR_HAS_LOCATION (incr)) + elocus = EXPR_LOCATION (incr); + + /* Check all the valid increment expressions: v++, v--, ++v, --v, + v = v + incr, v = incr + v and v = v - incr. */ + switch (TREE_CODE (incr)) + { + case POSTINCREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case PREDECREMENT_EXPR: + if (TREE_OPERAND (incr, 0) != decl) + break; + + incr_ok = true; + if (POINTER_TYPE_P (TREE_TYPE (decl)) + && TREE_OPERAND (incr, 1)) + { + tree t = fold_convert_loc (elocus, + sizetype, TREE_OPERAND (incr, 1)); + + if (TREE_CODE (incr) == POSTDECREMENT_EXPR + || TREE_CODE (incr) == PREDECREMENT_EXPR) + t = fold_build1_loc (elocus, NEGATE_EXPR, sizetype, t); + t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (decl), decl, t); + incr = build2 (MODIFY_EXPR, void_type_node, decl, t); + } + break; + + case MODIFY_EXPR: + if (TREE_OPERAND (incr, 0) != decl) + break; + if (TREE_OPERAND (incr, 1) == decl) + break; + if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR + && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl + || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl)) + incr_ok = true; + else if ((TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR + || (TREE_CODE (TREE_OPERAND (incr, 1)) + == POINTER_PLUS_EXPR)) + && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl) + incr_ok = true; + else + { + tree t = check_omp_for_incr_expr (elocus, + TREE_OPERAND (incr, 1), + decl); + if (t != error_mark_node) + { + incr_ok = true; + t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t); + incr = build2 (MODIFY_EXPR, void_type_node, decl, t); + } + } + break; + + default: + break; + } + if (!incr_ok) + { + error_at (elocus, "invalid increment expression"); + fail = true; + } + } + + TREE_VEC_ELT (initv, i) = init; + TREE_VEC_ELT (incrv, i) = incr; + } + + if (fail) + return NULL; + else + { + tree t = make_node (OMP_FOR); + + TREE_TYPE (t) = void_type_node; + OMP_FOR_INIT (t) = initv; + OMP_FOR_COND (t) = condv; + OMP_FOR_INCR (t) = incrv; + OMP_FOR_BODY (t) = body; + OMP_FOR_PRE_BODY (t) = pre_body; + + SET_EXPR_LOCATION (t, locus); + return add_stmt (t); + } +} + + +/* Divide CLAUSES into two lists: those that apply to a parallel + construct, and those that apply to a work-sharing construct. Place + the results in *PAR_CLAUSES and *WS_CLAUSES respectively. In + addition, add a nowait clause to the work-sharing list. LOC is the + location of the OMP_PARALLEL*. */ + +void +c_split_parallel_clauses (location_t loc, tree clauses, + tree *par_clauses, tree *ws_clauses) +{ + tree next; + + *par_clauses = NULL; + *ws_clauses = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); + + for (; clauses ; clauses = next) + { + next = OMP_CLAUSE_CHAIN (clauses); + + switch (OMP_CLAUSE_CODE (clauses)) + { + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_SHARED: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LASTPRIVATE: + case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_COPYIN: + case OMP_CLAUSE_IF: + case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_DEFAULT: + OMP_CLAUSE_CHAIN (clauses) = *par_clauses; + *par_clauses = clauses; + break; + + case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_ORDERED: + case OMP_CLAUSE_COLLAPSE: + OMP_CLAUSE_CHAIN (clauses) = *ws_clauses; + *ws_clauses = clauses; + break; + + default: + gcc_unreachable (); + } + } +} + +/* True if OpenMP sharing attribute of DECL is predetermined. */ + +enum omp_clause_default_kind +c_omp_predetermined_sharing (tree decl) +{ + /* Variables with const-qualified type having no mutable member + are predetermined shared. */ + if (TREE_READONLY (decl)) + return OMP_CLAUSE_DEFAULT_SHARED; + + return OMP_CLAUSE_DEFAULT_UNSPECIFIED; +} diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c new file mode 100644 index 0000000..08592f5 --- /dev/null +++ b/gcc/c-family/c-opts.c @@ -0,0 +1,1815 @@ +/* C/ObjC/C++ command line option handling. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. + Contributed by Neil Booth. + +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 "tree.h" +#include "c-common.h" +#include "c-pragma.h" +#include "flags.h" +#include "toplev.h" +#include "langhooks.h" +#include "diagnostic.h" +#include "intl.h" +#include "cppdefault.h" +#include "incpath.h" +#include "debug.h" /* For debug_hooks. */ +#include "opts.h" +#include "options.h" +#include "mkdeps.h" +#include "target.h" /* For gcc_targetcm. */ + +#ifndef DOLLARS_IN_IDENTIFIERS +# define DOLLARS_IN_IDENTIFIERS true +#endif + +#ifndef TARGET_SYSTEM_ROOT +# define TARGET_SYSTEM_ROOT NULL +#endif + +#ifndef TARGET_OPTF +#define TARGET_OPTF(ARG) +#endif + +/* CPP's options. */ +cpp_options *cpp_opts; + +/* Input filename. */ +static const char *this_input_filename; + +/* Filename and stream for preprocessed output. */ +static const char *out_fname; +static FILE *out_stream; + +/* Append dependencies to deps_file. */ +static bool deps_append; + +/* If dependency switches (-MF etc.) have been given. */ +static bool deps_seen; + +/* If -v seen. */ +static bool verbose; + +/* Dependency output file. */ +static const char *deps_file; + +/* The prefix given by -iprefix, if any. */ +static const char *iprefix; + +/* The multilib directory given by -imultilib, if any. */ +static const char *imultilib; + +/* The system root, if any. Overridden by -isysroot. */ +static const char *sysroot = TARGET_SYSTEM_ROOT; + +/* Zero disables all standard directories for headers. */ +static bool std_inc = true; + +/* Zero disables the C++-specific standard directories for headers. */ +static bool std_cxx_inc = true; + +/* If the quote chain has been split by -I-. */ +static bool quote_chain_split; + +/* If -Wunused-macros. */ +static bool warn_unused_macros; + +/* If -Wvariadic-macros. */ +static bool warn_variadic_macros = true; + +/* Number of deferred options. */ +static size_t deferred_count; + +/* Number of deferred options scanned for -include. */ +static size_t include_cursor; + +static void handle_OPT_d (const char *); +static void set_std_cxx98 (int); +static void set_std_cxx0x (int); +static void set_std_c89 (int, int); +static void set_std_c99 (int); +static void set_std_c1x (int); +static void check_deps_environment_vars (void); +static void handle_deferred_opts (void); +static void sanitize_cpp_opts (void); +static void add_prefixed_path (const char *, size_t); +static void push_command_line_include (void); +static void cb_file_change (cpp_reader *, const struct line_map *); +static void cb_dir_change (cpp_reader *, const char *); +static void finish_options (void); + +#ifndef STDC_0_IN_SYSTEM_HEADERS +#define STDC_0_IN_SYSTEM_HEADERS 0 +#endif + +/* Holds switches parsed by c_common_handle_option (), but whose + handling is deferred to c_common_post_options (). */ +static void defer_opt (enum opt_code, const char *); +static struct deferred_opt +{ + enum opt_code code; + const char *arg; +} *deferred_opts; + + +static const unsigned int +c_family_lang_mask = (CL_C | CL_CXX | CL_ObjC | CL_ObjCXX); + +/* Complain that switch CODE expects an argument but none was + provided. OPT was the command-line option. Return FALSE to get + the default message in opts.c, TRUE if we provide a specialized + one. */ +bool +c_common_missing_argument (const char *opt, size_t code) +{ + switch (code) + { + default: + /* Pick up the default message. */ + return false; + + case OPT_fconstant_string_class_: + error ("no class name specified with %qs", opt); + break; + + case OPT_A: + error ("assertion missing after %qs", opt); + break; + + case OPT_D: + case OPT_U: + error ("macro name missing after %qs", opt); + break; + + case OPT_F: + case OPT_I: + case OPT_idirafter: + case OPT_isysroot: + case OPT_isystem: + case OPT_iquote: + error ("missing path after %qs", opt); + break; + + case OPT_MF: + case OPT_MD: + case OPT_MMD: + case OPT_include: + case OPT_imacros: + case OPT_o: + error ("missing filename after %qs", opt); + break; + + case OPT_MQ: + case OPT_MT: + error ("missing makefile target after %qs", opt); + break; + } + + return true; +} + +/* Defer option CODE with argument ARG. */ +static void +defer_opt (enum opt_code code, const char *arg) +{ + deferred_opts[deferred_count].code = code; + deferred_opts[deferred_count].arg = arg; + deferred_count++; +} + +/* -Werror= may set a warning option to enable a warning that is emitted + by the preprocessor. Set any corresponding flag in cpp_opts. */ + +static void +warning_as_error_callback (int option_index) +{ + switch (option_index) + { + default: + /* Ignore options not associated with the preprocessor. */ + break; + + case OPT_Wdeprecated: + cpp_opts->warn_deprecated = 1; + break; + + case OPT_Wcomment: + case OPT_Wcomments: + cpp_opts->warn_comments = 1; + break; + + case OPT_Wtrigraphs: + cpp_opts->warn_trigraphs = 1; + break; + + case OPT_Wmultichar: + cpp_opts->warn_multichar = 1; + break; + + case OPT_Wtraditional: + cpp_opts->warn_traditional = 1; + break; + + case OPT_Wlong_long: + cpp_opts->warn_long_long = 1; + break; + + case OPT_Wendif_labels: + cpp_opts->warn_endif_labels = 1; + break; + + case OPT_Wvariadic_macros: + /* Set the local flag that is used later to update cpp_opts. */ + warn_variadic_macros = 1; + break; + + case OPT_Wbuiltin_macro_redefined: + cpp_opts->warn_builtin_macro_redefined = 1; + break; + + case OPT_Wundef: + cpp_opts->warn_undef = 1; + break; + + case OPT_Wunused_macros: + /* Set the local flag that is used later to update cpp_opts. */ + warn_unused_macros = 1; + break; + + case OPT_Wc___compat: + /* Add warnings in the same way as c_common_handle_option below. */ + if (warn_enum_compare == -1) + warn_enum_compare = 1; + if (warn_jump_misses_init == -1) + warn_jump_misses_init = 1; + cpp_opts->warn_cxx_operator_names = 1; + break; + + case OPT_Wnormalized_: + inform (input_location, "-Werror=normalized=: Set -Wnormalized=nfc"); + cpp_opts->warn_normalize = normalized_C; + break; + + case OPT_Winvalid_pch: + cpp_opts->warn_invalid_pch = 1; + break; + + case OPT_Wcpp: + /* Handled by standard diagnostics using the option's associated + boolean variable. */ + break; + } +} + +/* Common initialization before parsing options. */ +unsigned int +c_common_init_options (unsigned int argc, const char **argv) +{ + static const unsigned int lang_flags[] = {CL_C, CL_ObjC, CL_CXX, CL_ObjCXX}; + unsigned int i, result; + struct cpp_callbacks *cb; + + /* Register callback for warnings enabled by -Werror=. */ + register_warning_as_error_callback (warning_as_error_callback); + + /* This is conditionalized only because that is the way the front + ends used to do it. Maybe this should be unconditional? */ + if (c_dialect_cxx ()) + { + /* By default wrap lines at 80 characters. Is getenv + ("COLUMNS") preferable? */ + diagnostic_line_cutoff (global_dc) = 80; + /* By default, emit location information once for every + diagnostic message. */ + diagnostic_prefixing_rule (global_dc) = DIAGNOSTICS_SHOW_PREFIX_ONCE; + } + + global_dc->opt_permissive = OPT_fpermissive; + + parse_in = cpp_create_reader (c_dialect_cxx () ? CLK_GNUCXX: CLK_GNUC89, + ident_hash, line_table); + cb = cpp_get_callbacks (parse_in); + cb->error = c_cpp_error; + + cpp_opts = cpp_get_options (parse_in); + cpp_opts->dollars_in_ident = DOLLARS_IN_IDENTIFIERS; + cpp_opts->objc = c_dialect_objc (); + + /* Reset to avoid warnings on internal definitions. We set it just + before passing on command-line options to cpplib. */ + cpp_opts->warn_dollars = 0; + + flag_exceptions = c_dialect_cxx (); + warn_pointer_arith = c_dialect_cxx (); + warn_write_strings = c_dialect_cxx(); + flag_warn_unused_result = true; + + /* By default, C99-like requirements for complex multiply and divide. */ + flag_complex_method = 2; + + deferred_opts = XNEWVEC (struct deferred_opt, argc); + + result = lang_flags[c_language]; + + if (c_language == clk_c) + { + /* If preprocessing assembly language, accept any of the C-family + front end options since the driver may pass them through. */ + for (i = 1; i < argc; i++) + if (! strcmp (argv[i], "-lang-asm")) + { + result |= CL_C | CL_ObjC | CL_CXX | CL_ObjCXX; + break; + } + } + + return result; +} + +/* Handle switch SCODE with argument ARG. VALUE is true, unless no- + form of an -f or -W option was given. Returns 0 if the switch was + invalid, a negative number to prevent language-independent + processing in toplev.c (a hack necessary for the short-term). */ +int +c_common_handle_option (size_t scode, const char *arg, int value, + int kind) +{ + const struct cl_option *option = &cl_options[scode]; + enum opt_code code = (enum opt_code) scode; + int result = 1; + + /* Prevent resetting the language standard to a C dialect when the driver + has already determined that we're looking at assembler input. */ + bool preprocessing_asm_p = (cpp_get_options (parse_in)->lang == CLK_ASM); + + switch (code) + { + default: + if (cl_options[code].flags & c_family_lang_mask) + { + if ((option->flags & CL_TARGET) + && ! targetcm.handle_c_option (scode, arg, value)) + result = 0; + break; + } + result = 0; + break; + + case OPT__output_pch_: + pch_file = arg; + break; + + case OPT_A: + defer_opt (code, arg); + break; + + case OPT_C: + cpp_opts->discard_comments = 0; + break; + + case OPT_CC: + cpp_opts->discard_comments = 0; + cpp_opts->discard_comments_in_macro_exp = 0; + break; + + case OPT_D: + defer_opt (code, arg); + break; + + case OPT_E: + flag_preprocess_only = 1; + break; + + case OPT_H: + cpp_opts->print_include_names = 1; + break; + + case OPT_F: + TARGET_OPTF (xstrdup (arg)); + break; + + case OPT_I: + if (strcmp (arg, "-")) + add_path (xstrdup (arg), BRACKET, 0, true); + else + { + if (quote_chain_split) + error ("-I- specified twice"); + quote_chain_split = true; + split_quote_chain (); + inform (input_location, "obsolete option -I- used, please use -iquote instead"); + } + break; + + case OPT_M: + case OPT_MM: + /* When doing dependencies with -M or -MM, suppress normal + preprocessed output, but still do -dM etc. as software + depends on this. Preprocessed output does occur if -MD, -MMD + or environment var dependency generation is used. */ + cpp_opts->deps.style = (code == OPT_M ? DEPS_SYSTEM: DEPS_USER); + flag_no_output = 1; + break; + + case OPT_MD: + case OPT_MMD: + cpp_opts->deps.style = (code == OPT_MD ? DEPS_SYSTEM: DEPS_USER); + cpp_opts->deps.need_preprocessor_output = true; + deps_file = arg; + break; + + case OPT_MF: + deps_seen = true; + deps_file = arg; + break; + + case OPT_MG: + deps_seen = true; + cpp_opts->deps.missing_files = true; + break; + + case OPT_MP: + deps_seen = true; + cpp_opts->deps.phony_targets = true; + break; + + case OPT_MQ: + case OPT_MT: + deps_seen = true; + defer_opt (code, arg); + break; + + case OPT_P: + flag_no_line_commands = 1; + break; + + case OPT_fworking_directory: + flag_working_directory = value; + break; + + case OPT_U: + defer_opt (code, arg); + break; + + case OPT_Wall: + warn_unused = value; + set_Wformat (value); + handle_option (OPT_Wimplicit, value, NULL, c_family_lang_mask, kind); + warn_char_subscripts = value; + warn_missing_braces = value; + warn_parentheses = value; + warn_return_type = value; + warn_sequence_point = value; /* Was C only. */ + warn_switch = value; + if (warn_strict_aliasing == -1) + set_Wstrict_aliasing (value); + warn_address = value; + if (warn_strict_overflow == -1) + warn_strict_overflow = value; + warn_array_bounds = value; + warn_volatile_register_var = value; + + /* Only warn about unknown pragmas that are not in system + headers. */ + warn_unknown_pragmas = value; + + warn_uninitialized = value; + + if (!c_dialect_cxx ()) + { + /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding + can turn it off only if it's not explicit. */ + if (warn_main == -1) + warn_main = (value ? 2 : 0); + + /* In C, -Wall turns on -Wenum-compare, which we do here. + In C++ it is on by default, which is done in + c_common_post_options. */ + if (warn_enum_compare == -1) + warn_enum_compare = value; + } + else + { + /* C++-specific warnings. */ + warn_sign_compare = value; + warn_reorder = value; + warn_cxx0x_compat = value; + } + + cpp_opts->warn_trigraphs = value; + cpp_opts->warn_comments = value; + cpp_opts->warn_num_sign_change = value; + + if (warn_pointer_sign == -1) + warn_pointer_sign = value; + break; + + case OPT_Wbuiltin_macro_redefined: + cpp_opts->warn_builtin_macro_redefined = value; + break; + + case OPT_Wcomment: + case OPT_Wcomments: + cpp_opts->warn_comments = value; + break; + + case OPT_Wc___compat: + /* Because -Wenum-compare is the default in C++, -Wc++-compat + implies -Wenum-compare. */ + if (warn_enum_compare == -1 && value) + warn_enum_compare = value; + /* Because C++ always warns about a goto which misses an + initialization, -Wc++-compat turns on -Wjump-misses-init. */ + if (warn_jump_misses_init == -1 && value) + warn_jump_misses_init = value; + cpp_opts->warn_cxx_operator_names = value; + break; + + case OPT_Wdeprecated: + cpp_opts->warn_deprecated = value; + break; + + case OPT_Wendif_labels: + cpp_opts->warn_endif_labels = value; + break; + + case OPT_Werror: + global_dc->warning_as_error_requested = value; + break; + + case OPT_Werror_implicit_function_declaration: + /* For backward compatibility, this is the same as + -Werror=implicit-function-declaration. */ + enable_warning_as_error ("implicit-function-declaration", value, CL_C | CL_ObjC); + break; + + case OPT_Wformat: + set_Wformat (value); + break; + + case OPT_Wformat_: + set_Wformat (atoi (arg)); + break; + + case OPT_Wimplicit: + gcc_assert (value == 0 || value == 1); + if (warn_implicit_int == -1) + handle_option (OPT_Wimplicit_int, value, NULL, + c_family_lang_mask, kind); + if (warn_implicit_function_declaration == -1) + handle_option (OPT_Wimplicit_function_declaration, value, NULL, + c_family_lang_mask, kind); + break; + + case OPT_Wimport: + /* Silently ignore for now. */ + break; + + case OPT_Winvalid_pch: + cpp_opts->warn_invalid_pch = value; + break; + + case OPT_Wmissing_include_dirs: + cpp_opts->warn_missing_include_dirs = value; + break; + + case OPT_Wmultichar: + cpp_opts->warn_multichar = value; + break; + + case OPT_Wnormalized_: + if (!value || (arg && strcasecmp (arg, "none") == 0)) + cpp_opts->warn_normalize = normalized_none; + else if (!arg || strcasecmp (arg, "nfkc") == 0) + cpp_opts->warn_normalize = normalized_KC; + else if (strcasecmp (arg, "id") == 0) + cpp_opts->warn_normalize = normalized_identifier_C; + else if (strcasecmp (arg, "nfc") == 0) + cpp_opts->warn_normalize = normalized_C; + else + error ("argument %qs to %<-Wnormalized%> not recognized", arg); + break; + + case OPT_Wreturn_type: + warn_return_type = value; + break; + + case OPT_Wstrict_null_sentinel: + warn_strict_null_sentinel = value; + break; + + case OPT_Wtraditional: + cpp_opts->warn_traditional = value; + break; + + case OPT_Wtrigraphs: + cpp_opts->warn_trigraphs = value; + break; + + case OPT_Wundef: + cpp_opts->warn_undef = value; + break; + + case OPT_Wunknown_pragmas: + /* Set to greater than 1, so that even unknown pragmas in + system headers will be warned about. */ + warn_unknown_pragmas = value * 2; + break; + + case OPT_Wunused_macros: + warn_unused_macros = value; + break; + + case OPT_Wvariadic_macros: + warn_variadic_macros = value; + break; + + case OPT_Wwrite_strings: + warn_write_strings = value; + break; + + case OPT_Weffc__: + warn_ecpp = value; + if (value) + warn_nonvdtor = true; + break; + + case OPT_ansi: + if (!c_dialect_cxx ()) + set_std_c89 (false, true); + else + set_std_cxx98 (true); + break; + + case OPT_d: + handle_OPT_d (arg); + break; + + case OPT_fcond_mismatch: + if (!c_dialect_cxx ()) + { + flag_cond_mismatch = value; + break; + } + /* Fall through. */ + + case OPT_fall_virtual: + case OPT_falt_external_templates: + case OPT_fenum_int_equiv: + case OPT_fexternal_templates: + case OPT_fguiding_decls: + case OPT_fhonor_std: + case OPT_fhuge_objects: + case OPT_flabels_ok: + case OPT_fname_mangling_version_: + case OPT_fnew_abi: + case OPT_fnonnull_objects: + case OPT_fsquangle: + case OPT_fstrict_prototype: + case OPT_fthis_is_variable: + case OPT_fvtable_thunks: + case OPT_fxref: + case OPT_fvtable_gc: + warning (0, "switch %qs is no longer supported", option->opt_text); + break; + + case OPT_faccess_control: + flag_access_control = value; + break; + + case OPT_fasm: + flag_no_asm = !value; + break; + + case OPT_fbuiltin: + flag_no_builtin = !value; + break; + + case OPT_fbuiltin_: + if (value) + result = 0; + else + disable_builtin_function (arg); + break; + + case OPT_fdirectives_only: + cpp_opts->directives_only = value; + break; + + case OPT_fdollars_in_identifiers: + cpp_opts->dollars_in_ident = value; + break; + + case OPT_ffreestanding: + value = !value; + /* Fall through.... */ + case OPT_fhosted: + flag_hosted = value; + flag_no_builtin = !value; + break; + + case OPT_fshort_double: + flag_short_double = value; + break; + + case OPT_fshort_enums: + flag_short_enums = value; + break; + + case OPT_fshort_wchar: + flag_short_wchar = value; + break; + + case OPT_fsigned_bitfields: + flag_signed_bitfields = value; + break; + + case OPT_fsigned_char: + flag_signed_char = value; + break; + + case OPT_funsigned_bitfields: + flag_signed_bitfields = !value; + break; + + case OPT_funsigned_char: + flag_signed_char = !value; + break; + + case OPT_fcheck_new: + flag_check_new = value; + break; + + case OPT_fconserve_space: + flag_conserve_space = value; + break; + + case OPT_fconstant_string_class_: + constant_string_class_name = arg; + break; + + case OPT_fdefault_inline: + flag_default_inline = value; + break; + + case OPT_felide_constructors: + flag_elide_constructors = value; + break; + + case OPT_fenforce_eh_specs: + flag_enforce_eh_specs = value; + break; + + case OPT_fextended_identifiers: + cpp_opts->extended_identifiers = value; + break; + + case OPT_ffor_scope: + flag_new_for_scope = value; + break; + + case OPT_fgnu_keywords: + flag_no_gnu_keywords = !value; + break; + + case OPT_fgnu_runtime: + flag_next_runtime = !value; + break; + + case OPT_fhandle_exceptions: + warning (0, "-fhandle-exceptions has been renamed -fexceptions (and is now on by default)"); + flag_exceptions = value; + break; + + case OPT_fimplement_inlines: + flag_implement_inlines = value; + break; + + case OPT_fimplicit_inline_templates: + flag_implicit_inline_templates = value; + break; + + case OPT_fimplicit_templates: + flag_implicit_templates = value; + break; + + case OPT_flax_vector_conversions: + flag_lax_vector_conversions = value; + break; + + case OPT_fms_extensions: + flag_ms_extensions = value; + break; + + case OPT_fnext_runtime: + flag_next_runtime = value; + break; + + case OPT_fnil_receivers: + flag_nil_receivers = value; + break; + + case OPT_fnonansi_builtins: + flag_no_nonansi_builtin = !value; + break; + + case OPT_foperator_names: + cpp_opts->operator_names = value; + break; + + case OPT_foptional_diags: + flag_optional_diags = value; + break; + + case OPT_fpch_deps: + cpp_opts->restore_pch_deps = value; + break; + + case OPT_fpch_preprocess: + flag_pch_preprocess = value; + break; + + case OPT_fpermissive: + flag_permissive = value; + global_dc->permissive = value; + break; + + case OPT_fpreprocessed: + cpp_opts->preprocessed = value; + break; + + case OPT_freplace_objc_classes: + flag_replace_objc_classes = value; + break; + + case OPT_frepo: + flag_use_repository = value; + if (value) + flag_implicit_templates = 0; + break; + + case OPT_frtti: + flag_rtti = value; + break; + + case OPT_fshow_column: + cpp_opts->show_column = value; + break; + + case OPT_fstats: + flag_detailed_statistics = value; + break; + + case OPT_ftabstop_: + /* It is documented that we silently ignore silly values. */ + if (value >= 1 && value <= 100) + cpp_opts->tabstop = value; + break; + + case OPT_fexec_charset_: + cpp_opts->narrow_charset = arg; + break; + + case OPT_fwide_exec_charset_: + cpp_opts->wide_charset = arg; + break; + + case OPT_finput_charset_: + cpp_opts->input_charset = arg; + break; + + case OPT_ftemplate_depth_: + /* Kept for backwards compatibility. */ + case OPT_ftemplate_depth_eq: + max_tinst_depth = value; + break; + + case OPT_fuse_cxa_atexit: + flag_use_cxa_atexit = value; + break; + + case OPT_fuse_cxa_get_exception_ptr: + flag_use_cxa_get_exception_ptr = value; + break; + + case OPT_fvisibility_inlines_hidden: + visibility_options.inlines_hidden = value; + break; + + case OPT_fweak: + flag_weak = value; + break; + + case OPT_fthreadsafe_statics: + flag_threadsafe_statics = value; + break; + + case OPT_fpretty_templates: + flag_pretty_templates = value; + break; + + case OPT_fzero_link: + flag_zero_link = value; + break; + + case OPT_gen_decls: + flag_gen_declaration = 1; + break; + + case OPT_femit_struct_debug_baseonly: + set_struct_debug_option ("base"); + break; + + case OPT_femit_struct_debug_reduced: + set_struct_debug_option ("dir:ord:sys,dir:gen:any,ind:base"); + break; + + case OPT_femit_struct_debug_detailed_: + set_struct_debug_option (arg); + break; + + case OPT_idirafter: + add_path (xstrdup (arg), AFTER, 0, true); + break; + + case OPT_imacros: + case OPT_include: + defer_opt (code, arg); + break; + + case OPT_imultilib: + imultilib = arg; + break; + + case OPT_iprefix: + iprefix = arg; + break; + + case OPT_iquote: + add_path (xstrdup (arg), QUOTE, 0, true); + break; + + case OPT_isysroot: + sysroot = arg; + break; + + case OPT_isystem: + add_path (xstrdup (arg), SYSTEM, 0, true); + break; + + case OPT_iwithprefix: + add_prefixed_path (arg, SYSTEM); + break; + + case OPT_iwithprefixbefore: + add_prefixed_path (arg, BRACKET); + break; + + case OPT_lang_asm: + cpp_set_lang (parse_in, CLK_ASM); + cpp_opts->dollars_in_ident = false; + break; + + case OPT_lang_objc: + cpp_opts->objc = 1; + break; + + case OPT_nostdinc: + std_inc = false; + break; + + case OPT_nostdinc__: + std_cxx_inc = false; + break; + + case OPT_o: + if (!out_fname) + out_fname = arg; + else + error ("output filename specified twice"); + break; + + /* We need to handle the -pedantic switches here, rather than in + c_common_post_options, so that a subsequent -Wno-endif-labels + is not overridden. */ + case OPT_pedantic_errors: + case OPT_pedantic: + cpp_opts->pedantic = 1; + cpp_opts->warn_endif_labels = 1; + if (warn_pointer_sign == -1) + warn_pointer_sign = 1; + if (warn_overlength_strings == -1) + warn_overlength_strings = 1; + if (warn_main == -1) + warn_main = 2; + break; + + case OPT_print_objc_runtime_info: + print_struct_values = 1; + break; + + case OPT_print_pch_checksum: + c_common_print_pch_checksum (stdout); + exit_after_options = true; + break; + + case OPT_remap: + cpp_opts->remap = 1; + break; + + case OPT_std_c__98: + case OPT_std_gnu__98: + if (!preprocessing_asm_p) + set_std_cxx98 (code == OPT_std_c__98 /* ISO */); + break; + + case OPT_std_c__0x: + case OPT_std_gnu__0x: + if (!preprocessing_asm_p) + set_std_cxx0x (code == OPT_std_c__0x /* ISO */); + break; + + case OPT_std_c89: + case OPT_std_c90: + case OPT_std_iso9899_1990: + case OPT_std_iso9899_199409: + if (!preprocessing_asm_p) + set_std_c89 (code == OPT_std_iso9899_199409 /* c94 */, true /* ISO */); + break; + + case OPT_std_gnu89: + case OPT_std_gnu90: + if (!preprocessing_asm_p) + set_std_c89 (false /* c94 */, false /* ISO */); + break; + + case OPT_std_c99: + case OPT_std_c9x: + case OPT_std_iso9899_1999: + case OPT_std_iso9899_199x: + if (!preprocessing_asm_p) + set_std_c99 (true /* ISO */); + break; + + case OPT_std_gnu99: + case OPT_std_gnu9x: + if (!preprocessing_asm_p) + set_std_c99 (false /* ISO */); + break; + + case OPT_std_c1x: + if (!preprocessing_asm_p) + set_std_c1x (true /* ISO */); + break; + + case OPT_std_gnu1x: + if (!preprocessing_asm_p) + set_std_c1x (false /* ISO */); + break; + + case OPT_trigraphs: + cpp_opts->trigraphs = 1; + break; + + case OPT_traditional_cpp: + cpp_opts->traditional = 1; + break; + + case OPT_undef: + flag_undef = 1; + break; + + case OPT_v: + verbose = true; + break; + + case OPT_Wabi: + warn_psabi = value; + break; + } + + return result; +} + +/* Post-switch processing. */ +bool +c_common_post_options (const char **pfilename) +{ + struct cpp_callbacks *cb; + + /* Canonicalize the input and output filenames. */ + if (in_fnames == NULL) + { + in_fnames = XNEWVEC (const char *, 1); + in_fnames[0] = ""; + } + else if (strcmp (in_fnames[0], "-") == 0) + in_fnames[0] = ""; + + if (out_fname == NULL || !strcmp (out_fname, "-")) + out_fname = ""; + + if (cpp_opts->deps.style == DEPS_NONE) + check_deps_environment_vars (); + + handle_deferred_opts (); + + sanitize_cpp_opts (); + + register_include_chains (parse_in, sysroot, iprefix, imultilib, + std_inc, std_cxx_inc && c_dialect_cxx (), verbose); + +#ifdef C_COMMON_OVERRIDE_OPTIONS + /* Some machines may reject certain combinations of C + language-specific options. */ + C_COMMON_OVERRIDE_OPTIONS; +#endif + + /* Excess precision other than "fast" requires front-end + support. */ + if (c_dialect_cxx ()) + { + if (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD + && TARGET_FLT_EVAL_METHOD_NON_DEFAULT) + sorry ("-fexcess-precision=standard for C++"); + flag_excess_precision_cmdline = EXCESS_PRECISION_FAST; + } + else if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT) + flag_excess_precision_cmdline = (flag_iso + ? EXCESS_PRECISION_STANDARD + : EXCESS_PRECISION_FAST); + + /* By default we use C99 inline semantics in GNU99 or C99 mode. C99 + inline semantics are not supported in GNU89 or C89 mode. */ + if (flag_gnu89_inline == -1) + flag_gnu89_inline = !flag_isoc99; + else if (!flag_gnu89_inline && !flag_isoc99) + error ("-fno-gnu89-inline is only supported in GNU99 or C99 mode"); + + /* Default to ObjC sjlj exception handling if NeXT runtime. */ + if (flag_objc_sjlj_exceptions < 0) + flag_objc_sjlj_exceptions = flag_next_runtime; + if (flag_objc_exceptions && !flag_objc_sjlj_exceptions) + flag_exceptions = 1; + + /* -Wextra implies the following flags + unless explicitly overridden. */ + if (warn_type_limits == -1) + warn_type_limits = extra_warnings; + if (warn_clobbered == -1) + warn_clobbered = extra_warnings; + if (warn_empty_body == -1) + warn_empty_body = extra_warnings; + if (warn_sign_compare == -1) + warn_sign_compare = extra_warnings; + if (warn_missing_field_initializers == -1) + warn_missing_field_initializers = extra_warnings; + if (warn_missing_parameter_type == -1) + warn_missing_parameter_type = extra_warnings; + if (warn_old_style_declaration == -1) + warn_old_style_declaration = extra_warnings; + if (warn_override_init == -1) + warn_override_init = extra_warnings; + if (warn_ignored_qualifiers == -1) + warn_ignored_qualifiers = extra_warnings; + + /* -Wpointer-sign is disabled by default, but it is enabled if any + of -Wall or -pedantic are given. */ + if (warn_pointer_sign == -1) + warn_pointer_sign = 0; + + if (warn_strict_aliasing == -1) + warn_strict_aliasing = 0; + if (warn_strict_overflow == -1) + warn_strict_overflow = 0; + if (warn_jump_misses_init == -1) + warn_jump_misses_init = 0; + + /* -Woverlength-strings is off by default, but is enabled by -pedantic. + It is never enabled in C++, as the minimum limit is not normative + in that standard. */ + if (warn_overlength_strings == -1 || c_dialect_cxx ()) + warn_overlength_strings = 0; + + /* Wmain is enabled by default in C++ but not in C. */ + /* Wmain is disabled by default for -ffreestanding (!flag_hosted), + even if -Wall was given (warn_main will be 2 if set by -Wall, 1 + if set by -Wmain). */ + if (warn_main == -1) + warn_main = (c_dialect_cxx () && flag_hosted) ? 1 : 0; + else if (warn_main == 2) + warn_main = flag_hosted ? 1 : 0; + + /* In C, -Wconversion enables -Wsign-conversion (unless disabled + through -Wno-sign-conversion). While in C++, + -Wsign-conversion needs to be requested explicitly. */ + if (warn_sign_conversion == -1) + warn_sign_conversion = (c_dialect_cxx ()) ? 0 : warn_conversion; + + /* In C, -Wall and -Wc++-compat enable -Wenum-compare, which we do + in c_common_handle_option; if it has not yet been set, it is + disabled by default. In C++, it is enabled by default. */ + if (warn_enum_compare == -1) + warn_enum_compare = c_dialect_cxx () ? 1 : 0; + + /* -Wpacked-bitfield-compat is on by default for the C languages. The + warning is issued in stor-layout.c which is not part of the front-end so + we need to selectively turn it on here. */ + if (warn_packed_bitfield_compat == -1) + warn_packed_bitfield_compat = 1; + + /* Special format checking options don't work without -Wformat; warn if + they are used. */ + if (!warn_format) + { + warning (OPT_Wformat_y2k, + "-Wformat-y2k ignored without -Wformat"); + warning (OPT_Wformat_extra_args, + "-Wformat-extra-args ignored without -Wformat"); + warning (OPT_Wformat_zero_length, + "-Wformat-zero-length ignored without -Wformat"); + warning (OPT_Wformat_nonliteral, + "-Wformat-nonliteral ignored without -Wformat"); + warning (OPT_Wformat_contains_nul, + "-Wformat-contains-nul ignored without -Wformat"); + warning (OPT_Wformat_security, + "-Wformat-security ignored without -Wformat"); + } + + if (warn_implicit == -1) + warn_implicit = 0; + + if (warn_implicit_int == -1) + warn_implicit_int = 0; + + /* -Wimplicit-function-declaration is enabled by default for C99. */ + if (warn_implicit_function_declaration == -1) + warn_implicit_function_declaration = flag_isoc99; + + /* If we're allowing C++0x constructs, don't warn about C++0x + compatibility problems. */ + if (cxx_dialect == cxx0x) + warn_cxx0x_compat = 0; + + if (flag_preprocess_only) + { + /* Open the output now. We must do so even if flag_no_output is + on, because there may be other output than from the actual + preprocessing (e.g. from -dM). */ + if (out_fname[0] == '\0') + out_stream = stdout; + else + out_stream = fopen (out_fname, "w"); + + if (out_stream == NULL) + { + fatal_error ("opening output file %s: %m", out_fname); + return false; + } + + if (num_in_fnames > 1) + error ("too many filenames given. Type %s --help for usage", + progname); + + init_pp_output (out_stream); + } + else + { + init_c_lex (); + + /* Yuk. WTF is this? I do know ObjC relies on it somewhere. */ + input_location = UNKNOWN_LOCATION; + } + + cb = cpp_get_callbacks (parse_in); + cb->file_change = cb_file_change; + cb->dir_change = cb_dir_change; + cpp_post_options (parse_in); + + input_location = UNKNOWN_LOCATION; + + *pfilename = this_input_filename + = cpp_read_main_file (parse_in, in_fnames[0]); + /* Don't do any compilation or preprocessing if there is no input file. */ + if (this_input_filename == NULL) + { + errorcount++; + return false; + } + + if (flag_working_directory + && flag_preprocess_only && !flag_no_line_commands) + pp_dir_change (parse_in, get_src_pwd ()); + + return flag_preprocess_only; +} + +/* Front end initialization common to C, ObjC and C++. */ +bool +c_common_init (void) +{ + /* Set up preprocessor arithmetic. Must be done after call to + c_common_nodes_and_builtins for type nodes to be good. */ + cpp_opts->precision = TYPE_PRECISION (intmax_type_node); + cpp_opts->char_precision = TYPE_PRECISION (char_type_node); + cpp_opts->int_precision = TYPE_PRECISION (integer_type_node); + cpp_opts->wchar_precision = TYPE_PRECISION (wchar_type_node); + cpp_opts->unsigned_wchar = TYPE_UNSIGNED (wchar_type_node); + cpp_opts->bytes_big_endian = BYTES_BIG_ENDIAN; + + /* This can't happen until after wchar_precision and bytes_big_endian + are known. */ + cpp_init_iconv (parse_in); + + if (version_flag) + c_common_print_pch_checksum (stderr); + + /* Has to wait until now so that cpplib has its hash table. */ + init_pragma (); + + if (flag_preprocess_only) + { + finish_options (); + preprocess_file (parse_in); + return false; + } + + return true; +} + +/* Initialize the integrated preprocessor after debug output has been + initialized; loop over each input file. */ +void +c_common_parse_file (int set_yydebug) +{ + unsigned int i; + + if (set_yydebug) + switch (c_language) + { + case clk_c: + warning(0, "The C parser does not support -dy, option ignored"); + break; + case clk_objc: + warning(0, + "The Objective-C parser does not support -dy, option ignored"); + break; + case clk_cxx: + warning(0, "The C++ parser does not support -dy, option ignored"); + break; + case clk_objcxx: + warning(0, + "The Objective-C++ parser does not support -dy, option ignored"); + break; + default: + gcc_unreachable (); + } + + i = 0; + for (;;) + { + finish_options (); + pch_init (); + push_file_scope (); + c_parse_file (); + finish_file (); + pop_file_scope (); + /* And end the main input file, if the debug writer wants it */ + if (debug_hooks->start_end_main_source_file) + (*debug_hooks->end_source_file) (0); + if (++i >= num_in_fnames) + break; + cpp_undef_all (parse_in); + cpp_clear_file_cache (parse_in); + this_input_filename + = cpp_read_main_file (parse_in, in_fnames[i]); + /* If an input file is missing, abandon further compilation. + cpplib has issued a diagnostic. */ + if (!this_input_filename) + break; + } +} + +/* Common finish hook for the C, ObjC and C++ front ends. */ +void +c_common_finish (void) +{ + FILE *deps_stream = NULL; + + /* Don't write the deps file if there are errors. */ + if (cpp_opts->deps.style != DEPS_NONE && !seen_error ()) + { + /* If -M or -MM was seen without -MF, default output to the + output stream. */ + if (!deps_file) + deps_stream = out_stream; + else + { + deps_stream = fopen (deps_file, deps_append ? "a": "w"); + if (!deps_stream) + fatal_error ("opening dependency file %s: %m", deps_file); + } + } + + /* For performance, avoid tearing down cpplib's internal structures + with cpp_destroy (). */ + cpp_finish (parse_in, deps_stream); + + if (deps_stream && deps_stream != out_stream + && (ferror (deps_stream) || fclose (deps_stream))) + fatal_error ("closing dependency file %s: %m", deps_file); + + if (out_stream && (ferror (out_stream) || fclose (out_stream))) + fatal_error ("when writing output to %s: %m", out_fname); +} + +/* Either of two environment variables can specify output of + dependencies. Their value is either "OUTPUT_FILE" or "OUTPUT_FILE + DEPS_TARGET", where OUTPUT_FILE is the file to write deps info to + and DEPS_TARGET is the target to mention in the deps. They also + result in dependency information being appended to the output file + rather than overwriting it, and like Sun's compiler + SUNPRO_DEPENDENCIES suppresses the dependency on the main file. */ +static void +check_deps_environment_vars (void) +{ + char *spec; + + GET_ENVIRONMENT (spec, "DEPENDENCIES_OUTPUT"); + if (spec) + cpp_opts->deps.style = DEPS_USER; + else + { + GET_ENVIRONMENT (spec, "SUNPRO_DEPENDENCIES"); + if (spec) + { + cpp_opts->deps.style = DEPS_SYSTEM; + cpp_opts->deps.ignore_main_file = true; + } + } + + if (spec) + { + /* Find the space before the DEPS_TARGET, if there is one. */ + char *s = strchr (spec, ' '); + if (s) + { + /* Let the caller perform MAKE quoting. */ + defer_opt (OPT_MT, s + 1); + *s = '\0'; + } + + /* Command line -MF overrides environment variables and default. */ + if (!deps_file) + deps_file = spec; + + deps_append = 1; + deps_seen = true; + } +} + +/* Handle deferred command line switches. */ +static void +handle_deferred_opts (void) +{ + size_t i; + struct deps *deps; + + /* Avoid allocating the deps buffer if we don't need it. + (This flag may be true without there having been -MT or -MQ + options, but we'll still need the deps buffer.) */ + if (!deps_seen) + return; + + deps = cpp_get_deps (parse_in); + + for (i = 0; i < deferred_count; i++) + { + struct deferred_opt *opt = &deferred_opts[i]; + + if (opt->code == OPT_MT || opt->code == OPT_MQ) + deps_add_target (deps, opt->arg, opt->code == OPT_MQ); + } +} + +/* These settings are appropriate for GCC, but not necessarily so for + cpplib as a library. */ +static void +sanitize_cpp_opts (void) +{ + /* If we don't know what style of dependencies to output, complain + if any other dependency switches have been given. */ + if (deps_seen && cpp_opts->deps.style == DEPS_NONE) + error ("to generate dependencies you must specify either -M or -MM"); + + /* -dM and dependencies suppress normal output; do it here so that + the last -d[MDN] switch overrides earlier ones. */ + if (flag_dump_macros == 'M') + flag_no_output = 1; + + /* By default, -fdirectives-only implies -dD. This allows subsequent phases + to perform proper macro expansion. */ + if (cpp_opts->directives_only && !cpp_opts->preprocessed && !flag_dump_macros) + flag_dump_macros = 'D'; + + /* Disable -dD, -dN and -dI if normal output is suppressed. Allow + -dM since at least glibc relies on -M -dM to work. */ + /* Also, flag_no_output implies flag_no_line_commands, always. */ + if (flag_no_output) + { + if (flag_dump_macros != 'M') + flag_dump_macros = 0; + flag_dump_includes = 0; + flag_no_line_commands = 1; + } + else if (cpp_opts->deps.missing_files) + error ("-MG may only be used with -M or -MM"); + + cpp_opts->unsigned_char = !flag_signed_char; + cpp_opts->stdc_0_in_system_headers = STDC_0_IN_SYSTEM_HEADERS; + + /* Wlong-long is disabled by default. It is enabled by: + [-pedantic | -Wtraditional] -std=[gnu|c]++98 ; or + [-pedantic | -Wtraditional] -std=non-c99 . + + Either -Wlong-long or -Wno-long-long override any other settings. */ + if (warn_long_long == -1) + warn_long_long = ((pedantic || warn_traditional) + && (c_dialect_cxx () ? cxx_dialect == cxx98 : !flag_isoc99)); + cpp_opts->warn_long_long = warn_long_long; + + /* Similarly with -Wno-variadic-macros. No check for c99 here, since + this also turns off warnings about GCCs extension. */ + cpp_opts->warn_variadic_macros + = warn_variadic_macros && (pedantic || warn_traditional); + + /* If we're generating preprocessor output, emit current directory + if explicitly requested or if debugging information is enabled. + ??? Maybe we should only do it for debugging formats that + actually output the current directory? */ + if (flag_working_directory == -1) + flag_working_directory = (debug_info_level != DINFO_LEVEL_NONE); + + if (cpp_opts->directives_only) + { + if (warn_unused_macros) + error ("-fdirectives-only is incompatible with -Wunused_macros"); + if (cpp_opts->traditional) + error ("-fdirectives-only is incompatible with -traditional"); + } +} + +/* Add include path with a prefix at the front of its name. */ +static void +add_prefixed_path (const char *suffix, size_t chain) +{ + char *path; + const char *prefix; + size_t prefix_len, suffix_len; + + suffix_len = strlen (suffix); + prefix = iprefix ? iprefix : cpp_GCC_INCLUDE_DIR; + prefix_len = iprefix ? strlen (iprefix) : cpp_GCC_INCLUDE_DIR_len; + + path = (char *) xmalloc (prefix_len + suffix_len + 1); + memcpy (path, prefix, prefix_len); + memcpy (path + prefix_len, suffix, suffix_len); + path[prefix_len + suffix_len] = '\0'; + + add_path (path, chain, 0, false); +} + +/* Handle -D, -U, -A, -imacros, and the first -include. */ +static void +finish_options (void) +{ + if (!cpp_opts->preprocessed) + { + size_t i; + + cb_file_change (parse_in, + linemap_add (line_table, LC_RENAME, 0, + _(""), 0)); + + cpp_init_builtins (parse_in, flag_hosted); + c_cpp_builtins (parse_in); + + /* We're about to send user input to cpplib, so make it warn for + things that we previously (when we sent it internal definitions) + told it to not warn. + + C99 permits implementation-defined characters in identifiers. + The documented meaning of -std= is to turn off extensions that + conflict with the specified standard, and since a strictly + conforming program cannot contain a '$', we do not condition + their acceptance on the -std= setting. */ + cpp_opts->warn_dollars = (cpp_opts->pedantic && !cpp_opts->c99); + + cb_file_change (parse_in, + linemap_add (line_table, LC_RENAME, 0, + _(""), 0)); + + for (i = 0; i < deferred_count; i++) + { + struct deferred_opt *opt = &deferred_opts[i]; + + if (opt->code == OPT_D) + cpp_define (parse_in, opt->arg); + else if (opt->code == OPT_U) + cpp_undef (parse_in, opt->arg); + else if (opt->code == OPT_A) + { + if (opt->arg[0] == '-') + cpp_unassert (parse_in, opt->arg + 1); + else + cpp_assert (parse_in, opt->arg); + } + } + + /* Start the main input file, if the debug writer wants it. */ + if (debug_hooks->start_end_main_source_file + && !flag_preprocess_only) + (*debug_hooks->start_source_file) (0, this_input_filename); + + /* Handle -imacros after -D and -U. */ + for (i = 0; i < deferred_count; i++) + { + struct deferred_opt *opt = &deferred_opts[i]; + + if (opt->code == OPT_imacros + && cpp_push_include (parse_in, opt->arg)) + { + /* Disable push_command_line_include callback for now. */ + include_cursor = deferred_count + 1; + cpp_scan_nooutput (parse_in); + } + } + } + else + { + if (cpp_opts->directives_only) + cpp_init_special_builtins (parse_in); + + /* Start the main input file, if the debug writer wants it. */ + if (debug_hooks->start_end_main_source_file + && !flag_preprocess_only) + (*debug_hooks->start_source_file) (0, this_input_filename); + } + + include_cursor = 0; + push_command_line_include (); +} + +/* Give CPP the next file given by -include, if any. */ +static void +push_command_line_include (void) +{ + while (include_cursor < deferred_count) + { + struct deferred_opt *opt = &deferred_opts[include_cursor++]; + + if (!cpp_opts->preprocessed && opt->code == OPT_include + && cpp_push_include (parse_in, opt->arg)) + return; + } + + if (include_cursor == deferred_count) + { + include_cursor++; + /* -Wunused-macros should only warn about macros defined hereafter. */ + cpp_opts->warn_unused_macros = warn_unused_macros; + /* Restore the line map from . */ + if (!cpp_opts->preprocessed) + cpp_change_file (parse_in, LC_RENAME, this_input_filename); + + /* Set this here so the client can change the option if it wishes, + and after stacking the main file so we don't trace the main file. */ + line_table->trace_includes = cpp_opts->print_include_names; + } +} + +/* File change callback. Has to handle -include files. */ +static void +cb_file_change (cpp_reader * ARG_UNUSED (pfile), + const struct line_map *new_map) +{ + if (flag_preprocess_only) + pp_file_change (new_map); + else + fe_file_change (new_map); + + if (new_map == 0 || (new_map->reason == LC_LEAVE && MAIN_FILE_P (new_map))) + push_command_line_include (); +} + +void +cb_dir_change (cpp_reader * ARG_UNUSED (pfile), const char *dir) +{ + if (!set_src_pwd (dir)) + warning (0, "too late for # directive to set debug directory"); +} + +/* Set the C 89 standard (with 1994 amendments if C94, without GNU + extensions if ISO). There is no concept of gnu94. */ +static void +set_std_c89 (int c94, int iso) +{ + cpp_set_lang (parse_in, c94 ? CLK_STDC94: iso ? CLK_STDC89: CLK_GNUC89); + flag_iso = iso; + flag_no_asm = iso; + flag_no_gnu_keywords = iso; + flag_no_nonansi_builtin = iso; + flag_isoc94 = c94; + flag_isoc99 = 0; + flag_isoc1x = 0; +} + +/* Set the C 99 standard (without GNU extensions if ISO). */ +static void +set_std_c99 (int iso) +{ + cpp_set_lang (parse_in, iso ? CLK_STDC99: CLK_GNUC99); + flag_no_asm = iso; + flag_no_nonansi_builtin = iso; + flag_iso = iso; + flag_isoc1x = 0; + flag_isoc99 = 1; + flag_isoc94 = 1; +} + +/* Set the C 1X standard draft (without GNU extensions if ISO). */ +static void +set_std_c1x (int iso) +{ + cpp_set_lang (parse_in, iso ? CLK_STDC1X: CLK_GNUC1X); + flag_no_asm = iso; + flag_no_nonansi_builtin = iso; + flag_iso = iso; + flag_isoc1x = 1; + flag_isoc99 = 1; + flag_isoc94 = 1; +} + +/* Set the C++ 98 standard (without GNU extensions if ISO). */ +static void +set_std_cxx98 (int iso) +{ + cpp_set_lang (parse_in, iso ? CLK_CXX98: CLK_GNUCXX); + flag_no_gnu_keywords = iso; + flag_no_nonansi_builtin = iso; + flag_iso = iso; + cxx_dialect = cxx98; +} + +/* Set the C++ 0x working draft "standard" (without GNU extensions if ISO). */ +static void +set_std_cxx0x (int iso) +{ + cpp_set_lang (parse_in, iso ? CLK_CXX0X: CLK_GNUCXX0X); + flag_no_gnu_keywords = iso; + flag_no_nonansi_builtin = iso; + flag_iso = iso; + cxx_dialect = cxx0x; +} + +/* Args to -d specify what to dump. Silently ignore + unrecognized options; they may be aimed at toplev.c. */ +static void +handle_OPT_d (const char *arg) +{ + char c; + + while ((c = *arg++) != '\0') + switch (c) + { + case 'M': /* Dump macros only. */ + case 'N': /* Dump names. */ + case 'D': /* Dump definitions. */ + case 'U': /* Dump used macros. */ + flag_dump_macros = c; + break; + + case 'I': + flag_dump_includes = 1; + break; + } +} diff --git a/gcc/c-family/c-pch.c b/gcc/c-family/c-pch.c new file mode 100644 index 0000000..951ab1f --- /dev/null +++ b/gcc/c-family/c-pch.c @@ -0,0 +1,517 @@ +/* Precompiled header implementation for the C languages. + Copyright (C) 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 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 "version.h" +#include "cpplib.h" +#include "tree.h" +#include "flags.h" +#include "c-common.h" +#include "output.h" +#include "toplev.h" +#include "debug.h" +#include "c-pragma.h" +#include "ggc.h" +#include "langhooks.h" +#include "hosthooks.h" +#include "target.h" +#include "opts.h" +#include "timevar.h" + +/* This is a list of flag variables that must match exactly, and their + names for the error message. The possible values for *flag_var must + fit in a 'signed char'. */ + +static const struct c_pch_matching +{ + int *flag_var; + const char *flag_name; +} pch_matching[] = { + { &flag_exceptions, "-fexceptions" }, +}; + +enum { + MATCH_SIZE = ARRAY_SIZE (pch_matching) +}; + +/* The value of the checksum in the dummy compiler that is actually + checksummed. That compiler should never be run. */ +static const char no_checksum[16] = { 0 }; + +/* Information about flags and suchlike that affect PCH validity. + + Before this structure is read, both an initial 8-character identification + string, and a 16-byte checksum, have been read and validated. */ + +struct c_pch_validity +{ + unsigned char debug_info_type; + signed char match[MATCH_SIZE]; + void (*pch_init) (void); + size_t target_data_length; +}; + +struct c_pch_header +{ + unsigned long asm_size; +}; + +#define IDENT_LENGTH 8 + +/* The file we'll be writing the PCH to. */ +static FILE *pch_outfile; + +/* The position in the assembler output file when pch_init was called. */ +static long asm_file_startpos; + +static const char *get_ident (void); + +/* Compute an appropriate 8-byte magic number for the PCH file, so that + utilities like file(1) can identify it, and so that GCC can quickly + ignore non-PCH files and PCH files that are of a completely different + format. */ + +static const char * +get_ident (void) +{ + static char result[IDENT_LENGTH]; + static const char templ[] = "gpch.013"; + static const char c_language_chars[] = "Co+O"; + + memcpy (result, templ, IDENT_LENGTH); + result[4] = c_language_chars[c_language]; + + return result; +} + +/* Prepare to write a PCH file, if one is being written. This is + called at the start of compilation. + + Also, print out the executable checksum if -fverbose-asm is in effect. */ + +void +pch_init (void) +{ + FILE *f; + struct c_pch_validity v; + void *target_validity; + static const char partial_pch[] = "gpcWrite"; + +#ifdef ASM_COMMENT_START + if (flag_verbose_asm) + { + fprintf (asm_out_file, "%s ", ASM_COMMENT_START); + c_common_print_pch_checksum (asm_out_file); + fputc ('\n', asm_out_file); + } +#endif + + if (!pch_file) + return; + + f = fopen (pch_file, "w+b"); + if (f == NULL) + fatal_error ("can%'t create precompiled header %s: %m", pch_file); + pch_outfile = f; + + gcc_assert (memcmp (executable_checksum, no_checksum, 16) != 0); + + memset (&v, '\0', sizeof (v)); + v.debug_info_type = write_symbols; + { + size_t i; + for (i = 0; i < MATCH_SIZE; i++) + { + v.match[i] = *pch_matching[i].flag_var; + gcc_assert (v.match[i] == *pch_matching[i].flag_var); + } + } + v.pch_init = &pch_init; + target_validity = targetm.get_pch_validity (&v.target_data_length); + + if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1 + || fwrite (executable_checksum, 16, 1, f) != 1 + || fwrite (&v, sizeof (v), 1, f) != 1 + || fwrite (target_validity, v.target_data_length, 1, f) != 1) + fatal_error ("can%'t write to %s: %m", pch_file); + + /* We need to be able to re-read the output. */ + /* The driver always provides a valid -o option. */ + if (asm_file_name == NULL + || strcmp (asm_file_name, "-") == 0) + fatal_error ("%qs is not a valid output file", asm_file_name); + + asm_file_startpos = ftell (asm_out_file); + + /* Let the debugging format deal with the PCHness. */ + (*debug_hooks->handle_pch) (0); + + cpp_save_state (parse_in, f); +} + +/* Write the PCH file. This is called at the end of a compilation which + will produce a PCH file. */ + +void +c_common_write_pch (void) +{ + char *buf; + long asm_file_end; + long written; + struct c_pch_header h; + + timevar_push (TV_PCH_SAVE); + + (*debug_hooks->handle_pch) (1); + + cpp_write_pch_deps (parse_in, pch_outfile); + + asm_file_end = ftell (asm_out_file); + h.asm_size = asm_file_end - asm_file_startpos; + + if (fwrite (&h, sizeof (h), 1, pch_outfile) != 1) + fatal_error ("can%'t write %s: %m", pch_file); + + buf = XNEWVEC (char, 16384); + + if (fseek (asm_out_file, asm_file_startpos, SEEK_SET) != 0) + fatal_error ("can%'t seek in %s: %m", asm_file_name); + + for (written = asm_file_startpos; written < asm_file_end; ) + { + long size = asm_file_end - written; + if (size > 16384) + size = 16384; + if (fread (buf, size, 1, asm_out_file) != 1) + fatal_error ("can%'t read %s: %m", asm_file_name); + if (fwrite (buf, size, 1, pch_outfile) != 1) + fatal_error ("can%'t write %s: %m", pch_file); + written += size; + } + free (buf); + /* asm_out_file can be written afterwards, so fseek to clear + _IOREAD flag. */ + if (fseek (asm_out_file, 0, SEEK_END) != 0) + fatal_error ("can%'t seek in %s: %m", asm_file_name); + + gt_pch_save (pch_outfile); + + timevar_push (TV_PCH_CPP_SAVE); + cpp_write_pch_state (parse_in, pch_outfile); + timevar_pop (TV_PCH_CPP_SAVE); + + if (fseek (pch_outfile, 0, SEEK_SET) != 0 + || fwrite (get_ident (), IDENT_LENGTH, 1, pch_outfile) != 1) + fatal_error ("can%'t write %s: %m", pch_file); + + fclose (pch_outfile); + + timevar_pop (TV_PCH_SAVE); +} + +/* Check the PCH file called NAME, open on FD, to see if it can be + used in this compilation. Return 1 if valid, 0 if the file can't + be used now but might be if it's seen later in the compilation, and + 2 if this file could never be used in the compilation. */ + +int +c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) +{ + int sizeread; + int result; + char ident[IDENT_LENGTH + 16]; + const char *pch_ident; + struct c_pch_validity v; + + /* Perform a quick test of whether this is a valid + precompiled header for the current language. */ + + gcc_assert (memcmp (executable_checksum, no_checksum, 16) != 0); + + sizeread = read (fd, ident, IDENT_LENGTH + 16); + if (sizeread == -1) + fatal_error ("can%'t read %s: %m", name); + else if (sizeread != IDENT_LENGTH + 16) + { + if (cpp_get_options (pfile)->warn_invalid_pch) + cpp_error (pfile, CPP_DL_WARNING, "%s: too short to be a PCH file", + name); + return 2; + } + + pch_ident = get_ident(); + if (memcmp (ident, pch_ident, IDENT_LENGTH) != 0) + { + if (cpp_get_options (pfile)->warn_invalid_pch) + { + if (memcmp (ident, pch_ident, 5) == 0) + /* It's a PCH, for the right language, but has the wrong version. + */ + cpp_error (pfile, CPP_DL_WARNING, + "%s: not compatible with this GCC version", name); + else if (memcmp (ident, pch_ident, 4) == 0) + /* It's a PCH for the wrong language. */ + cpp_error (pfile, CPP_DL_WARNING, "%s: not for %s", name, + lang_hooks.name); + else + /* Not any kind of PCH. */ + cpp_error (pfile, CPP_DL_WARNING, "%s: not a PCH file", name); + } + return 2; + } + if (memcmp (ident + IDENT_LENGTH, executable_checksum, 16) != 0) + { + if (cpp_get_options (pfile)->warn_invalid_pch) + cpp_error (pfile, CPP_DL_WARNING, + "%s: created by a different GCC executable", name); + return 2; + } + + /* At this point, we know it's a PCH file created by this + executable, so it ought to be long enough that we can read a + c_pch_validity structure. */ + if (read (fd, &v, sizeof (v)) != sizeof (v)) + fatal_error ("can%'t read %s: %m", name); + + /* The allowable debug info combinations are that either the PCH file + was built with the same as is being used now, or the PCH file was + built for some kind of debug info but now none is in use. */ + if (v.debug_info_type != write_symbols + && write_symbols != NO_DEBUG) + { + if (cpp_get_options (pfile)->warn_invalid_pch) + cpp_error (pfile, CPP_DL_WARNING, + "%s: created with -g%s, but used with -g%s", name, + debug_type_names[v.debug_info_type], + debug_type_names[write_symbols]); + return 2; + } + + /* Check flags that must match exactly. */ + { + size_t i; + for (i = 0; i < MATCH_SIZE; i++) + if (*pch_matching[i].flag_var != v.match[i]) + { + if (cpp_get_options (pfile)->warn_invalid_pch) + cpp_error (pfile, CPP_DL_WARNING, + "%s: settings for %s do not match", name, + pch_matching[i].flag_name); + return 2; + } + } + + /* If the text segment was not loaded at the same address as it was + when the PCH file was created, function pointers loaded from the + PCH will not be valid. We could in theory remap all the function + pointers, but no support for that exists at present. + Since we have the same executable, it should only be necessary to + check one function. */ + if (v.pch_init != &pch_init) + { + if (cpp_get_options (pfile)->warn_invalid_pch) + cpp_error (pfile, CPP_DL_WARNING, + "%s: had text segment at different address", name); + return 2; + } + + /* Check the target-specific validity data. */ + { + void *this_file_data = xmalloc (v.target_data_length); + const char *msg; + + if ((size_t) read (fd, this_file_data, v.target_data_length) + != v.target_data_length) + fatal_error ("can%'t read %s: %m", name); + msg = targetm.pch_valid_p (this_file_data, v.target_data_length); + free (this_file_data); + if (msg != NULL) + { + if (cpp_get_options (pfile)->warn_invalid_pch) + cpp_error (pfile, CPP_DL_WARNING, "%s: %s", name, msg); + return 2; + } + } + + /* Check the preprocessor macros are the same as when the PCH was + generated. */ + + result = cpp_valid_state (pfile, name, fd); + if (result == -1) + return 2; + else + return result == 0; +} + +/* If non-NULL, this function is called after a precompile header file + is loaded. */ +void (*lang_post_pch_load) (void); + +/* Load in the PCH file NAME, open on FD. It was originally searched for + by ORIG_NAME. */ + +void +c_common_read_pch (cpp_reader *pfile, const char *name, + int fd, const char *orig_name ATTRIBUTE_UNUSED) +{ + FILE *f; + struct c_pch_header h; + struct save_macro_data *smd; + expanded_location saved_loc; + bool saved_trace_includes; + + timevar_push (TV_PCH_RESTORE); + + f = fdopen (fd, "rb"); + if (f == NULL) + { + cpp_errno (pfile, CPP_DL_ERROR, "calling fdopen"); + close (fd); + goto end; + } + + cpp_get_callbacks (parse_in)->valid_pch = NULL; + + if (fread (&h, sizeof (h), 1, f) != 1) + { + cpp_errno (pfile, CPP_DL_ERROR, "reading"); + fclose (f); + goto end; + } + + if (!flag_preprocess_only) + { + unsigned long written; + char * buf = XNEWVEC (char, 16384); + + for (written = 0; written < h.asm_size; ) + { + long size = h.asm_size - written; + if (size > 16384) + size = 16384; + if (fread (buf, size, 1, f) != 1 + || fwrite (buf, size, 1, asm_out_file) != 1) + cpp_errno (pfile, CPP_DL_ERROR, "reading"); + written += size; + } + free (buf); + } + else + { + /* If we're preprocessing, don't write to a NULL + asm_out_file. */ + if (fseek (f, h.asm_size, SEEK_CUR) != 0) + cpp_errno (pfile, CPP_DL_ERROR, "seeking"); + } + + /* Save the location and then restore it after reading the PCH. */ + saved_loc = expand_location (line_table->highest_line); + saved_trace_includes = line_table->trace_includes; + + timevar_push (TV_PCH_CPP_RESTORE); + cpp_prepare_state (pfile, &smd); + timevar_pop (TV_PCH_CPP_RESTORE); + + gt_pch_restore (f); + + timevar_push (TV_PCH_CPP_RESTORE); + if (cpp_read_state (pfile, name, f, smd) != 0) + { + fclose (f); + timevar_pop (TV_PCH_CPP_RESTORE); + goto end; + } + timevar_pop (TV_PCH_CPP_RESTORE); + + + fclose (f); + + line_table->trace_includes = saved_trace_includes; + cpp_set_line_map (pfile, line_table); + linemap_add (line_table, LC_RENAME, 0, saved_loc.file, saved_loc.line); + + /* Give the front end a chance to take action after a PCH file has + been loaded. */ + if (lang_post_pch_load) + (*lang_post_pch_load) (); + +end: + timevar_pop (TV_PCH_RESTORE); +} + +/* Indicate that no more PCH files should be read. */ + +void +c_common_no_more_pch (void) +{ + if (cpp_get_callbacks (parse_in)->valid_pch) + { + cpp_get_callbacks (parse_in)->valid_pch = NULL; + host_hooks.gt_pch_use_address (NULL, 0, -1, 0); + } +} + +/* Handle #pragma GCC pch_preprocess, to load in the PCH file. */ + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +void +c_common_pch_pragma (cpp_reader *pfile, const char *name) +{ + int fd; + + if (!cpp_get_options (pfile)->preprocessed) + { + error ("pch_preprocess pragma should only be used with -fpreprocessed"); + inform (input_location, "use #include instead"); + return; + } + + fd = open (name, O_RDONLY | O_BINARY, 0666); + if (fd == -1) + fatal_error ("%s: couldn%'t open PCH file: %m", name); + + if (c_common_valid_pch (pfile, name, fd) != 1) + { + if (!cpp_get_options (pfile)->warn_invalid_pch) + inform (input_location, "use -Winvalid-pch for more information"); + fatal_error ("%s: PCH file was invalid", name); + } + + c_common_read_pch (pfile, name, fd, name); + + close (fd); +} + +/* Print out executable_checksum[]. */ + +void +c_common_print_pch_checksum (FILE *f) +{ + int i; + fputs ("Compiler executable checksum: ", f); + for (i = 0; i < 16; i++) + fprintf (f, "%02x", executable_checksum[i]); + putc ('\n', f); +} diff --git a/gcc/c-family/c-ppoutput.c b/gcc/c-family/c-ppoutput.c new file mode 100644 index 0000000..1700fae --- /dev/null +++ b/gcc/c-family/c-ppoutput.c @@ -0,0 +1,625 @@ +/* Preprocess only, using cpplib. + Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007, + 2008, 2009 Free Software Foundation, Inc. + Written by Per Bothner, 1994-95. + + This program 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. + + This program 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 this program; see the file COPYING3. If not see + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "cpplib.h" +#include "../libcpp/internal.h" +#include "tree.h" +#include "c-common.h" /* For flags. */ +#include "c-pragma.h" /* For parse_in. */ + +/* Encapsulates state used to convert a stream of tokens into a text + file. */ +static struct +{ + FILE *outf; /* Stream to write to. */ + const cpp_token *prev; /* Previous token. */ + const cpp_token *source; /* Source token for spacing. */ + int src_line; /* Line number currently being written. */ + unsigned char printed; /* Nonzero if something output at line. */ + bool first_time; /* pp_file_change hasn't been called yet. */ +} print; + +/* Defined and undefined macros being queued for output with -dU at + the next newline. */ +typedef struct macro_queue +{ + struct macro_queue *next; /* Next macro in the list. */ + char *macro; /* The name of the macro if not + defined, the full definition if + defined. */ +} macro_queue; +static macro_queue *define_queue, *undef_queue; + +/* General output routines. */ +static void scan_translation_unit (cpp_reader *); +static void print_lines_directives_only (int, const void *, size_t); +static void scan_translation_unit_directives_only (cpp_reader *); +static void scan_translation_unit_trad (cpp_reader *); +static void account_for_newlines (const unsigned char *, size_t); +static int dump_macro (cpp_reader *, cpp_hashnode *, void *); +static void dump_queued_macros (cpp_reader *); + +static void print_line (source_location, const char *); +static void maybe_print_line (source_location); +static void do_line_change (cpp_reader *, const cpp_token *, + source_location, int); + +/* Callback routines for the parser. Most of these are active only + in specific modes. */ +static void cb_line_change (cpp_reader *, const cpp_token *, int); +static void cb_define (cpp_reader *, source_location, cpp_hashnode *); +static void cb_undef (cpp_reader *, source_location, cpp_hashnode *); +static void cb_used_define (cpp_reader *, source_location, cpp_hashnode *); +static void cb_used_undef (cpp_reader *, source_location, cpp_hashnode *); +static void cb_include (cpp_reader *, source_location, const unsigned char *, + const char *, int, const cpp_token **); +static void cb_ident (cpp_reader *, source_location, const cpp_string *); +static void cb_def_pragma (cpp_reader *, source_location); +static void cb_read_pch (cpp_reader *pfile, const char *name, + int fd, const char *orig_name); + +/* Preprocess and output. */ +void +preprocess_file (cpp_reader *pfile) +{ + /* A successful cpp_read_main_file guarantees that we can call + cpp_scan_nooutput or cpp_get_token next. */ + if (flag_no_output) + { + /* Scan -included buffers, then the main file. */ + while (pfile->buffer->prev) + cpp_scan_nooutput (pfile); + cpp_scan_nooutput (pfile); + } + else if (cpp_get_options (pfile)->traditional) + scan_translation_unit_trad (pfile); + else if (cpp_get_options (pfile)->directives_only + && !cpp_get_options (pfile)->preprocessed) + scan_translation_unit_directives_only (pfile); + else + scan_translation_unit (pfile); + + /* -dM command line option. Should this be elsewhere? */ + if (flag_dump_macros == 'M') + cpp_forall_identifiers (pfile, dump_macro, NULL); + + /* Flush any pending output. */ + if (print.printed) + putc ('\n', print.outf); +} + +/* Set up the callbacks as appropriate. */ +void +init_pp_output (FILE *out_stream) +{ + cpp_callbacks *cb = cpp_get_callbacks (parse_in); + + if (!flag_no_output) + { + cb->line_change = cb_line_change; + /* Don't emit #pragma or #ident directives if we are processing + assembly language; the assembler may choke on them. */ + if (cpp_get_options (parse_in)->lang != CLK_ASM) + { + cb->ident = cb_ident; + cb->def_pragma = cb_def_pragma; + } + } + + if (flag_dump_includes) + cb->include = cb_include; + + if (flag_pch_preprocess) + { + cb->valid_pch = c_common_valid_pch; + cb->read_pch = cb_read_pch; + } + + if (flag_dump_macros == 'N' || flag_dump_macros == 'D') + { + cb->define = cb_define; + cb->undef = cb_undef; + } + + if (flag_dump_macros == 'U') + { + cb->before_define = dump_queued_macros; + cb->used_define = cb_used_define; + cb->used_undef = cb_used_undef; + } + + /* Initialize the print structure. */ + print.src_line = 1; + print.printed = 0; + print.prev = 0; + print.outf = out_stream; + print.first_time = 1; +} + +/* Writes out the preprocessed file, handling spacing and paste + avoidance issues. */ +static void +scan_translation_unit (cpp_reader *pfile) +{ + bool avoid_paste = false; + bool do_line_adjustments + = cpp_get_options (parse_in)->lang != CLK_ASM + && !flag_no_line_commands; + bool in_pragma = false; + + print.source = NULL; + for (;;) + { + source_location loc; + const cpp_token *token = cpp_get_token_with_location (pfile, &loc); + + if (token->type == CPP_PADDING) + { + avoid_paste = true; + if (print.source == NULL + || (!(print.source->flags & PREV_WHITE) + && token->val.source == NULL)) + print.source = token->val.source; + continue; + } + + if (token->type == CPP_EOF) + break; + + /* Subtle logic to output a space if and only if necessary. */ + if (avoid_paste) + { + const struct line_map *map + = linemap_lookup (line_table, loc); + int src_line = SOURCE_LINE (map, loc); + + if (print.source == NULL) + print.source = token; + + if (src_line != print.src_line + && do_line_adjustments + && !in_pragma) + { + do_line_change (pfile, token, loc, false); + putc (' ', print.outf); + } + else if (print.source->flags & PREV_WHITE + || (print.prev + && cpp_avoid_paste (pfile, print.prev, token)) + || (print.prev == NULL && token->type == CPP_HASH)) + putc (' ', print.outf); + } + else if (token->flags & PREV_WHITE) + { + const struct line_map *map + = linemap_lookup (line_table, loc); + int src_line = SOURCE_LINE (map, loc); + + if (src_line != print.src_line + && do_line_adjustments + && !in_pragma) + do_line_change (pfile, token, loc, false); + putc (' ', print.outf); + } + + avoid_paste = false; + print.source = NULL; + print.prev = token; + if (token->type == CPP_PRAGMA) + { + const char *space; + const char *name; + + maybe_print_line (token->src_loc); + fputs ("#pragma ", print.outf); + c_pp_lookup_pragma (token->val.pragma, &space, &name); + if (space) + fprintf (print.outf, "%s %s", space, name); + else + fprintf (print.outf, "%s", name); + print.printed = 1; + in_pragma = true; + } + else if (token->type == CPP_PRAGMA_EOL) + { + maybe_print_line (token->src_loc); + in_pragma = false; + } + else + cpp_output_token (token, print.outf); + + if (token->type == CPP_COMMENT) + account_for_newlines (token->val.str.text, token->val.str.len); + } +} + +static void +print_lines_directives_only (int lines, const void *buf, size_t size) +{ + print.src_line += lines; + fwrite (buf, 1, size, print.outf); +} + +/* Writes out the preprocessed file, handling spacing and paste + avoidance issues. */ +static void +scan_translation_unit_directives_only (cpp_reader *pfile) +{ + struct _cpp_dir_only_callbacks cb; + + cb.print_lines = print_lines_directives_only; + cb.maybe_print_line = maybe_print_line; + + _cpp_preprocess_dir_only (pfile, &cb); +} + +/* Adjust print.src_line for newlines embedded in output. */ +static void +account_for_newlines (const unsigned char *str, size_t len) +{ + while (len--) + if (*str++ == '\n') + print.src_line++; +} + +/* Writes out a traditionally preprocessed file. */ +static void +scan_translation_unit_trad (cpp_reader *pfile) +{ + while (_cpp_read_logical_line_trad (pfile)) + { + size_t len = pfile->out.cur - pfile->out.base; + maybe_print_line (pfile->out.first_line); + fwrite (pfile->out.base, 1, len, print.outf); + print.printed = 1; + if (!CPP_OPTION (pfile, discard_comments)) + account_for_newlines (pfile->out.base, len); + } +} + +/* If the token read on logical line LINE needs to be output on a + different line to the current one, output the required newlines or + a line marker, and return 1. Otherwise return 0. */ +static void +maybe_print_line (source_location src_loc) +{ + const struct line_map *map = linemap_lookup (line_table, src_loc); + int src_line = SOURCE_LINE (map, src_loc); + /* End the previous line of text. */ + if (print.printed) + { + putc ('\n', print.outf); + print.src_line++; + print.printed = 0; + } + + if (src_line >= print.src_line && src_line < print.src_line + 8) + { + while (src_line > print.src_line) + { + putc ('\n', print.outf); + print.src_line++; + } + } + else + print_line (src_loc, ""); +} + +/* Output a line marker for logical line LINE. Special flags are "1" + or "2" indicating entering or leaving a file. */ +static void +print_line (source_location src_loc, const char *special_flags) +{ + /* End any previous line of text. */ + if (print.printed) + putc ('\n', print.outf); + print.printed = 0; + + if (!flag_no_line_commands) + { + const struct line_map *map = linemap_lookup (line_table, src_loc); + + size_t to_file_len = strlen (map->to_file); + unsigned char *to_file_quoted = + (unsigned char *) alloca (to_file_len * 4 + 1); + unsigned char *p; + + print.src_line = SOURCE_LINE (map, src_loc); + + /* cpp_quote_string does not nul-terminate, so we have to do it + ourselves. */ + p = cpp_quote_string (to_file_quoted, + (const unsigned char *) map->to_file, to_file_len); + *p = '\0'; + fprintf (print.outf, "# %u \"%s\"%s", + print.src_line == 0 ? 1 : print.src_line, + to_file_quoted, special_flags); + + if (map->sysp == 2) + fputs (" 3 4", print.outf); + else if (map->sysp == 1) + fputs (" 3", print.outf); + + putc ('\n', print.outf); + } +} + +/* Helper function for cb_line_change and scan_translation_unit. */ +static void +do_line_change (cpp_reader *pfile, const cpp_token *token, + source_location src_loc, int parsing_args) +{ + if (define_queue || undef_queue) + dump_queued_macros (pfile); + + if (token->type == CPP_EOF || parsing_args) + return; + + maybe_print_line (src_loc); + print.prev = 0; + print.source = 0; + + /* Supply enough spaces to put this token in its original column, + one space per column greater than 2, since scan_translation_unit + will provide a space if PREV_WHITE. Don't bother trying to + reconstruct tabs; we can't get it right in general, and nothing + ought to care. Some things do care; the fault lies with them. */ + if (!CPP_OPTION (pfile, traditional)) + { + const struct line_map *map = linemap_lookup (line_table, src_loc); + int spaces = SOURCE_COLUMN (map, src_loc) - 2; + print.printed = 1; + + while (-- spaces >= 0) + putc (' ', print.outf); + } +} + +/* Called when a line of output is started. TOKEN is the first token + of the line, and at end of file will be CPP_EOF. */ +static void +cb_line_change (cpp_reader *pfile, const cpp_token *token, + int parsing_args) +{ + do_line_change (pfile, token, token->src_loc, parsing_args); +} + +static void +cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line, + const cpp_string *str) +{ + maybe_print_line (line); + fprintf (print.outf, "#ident %s\n", str->text); + print.src_line++; +} + +static void +cb_define (cpp_reader *pfile, source_location line, cpp_hashnode *node) +{ + maybe_print_line (line); + fputs ("#define ", print.outf); + + /* 'D' is whole definition; 'N' is name only. */ + if (flag_dump_macros == 'D') + fputs ((const char *) cpp_macro_definition (pfile, node), + print.outf); + else + fputs ((const char *) NODE_NAME (node), print.outf); + + putc ('\n', print.outf); + if (linemap_lookup (line_table, line)->to_line != 0) + print.src_line++; +} + +static void +cb_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line, + cpp_hashnode *node) +{ + maybe_print_line (line); + fprintf (print.outf, "#undef %s\n", NODE_NAME (node)); + print.src_line++; +} + +static void +cb_used_define (cpp_reader *pfile, source_location line ATTRIBUTE_UNUSED, + cpp_hashnode *node) +{ + macro_queue *q; + if (node->flags & NODE_BUILTIN) + return; + q = XNEW (macro_queue); + q->macro = xstrdup ((const char *) cpp_macro_definition (pfile, node)); + q->next = define_queue; + define_queue = q; +} + +static void +cb_used_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, + source_location line ATTRIBUTE_UNUSED, + cpp_hashnode *node) +{ + macro_queue *q; + q = XNEW (macro_queue); + q->macro = xstrdup ((const char *) NODE_NAME (node)); + q->next = undef_queue; + undef_queue = q; +} + +static void +dump_queued_macros (cpp_reader *pfile ATTRIBUTE_UNUSED) +{ + macro_queue *q; + + /* End the previous line of text. */ + if (print.printed) + { + putc ('\n', print.outf); + print.src_line++; + print.printed = 0; + } + + for (q = define_queue; q;) + { + macro_queue *oq; + fputs ("#define ", print.outf); + fputs (q->macro, print.outf); + putc ('\n', print.outf); + print.src_line++; + oq = q; + q = q->next; + free (oq->macro); + free (oq); + } + define_queue = NULL; + for (q = undef_queue; q;) + { + macro_queue *oq; + fprintf (print.outf, "#undef %s\n", q->macro); + print.src_line++; + oq = q; + q = q->next; + free (oq->macro); + free (oq); + } + undef_queue = NULL; +} + +static void +cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line, + const unsigned char *dir, const char *header, int angle_brackets, + const cpp_token **comments) +{ + maybe_print_line (line); + if (angle_brackets) + fprintf (print.outf, "#%s <%s>", dir, header); + else + fprintf (print.outf, "#%s \"%s\"", dir, header); + + if (comments != NULL) + { + while (*comments != NULL) + { + if ((*comments)->flags & PREV_WHITE) + putc (' ', print.outf); + cpp_output_token (*comments, print.outf); + ++comments; + } + } + + putc ('\n', print.outf); + print.src_line++; +} + +/* Callback called when -fworking-director and -E to emit working + directory in cpp output file. */ + +void +pp_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir) +{ + size_t to_file_len = strlen (dir); + unsigned char *to_file_quoted = + (unsigned char *) alloca (to_file_len * 4 + 1); + unsigned char *p; + + /* cpp_quote_string does not nul-terminate, so we have to do it ourselves. */ + p = cpp_quote_string (to_file_quoted, (const unsigned char *) dir, to_file_len); + *p = '\0'; + fprintf (print.outf, "# 1 \"%s//\"\n", to_file_quoted); +} + +/* The file name, line number or system header flags have changed, as + described in MAP. */ + +void +pp_file_change (const struct line_map *map) +{ + const char *flags = ""; + + if (flag_no_line_commands) + return; + + if (map != NULL) + { + input_location = map->start_location; + if (print.first_time) + { + /* Avoid printing foo.i when the main file is foo.c. */ + if (!cpp_get_options (parse_in)->preprocessed) + print_line (map->start_location, flags); + print.first_time = 0; + } + else + { + /* Bring current file to correct line when entering a new file. */ + if (map->reason == LC_ENTER) + { + const struct line_map *from = INCLUDED_FROM (line_table, map); + maybe_print_line (LAST_SOURCE_LINE_LOCATION (from)); + } + if (map->reason == LC_ENTER) + flags = " 1"; + else if (map->reason == LC_LEAVE) + flags = " 2"; + print_line (map->start_location, flags); + } + } +} + +/* Copy a #pragma directive to the preprocessed output. */ +static void +cb_def_pragma (cpp_reader *pfile, source_location line) +{ + maybe_print_line (line); + fputs ("#pragma ", print.outf); + cpp_output_line (pfile, print.outf); + print.src_line++; +} + +/* Dump out the hash table. */ +static int +dump_macro (cpp_reader *pfile, cpp_hashnode *node, void *v ATTRIBUTE_UNUSED) +{ + if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)) + { + fputs ("#define ", print.outf); + fputs ((const char *) cpp_macro_definition (pfile, node), + print.outf); + putc ('\n', print.outf); + print.src_line++; + } + + return 1; +} + +/* Load in the PCH file NAME, open on FD. It was originally searched for + by ORIG_NAME. Also, print out a #include command so that the PCH + file can be loaded when the preprocessed output is compiled. */ + +static void +cb_read_pch (cpp_reader *pfile, const char *name, + int fd, const char *orig_name ATTRIBUTE_UNUSED) +{ + c_common_read_pch (pfile, name, fd, orig_name); + + fprintf (print.outf, "#pragma GCC pch_preprocess \"%s\"\n", name); + print.src_line++; +} diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c new file mode 100644 index 0000000..a48bf4f --- /dev/null +++ b/gcc/c-family/c-pragma.c @@ -0,0 +1,1336 @@ +/* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack. + Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + 2006, 2007, 2008 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 "tree.h" +#include "function.h" /* For cfun. FIXME: Does the parser know + when it is inside a function, so that + we don't have to look at cfun? */ +#include "cpplib.h" +#include "c-pragma.h" +#include "flags.h" +#include "toplev.h" +#include "c-common.h" +#include "output.h" +#include "tm_p.h" /* For REGISTER_TARGET_PRAGMAS (why is + this not a target hook?). */ +#include "vec.h" +#include "vecprim.h" +#include "target.h" +#include "diagnostic.h" +#include "opts.h" +#include "plugin.h" + +#define GCC_BAD(gmsgid) \ + do { warning (OPT_Wpragmas, gmsgid); return; } while (0) +#define GCC_BAD2(gmsgid, arg) \ + do { warning (OPT_Wpragmas, gmsgid, arg); return; } while (0) + +typedef struct GTY(()) align_stack { + int alignment; + tree id; + struct align_stack * prev; +} align_stack; + +static GTY(()) struct align_stack * alignment_stack; + +#ifdef HANDLE_PRAGMA_PACK +static void handle_pragma_pack (cpp_reader *); + +#ifdef HANDLE_PRAGMA_PACK_PUSH_POP +/* If we have a "global" #pragma pack() in effect when the first + #pragma pack(push,) is encountered, this stores the value of + maximum_field_alignment in effect. When the final pop_alignment() + happens, we restore the value to this, not to a value of 0 for + maximum_field_alignment. Value is in bits. */ +static int default_alignment; +#define SET_GLOBAL_ALIGNMENT(ALIGN) (maximum_field_alignment = *(alignment_stack == NULL \ + ? &default_alignment \ + : &alignment_stack->alignment) = (ALIGN)) + +static void push_alignment (int, tree); +static void pop_alignment (tree); + +/* Push an alignment value onto the stack. */ +static void +push_alignment (int alignment, tree id) +{ + align_stack * entry; + + entry = GGC_NEW (align_stack); + + entry->alignment = alignment; + entry->id = id; + entry->prev = alignment_stack; + + /* The current value of maximum_field_alignment is not necessarily + 0 since there may be a #pragma pack() in effect; remember it + so that we can restore it after the final #pragma pop(). */ + if (alignment_stack == NULL) + default_alignment = maximum_field_alignment; + + alignment_stack = entry; + + maximum_field_alignment = alignment; +} + +/* Undo a push of an alignment onto the stack. */ +static void +pop_alignment (tree id) +{ + align_stack * entry; + + if (alignment_stack == NULL) + GCC_BAD ("#pragma pack (pop) encountered without matching #pragma pack (push)"); + + /* If we got an identifier, strip away everything above the target + entry so that the next step will restore the state just below it. */ + if (id) + { + for (entry = alignment_stack; entry; entry = entry->prev) + if (entry->id == id) + { + alignment_stack = entry; + break; + } + if (entry == NULL) + warning (OPT_Wpragmas, "\ +#pragma pack(pop, %E) encountered without matching #pragma pack(push, %E)" + , id, id); + } + + entry = alignment_stack->prev; + + maximum_field_alignment = entry ? entry->alignment : default_alignment; + + alignment_stack = entry; +} +#else /* not HANDLE_PRAGMA_PACK_PUSH_POP */ +#define SET_GLOBAL_ALIGNMENT(ALIGN) (maximum_field_alignment = (ALIGN)) +#define push_alignment(ID, N) \ + GCC_BAD ("#pragma pack(push[, id], ) is not supported on this target") +#define pop_alignment(ID) \ + GCC_BAD ("#pragma pack(pop[, id], ) is not supported on this target") +#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ + +/* #pragma pack () + #pragma pack (N) + + #pragma pack (push) + #pragma pack (push, N) + #pragma pack (push, ID) + #pragma pack (push, ID, N) + #pragma pack (pop) + #pragma pack (pop, ID) */ +static void +handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy)) +{ + tree x, id = 0; + int align = -1; + enum cpp_ttype token; + enum { set, push, pop } action; + + if (pragma_lex (&x) != CPP_OPEN_PAREN) + GCC_BAD ("missing %<(%> after %<#pragma pack%> - ignored"); + + token = pragma_lex (&x); + if (token == CPP_CLOSE_PAREN) + { + action = set; + align = initial_max_fld_align; + } + else if (token == CPP_NUMBER) + { + if (TREE_CODE (x) != INTEGER_CST) + GCC_BAD ("invalid constant in %<#pragma pack%> - ignored"); + align = TREE_INT_CST_LOW (x); + action = set; + if (pragma_lex (&x) != CPP_CLOSE_PAREN) + GCC_BAD ("malformed %<#pragma pack%> - ignored"); + } + else if (token == CPP_NAME) + { +#define GCC_BAD_ACTION do { if (action != pop) \ + GCC_BAD ("malformed %<#pragma pack(push[, id][, ])%> - ignored"); \ + else \ + GCC_BAD ("malformed %<#pragma pack(pop[, id])%> - ignored"); \ + } while (0) + + const char *op = IDENTIFIER_POINTER (x); + if (!strcmp (op, "push")) + action = push; + else if (!strcmp (op, "pop")) + action = pop; + else + GCC_BAD2 ("unknown action %qE for %<#pragma pack%> - ignored", x); + + while ((token = pragma_lex (&x)) == CPP_COMMA) + { + token = pragma_lex (&x); + if (token == CPP_NAME && id == 0) + { + id = x; + } + else if (token == CPP_NUMBER && action == push && align == -1) + { + if (TREE_CODE (x) != INTEGER_CST) + GCC_BAD ("invalid constant in %<#pragma pack%> - ignored"); + align = TREE_INT_CST_LOW (x); + if (align == -1) + action = set; + } + else + GCC_BAD_ACTION; + } + + if (token != CPP_CLOSE_PAREN) + GCC_BAD_ACTION; +#undef GCC_BAD_ACTION + } + else + GCC_BAD ("malformed %<#pragma pack%> - ignored"); + + if (pragma_lex (&x) != CPP_EOF) + warning (OPT_Wpragmas, "junk at end of %<#pragma pack%>"); + + if (flag_pack_struct) + GCC_BAD ("#pragma pack has no effect with -fpack-struct - ignored"); + + if (action != pop) + switch (align) + { + case 0: + case 1: + case 2: + case 4: + case 8: + case 16: + align *= BITS_PER_UNIT; + break; + case -1: + if (action == push) + { + align = maximum_field_alignment; + break; + } + default: + GCC_BAD2 ("alignment must be a small power of two, not %d", align); + } + + switch (action) + { + case set: SET_GLOBAL_ALIGNMENT (align); break; + case push: push_alignment (align, id); break; + case pop: pop_alignment (id); break; + } +} +#endif /* HANDLE_PRAGMA_PACK */ + +typedef struct GTY(()) pending_weak_d +{ + tree name; + tree value; +} pending_weak; + +DEF_VEC_O(pending_weak); +DEF_VEC_ALLOC_O(pending_weak,gc); + +static GTY(()) VEC(pending_weak,gc) *pending_weaks; + +#ifdef HANDLE_PRAGMA_WEAK +static void apply_pragma_weak (tree, tree); +static void handle_pragma_weak (cpp_reader *); + +static void +apply_pragma_weak (tree decl, tree value) +{ + if (value) + { + value = build_string (IDENTIFIER_LENGTH (value), + IDENTIFIER_POINTER (value)); + decl_attributes (&decl, build_tree_list (get_identifier ("alias"), + build_tree_list (NULL, value)), + 0); + } + + if (SUPPORTS_WEAK && DECL_EXTERNAL (decl) && TREE_USED (decl) + && !DECL_WEAK (decl) /* Don't complain about a redundant #pragma. */ + && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) + warning (OPT_Wpragmas, "applying #pragma weak %q+D after first use " + "results in unspecified behavior", decl); + + declare_weak (decl); +} + +void +maybe_apply_pragma_weak (tree decl) +{ + tree id; + int i; + pending_weak *pe; + + /* Avoid asking for DECL_ASSEMBLER_NAME when it's not needed. */ + + /* No weak symbols pending, take the short-cut. */ + if (!pending_weaks) + return; + /* If it's not visible outside this file, it doesn't matter whether + it's weak. */ + if (!DECL_EXTERNAL (decl) && !TREE_PUBLIC (decl)) + return; + /* If it's not a function or a variable, it can't be weak. + FIXME: what kinds of things are visible outside this file but + aren't functions or variables? Should this be an assert instead? */ + if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL) + return; + + id = DECL_ASSEMBLER_NAME (decl); + + for (i = 0; VEC_iterate (pending_weak, pending_weaks, i, pe); i++) + if (id == pe->name) + { + apply_pragma_weak (decl, pe->value); + VEC_unordered_remove (pending_weak, pending_weaks, i); + break; + } +} + +/* Process all "#pragma weak A = B" directives where we have not seen + a decl for A. */ +void +maybe_apply_pending_pragma_weaks (void) +{ + tree alias_id, id, decl; + int i; + pending_weak *pe; + + for (i = 0; VEC_iterate (pending_weak, pending_weaks, i, pe); i++) + { + alias_id = pe->name; + id = pe->value; + + if (id == NULL) + continue; + + decl = build_decl (UNKNOWN_LOCATION, + FUNCTION_DECL, alias_id, default_function_type); + + DECL_ARTIFICIAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = 1; + DECL_WEAK (decl) = 1; + + assemble_alias (decl, id); + } +} + +/* #pragma weak name [= value] */ +static void +handle_pragma_weak (cpp_reader * ARG_UNUSED (dummy)) +{ + tree name, value, x, decl; + enum cpp_ttype t; + + value = 0; + + if (pragma_lex (&name) != CPP_NAME) + GCC_BAD ("malformed #pragma weak, ignored"); + t = pragma_lex (&x); + if (t == CPP_EQ) + { + if (pragma_lex (&value) != CPP_NAME) + GCC_BAD ("malformed #pragma weak, ignored"); + t = pragma_lex (&x); + } + if (t != CPP_EOF) + warning (OPT_Wpragmas, "junk at end of %<#pragma weak%>"); + + decl = identifier_global_value (name); + if (decl && DECL_P (decl)) + { + apply_pragma_weak (decl, value); + if (value) + assemble_alias (decl, value); + } + else + { + pending_weak *pe; + pe = VEC_safe_push (pending_weak, gc, pending_weaks, NULL); + pe->name = name; + pe->value = value; + } +} +#else +void +maybe_apply_pragma_weak (tree ARG_UNUSED (decl)) +{ +} + +void +maybe_apply_pending_pragma_weaks (void) +{ +} +#endif /* HANDLE_PRAGMA_WEAK */ + +/* GCC supports two #pragma directives for renaming the external + symbol associated with a declaration (DECL_ASSEMBLER_NAME), for + compatibility with the Solaris and Tru64 system headers. GCC also + has its own notation for this, __asm__("name") annotations. + + Corner cases of these features and their interaction: + + 1) Both pragmas silently apply only to declarations with external + linkage (that is, TREE_PUBLIC || DECL_EXTERNAL). Asm labels + do not have this restriction. + + 2) In C++, both #pragmas silently apply only to extern "C" declarations. + Asm labels do not have this restriction. + + 3) If any of the three ways of changing DECL_ASSEMBLER_NAME is + applied to a decl whose DECL_ASSEMBLER_NAME is already set, and the + new name is different, a warning issues and the name does not change. + + 4) The "source name" for #pragma redefine_extname is the DECL_NAME, + *not* the DECL_ASSEMBLER_NAME. + + 5) If #pragma extern_prefix is in effect and a declaration occurs + with an __asm__ name, the #pragma extern_prefix is silently + ignored for that declaration. + + 6) If #pragma extern_prefix and #pragma redefine_extname apply to + the same declaration, whichever triggered first wins, and a warning + is issued. (We would like to have #pragma redefine_extname always + win, but it can appear either before or after the declaration, and + if it appears afterward, we have no way of knowing whether a modified + DECL_ASSEMBLER_NAME is due to #pragma extern_prefix.) */ + +static GTY(()) tree pending_redefine_extname; + +static void handle_pragma_redefine_extname (cpp_reader *); + +/* #pragma redefine_extname oldname newname */ +static void +handle_pragma_redefine_extname (cpp_reader * ARG_UNUSED (dummy)) +{ + tree oldname, newname, decl, x; + enum cpp_ttype t; + + if (pragma_lex (&oldname) != CPP_NAME) + GCC_BAD ("malformed #pragma redefine_extname, ignored"); + if (pragma_lex (&newname) != CPP_NAME) + GCC_BAD ("malformed #pragma redefine_extname, ignored"); + t = pragma_lex (&x); + if (t != CPP_EOF) + warning (OPT_Wpragmas, "junk at end of %<#pragma redefine_extname%>"); + + decl = identifier_global_value (oldname); + if (decl + && (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)) + && (TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == VAR_DECL) + && has_c_linkage (decl)) + { + if (DECL_ASSEMBLER_NAME_SET_P (decl)) + { + const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + name = targetm.strip_name_encoding (name); + + if (strcmp (name, IDENTIFIER_POINTER (newname))) + warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to " + "conflict with previous rename"); + } + else + change_decl_assembler_name (decl, newname); + } + else + /* We have to add this to the rename list even if there's already + a global value that doesn't meet the above criteria, because in + C++ "struct foo {...};" puts "foo" in the current namespace but + does *not* conflict with a subsequent declaration of a function + or variable foo. See g++.dg/other/pragma-re-2.C. */ + add_to_renaming_pragma_list (oldname, newname); +} + +/* This is called from here and from ia64.c. */ +void +add_to_renaming_pragma_list (tree oldname, tree newname) +{ + tree previous = purpose_member (oldname, pending_redefine_extname); + if (previous) + { + if (TREE_VALUE (previous) != newname) + warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to " + "conflict with previous #pragma redefine_extname"); + return; + } + + pending_redefine_extname + = tree_cons (oldname, newname, pending_redefine_extname); +} + +static GTY(()) tree pragma_extern_prefix; + +/* #pragma extern_prefix "prefix" */ +static void +handle_pragma_extern_prefix (cpp_reader * ARG_UNUSED (dummy)) +{ + tree prefix, x; + enum cpp_ttype t; + + if (pragma_lex (&prefix) != CPP_STRING) + GCC_BAD ("malformed #pragma extern_prefix, ignored"); + t = pragma_lex (&x); + if (t != CPP_EOF) + warning (OPT_Wpragmas, "junk at end of %<#pragma extern_prefix%>"); + + if (targetm.handle_pragma_extern_prefix) + /* Note that the length includes the null terminator. */ + pragma_extern_prefix = (TREE_STRING_LENGTH (prefix) > 1 ? prefix : NULL); + else if (warn_unknown_pragmas > in_system_header) + warning (OPT_Wunknown_pragmas, + "#pragma extern_prefix not supported on this target"); +} + +/* Hook from the front ends to apply the results of one of the preceding + pragmas that rename variables. */ + +tree +maybe_apply_renaming_pragma (tree decl, tree asmname) +{ + tree *p, t; + + /* The renaming pragmas are only applied to declarations with + external linkage. */ + if ((TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL) + || (!TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) + || !has_c_linkage (decl)) + return asmname; + + /* If the DECL_ASSEMBLER_NAME is already set, it does not change, + but we may warn about a rename that conflicts. */ + if (DECL_ASSEMBLER_NAME_SET_P (decl)) + { + const char *oldname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + oldname = targetm.strip_name_encoding (oldname); + + if (asmname && strcmp (TREE_STRING_POINTER (asmname), oldname)) + warning (OPT_Wpragmas, "asm declaration ignored due to " + "conflict with previous rename"); + + /* Take any pending redefine_extname off the list. */ + for (p = &pending_redefine_extname; (t = *p); p = &TREE_CHAIN (t)) + if (DECL_NAME (decl) == TREE_PURPOSE (t)) + { + /* Only warn if there is a conflict. */ + if (strcmp (IDENTIFIER_POINTER (TREE_VALUE (t)), oldname)) + warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to " + "conflict with previous rename"); + + *p = TREE_CHAIN (t); + break; + } + return 0; + } + + /* Find out if we have a pending #pragma redefine_extname. */ + for (p = &pending_redefine_extname; (t = *p); p = &TREE_CHAIN (t)) + if (DECL_NAME (decl) == TREE_PURPOSE (t)) + { + tree newname = TREE_VALUE (t); + *p = TREE_CHAIN (t); + + /* If we already have an asmname, #pragma redefine_extname is + ignored (with a warning if it conflicts). */ + if (asmname) + { + if (strcmp (TREE_STRING_POINTER (asmname), + IDENTIFIER_POINTER (newname)) != 0) + warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to " + "conflict with __asm__ declaration"); + return asmname; + } + + /* Otherwise we use what we've got; #pragma extern_prefix is + silently ignored. */ + return build_string (IDENTIFIER_LENGTH (newname), + IDENTIFIER_POINTER (newname)); + } + + /* If we've got an asmname, #pragma extern_prefix is silently ignored. */ + if (asmname) + return asmname; + + /* If #pragma extern_prefix is in effect, apply it. */ + if (pragma_extern_prefix) + { + const char *prefix = TREE_STRING_POINTER (pragma_extern_prefix); + size_t plen = TREE_STRING_LENGTH (pragma_extern_prefix) - 1; + + const char *id = IDENTIFIER_POINTER (DECL_NAME (decl)); + size_t ilen = IDENTIFIER_LENGTH (DECL_NAME (decl)); + + char *newname = (char *) alloca (plen + ilen + 1); + + memcpy (newname, prefix, plen); + memcpy (newname + plen, id, ilen + 1); + + return build_string (plen + ilen, newname); + } + + /* Nada. */ + return 0; +} + + +#ifdef HANDLE_PRAGMA_VISIBILITY +static void handle_pragma_visibility (cpp_reader *); + +static VEC (int, heap) *visstack; + +/* Push the visibility indicated by STR onto the top of the #pragma + visibility stack. KIND is 0 for #pragma GCC visibility, 1 for + C++ namespace with visibility attribute and 2 for C++ builtin + ABI namespace. push_visibility/pop_visibility calls must have + matching KIND, it is not allowed to push visibility using one + KIND and pop using a different one. */ + +void +push_visibility (const char *str, int kind) +{ + VEC_safe_push (int, heap, visstack, + ((int) default_visibility) | (kind << 8)); + if (!strcmp (str, "default")) + default_visibility = VISIBILITY_DEFAULT; + else if (!strcmp (str, "internal")) + default_visibility = VISIBILITY_INTERNAL; + else if (!strcmp (str, "hidden")) + default_visibility = VISIBILITY_HIDDEN; + else if (!strcmp (str, "protected")) + default_visibility = VISIBILITY_PROTECTED; + else + GCC_BAD ("#pragma GCC visibility push() must specify default, internal, hidden or protected"); + visibility_options.inpragma = 1; +} + +/* Pop a level of the #pragma visibility stack. Return true if + successful. */ + +bool +pop_visibility (int kind) +{ + if (!VEC_length (int, visstack)) + return false; + if ((VEC_last (int, visstack) >> 8) != kind) + return false; + default_visibility + = (enum symbol_visibility) (VEC_pop (int, visstack) & 0xff); + visibility_options.inpragma + = VEC_length (int, visstack) != 0; + return true; +} + +/* Sets the default visibility for symbols to something other than that + specified on the command line. */ + +static void +handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED) +{ + /* Form is #pragma GCC visibility push(hidden)|pop */ + tree x; + enum cpp_ttype token; + enum { bad, push, pop } action = bad; + + token = pragma_lex (&x); + if (token == CPP_NAME) + { + const char *op = IDENTIFIER_POINTER (x); + if (!strcmp (op, "push")) + action = push; + else if (!strcmp (op, "pop")) + action = pop; + } + if (bad == action) + GCC_BAD ("#pragma GCC visibility must be followed by push or pop"); + else + { + if (pop == action) + { + if (! pop_visibility (0)) + GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>"); + } + else + { + if (pragma_lex (&x) != CPP_OPEN_PAREN) + GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored"); + token = pragma_lex (&x); + if (token != CPP_NAME) + GCC_BAD ("malformed #pragma GCC visibility push"); + else + push_visibility (IDENTIFIER_POINTER (x), 0); + if (pragma_lex (&x) != CPP_CLOSE_PAREN) + GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored"); + } + } + if (pragma_lex (&x) != CPP_EOF) + warning (OPT_Wpragmas, "junk at end of %<#pragma GCC visibility%>"); +} + +#endif + +static void +handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy)) +{ + const char *kind_string, *option_string; + unsigned int option_index; + enum cpp_ttype token; + diagnostic_t kind; + tree x; + + if (cfun) + { + error ("#pragma GCC diagnostic not allowed inside functions"); + return; + } + + token = pragma_lex (&x); + if (token != CPP_NAME) + GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>"); + kind_string = IDENTIFIER_POINTER (x); + if (strcmp (kind_string, "error") == 0) + kind = DK_ERROR; + else if (strcmp (kind_string, "warning") == 0) + kind = DK_WARNING; + else if (strcmp (kind_string, "ignored") == 0) + kind = DK_IGNORED; + else + GCC_BAD ("expected [error|warning|ignored] after %<#pragma GCC diagnostic%>"); + + token = pragma_lex (&x); + if (token != CPP_STRING) + GCC_BAD ("missing option after %<#pragma GCC diagnostic%> kind"); + option_string = TREE_STRING_POINTER (x); + for (option_index = 0; option_index < cl_options_count; option_index++) + if (strcmp (cl_options[option_index].opt_text, option_string) == 0) + { + /* This overrides -Werror, for example. */ + diagnostic_classify_diagnostic (global_dc, option_index, kind); + /* This makes sure the option is enabled, like -Wfoo would do. */ + if (cl_options[option_index].var_type == CLVC_BOOLEAN + && cl_options[option_index].flag_var + && kind != DK_IGNORED) + *(int *) cl_options[option_index].flag_var = 1; + return; + } + GCC_BAD ("unknown option after %<#pragma GCC diagnostic%> kind"); +} + +/* Parse #pragma GCC target (xxx) to set target specific options. */ +static void +handle_pragma_target(cpp_reader *ARG_UNUSED(dummy)) +{ + enum cpp_ttype token; + tree x; + bool close_paren_needed_p = false; + + if (cfun) + { + error ("#pragma GCC option is not allowed inside functions"); + return; + } + + token = pragma_lex (&x); + if (token == CPP_OPEN_PAREN) + { + close_paren_needed_p = true; + token = pragma_lex (&x); + } + + if (token != CPP_STRING) + { + GCC_BAD ("%<#pragma GCC option%> is not a string"); + return; + } + + /* Strings are user options. */ + else + { + tree args = NULL_TREE; + + do + { + /* Build up the strings now as a tree linked list. Skip empty + strings. */ + if (TREE_STRING_LENGTH (x) > 0) + args = tree_cons (NULL_TREE, x, args); + + token = pragma_lex (&x); + while (token == CPP_COMMA) + token = pragma_lex (&x); + } + while (token == CPP_STRING); + + if (close_paren_needed_p) + { + if (token == CPP_CLOSE_PAREN) + token = pragma_lex (&x); + else + GCC_BAD ("%<#pragma GCC target (string [,string]...)%> does " + "not have a final %<)%>."); + } + + if (token != CPP_EOF) + { + error ("#pragma GCC target string... is badly formed"); + return; + } + + /* put arguments in the order the user typed them. */ + args = nreverse (args); + + if (targetm.target_option.pragma_parse (args, NULL_TREE)) + current_target_pragma = args; + } +} + +/* Handle #pragma GCC optimize to set optimization options. */ +static void +handle_pragma_optimize (cpp_reader *ARG_UNUSED(dummy)) +{ + enum cpp_ttype token; + tree x; + bool close_paren_needed_p = false; + tree optimization_previous_node = optimization_current_node; + + if (cfun) + { + error ("#pragma GCC optimize is not allowed inside functions"); + return; + } + + token = pragma_lex (&x); + if (token == CPP_OPEN_PAREN) + { + close_paren_needed_p = true; + token = pragma_lex (&x); + } + + if (token != CPP_STRING && token != CPP_NUMBER) + { + GCC_BAD ("%<#pragma GCC optimize%> is not a string or number"); + return; + } + + /* Strings/numbers are user options. */ + else + { + tree args = NULL_TREE; + + do + { + /* Build up the numbers/strings now as a list. */ + if (token != CPP_STRING || TREE_STRING_LENGTH (x) > 0) + args = tree_cons (NULL_TREE, x, args); + + token = pragma_lex (&x); + while (token == CPP_COMMA) + token = pragma_lex (&x); + } + while (token == CPP_STRING || token == CPP_NUMBER); + + if (close_paren_needed_p) + { + if (token == CPP_CLOSE_PAREN) + token = pragma_lex (&x); + else + GCC_BAD ("%<#pragma GCC optimize (string [,string]...)%> does " + "not have a final %<)%>."); + } + + if (token != CPP_EOF) + { + error ("#pragma GCC optimize string... is badly formed"); + return; + } + + /* put arguments in the order the user typed them. */ + args = nreverse (args); + + parse_optimize_options (args, false); + current_optimize_pragma = chainon (current_optimize_pragma, args); + optimization_current_node = build_optimization_node (); + c_cpp_builtins_optimize_pragma (parse_in, + optimization_previous_node, + optimization_current_node); + } +} + +/* Stack of the #pragma GCC options created with #pragma GCC push_option. Save + both the binary representation of the options and the TREE_LIST of + strings that will be added to the function's attribute list. */ +typedef struct GTY(()) opt_stack { + struct opt_stack *prev; + tree target_binary; + tree target_strings; + tree optimize_binary; + tree optimize_strings; +} opt_stack; + +static GTY(()) struct opt_stack * options_stack; + +/* Handle #pragma GCC push_options to save the current target and optimization + options. */ + +static void +handle_pragma_push_options (cpp_reader *ARG_UNUSED(dummy)) +{ + enum cpp_ttype token; + tree x = 0; + opt_stack *p; + + token = pragma_lex (&x); + if (token != CPP_EOF) + { + warning (OPT_Wpragmas, "junk at end of %<#pragma push_options%>"); + return; + } + + p = GGC_NEW (opt_stack); + p->prev = options_stack; + options_stack = p; + + /* Save optimization and target flags in binary format. */ + p->optimize_binary = build_optimization_node (); + p->target_binary = build_target_option_node (); + + /* Save optimization and target flags in string list format. */ + p->optimize_strings = copy_list (current_optimize_pragma); + p->target_strings = copy_list (current_target_pragma); +} + +/* Handle #pragma GCC pop_options to restore the current target and + optimization options from a previous push_options. */ + +static void +handle_pragma_pop_options (cpp_reader *ARG_UNUSED(dummy)) +{ + enum cpp_ttype token; + tree x = 0; + opt_stack *p; + + token = pragma_lex (&x); + if (token != CPP_EOF) + { + warning (OPT_Wpragmas, "junk at end of %<#pragma pop_options%>"); + return; + } + + if (! options_stack) + { + warning (OPT_Wpragmas, + "%<#pragma GCC pop_options%> without a corresponding " + "%<#pragma GCC push_options%>"); + return; + } + + p = options_stack; + options_stack = p->prev; + + if (p->target_binary != target_option_current_node) + { + (void) targetm.target_option.pragma_parse (NULL_TREE, p->target_binary); + target_option_current_node = p->target_binary; + } + + if (p->optimize_binary != optimization_current_node) + { + tree old_optimize = optimization_current_node; + cl_optimization_restore (TREE_OPTIMIZATION (p->optimize_binary)); + c_cpp_builtins_optimize_pragma (parse_in, old_optimize, + p->optimize_binary); + optimization_current_node = p->optimize_binary; + } + + current_target_pragma = p->target_strings; + current_optimize_pragma = p->optimize_strings; +} + +/* Handle #pragma GCC reset_options to restore the current target and + optimization options to the original options used on the command line. */ + +static void +handle_pragma_reset_options (cpp_reader *ARG_UNUSED(dummy)) +{ + enum cpp_ttype token; + tree x = 0; + tree new_optimize = optimization_default_node; + tree new_target = target_option_default_node; + + token = pragma_lex (&x); + if (token != CPP_EOF) + { + warning (OPT_Wpragmas, "junk at end of %<#pragma reset_options%>"); + return; + } + + if (new_target != target_option_current_node) + { + (void) targetm.target_option.pragma_parse (NULL_TREE, new_target); + target_option_current_node = new_target; + } + + if (new_optimize != optimization_current_node) + { + tree old_optimize = optimization_current_node; + cl_optimization_restore (TREE_OPTIMIZATION (new_optimize)); + c_cpp_builtins_optimize_pragma (parse_in, old_optimize, new_optimize); + optimization_current_node = new_optimize; + } + + current_target_pragma = NULL_TREE; + current_optimize_pragma = NULL_TREE; +} + +/* Print a plain user-specified message. */ + +static void +handle_pragma_message (cpp_reader *ARG_UNUSED(dummy)) +{ + enum cpp_ttype token; + tree x, message = 0; + + token = pragma_lex (&x); + if (token == CPP_OPEN_PAREN) + { + token = pragma_lex (&x); + if (token == CPP_STRING) + message = x; + else + GCC_BAD ("expected a string after %<#pragma message%>"); + if (pragma_lex (&x) != CPP_CLOSE_PAREN) + GCC_BAD ("malformed %<#pragma message%>, ignored"); + } + else if (token == CPP_STRING) + message = x; + else + GCC_BAD ("expected a string after %<#pragma message%>"); + + gcc_assert (message); + + if (pragma_lex (&x) != CPP_EOF) + warning (OPT_Wpragmas, "junk at end of %<#pragma message%>"); + + if (TREE_STRING_LENGTH (message) > 1) + inform (input_location, "#pragma message: %s", TREE_STRING_POINTER (message)); +} + +/* Mark whether the current location is valid for a STDC pragma. */ + +static bool valid_location_for_stdc_pragma; + +void +mark_valid_location_for_stdc_pragma (bool flag) +{ + valid_location_for_stdc_pragma = flag; +} + +/* Return true if the current location is valid for a STDC pragma. */ + +bool +valid_location_for_stdc_pragma_p (void) +{ + return valid_location_for_stdc_pragma; +} + +enum pragma_switch_t { PRAGMA_ON, PRAGMA_OFF, PRAGMA_DEFAULT, PRAGMA_BAD }; + +/* A STDC pragma must appear outside of external declarations or + preceding all explicit declarations and statements inside a compound + statement; its behavior is undefined if used in any other context. + It takes a switch of ON, OFF, or DEFAULT. */ + +static enum pragma_switch_t +handle_stdc_pragma (const char *pname) +{ + const char *arg; + tree t; + enum pragma_switch_t ret; + + if (!valid_location_for_stdc_pragma_p ()) + { + warning (OPT_Wpragmas, "invalid location for %, ignored", + pname); + return PRAGMA_BAD; + } + + if (pragma_lex (&t) != CPP_NAME) + { + warning (OPT_Wpragmas, "malformed %<#pragma %s%>, ignored", pname); + return PRAGMA_BAD; + } + + arg = IDENTIFIER_POINTER (t); + + if (!strcmp (arg, "ON")) + ret = PRAGMA_ON; + else if (!strcmp (arg, "OFF")) + ret = PRAGMA_OFF; + else if (!strcmp (arg, "DEFAULT")) + ret = PRAGMA_DEFAULT; + else + { + warning (OPT_Wpragmas, "malformed %<#pragma %s%>, ignored", pname); + return PRAGMA_BAD; + } + + if (pragma_lex (&t) != CPP_EOF) + { + warning (OPT_Wpragmas, "junk at end of %<#pragma %s%>", pname); + return PRAGMA_BAD; + } + + return ret; +} + +/* #pragma STDC FLOAT_CONST_DECIMAL64 ON + #pragma STDC FLOAT_CONST_DECIMAL64 OFF + #pragma STDC FLOAT_CONST_DECIMAL64 DEFAULT */ + +static void +handle_pragma_float_const_decimal64 (cpp_reader *ARG_UNUSED (dummy)) +{ + if (c_dialect_cxx ()) + { + if (warn_unknown_pragmas > in_system_header) + warning (OPT_Wunknown_pragmas, + "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported" + " for C++"); + return; + } + + if (!targetm.decimal_float_supported_p ()) + { + if (warn_unknown_pragmas > in_system_header) + warning (OPT_Wunknown_pragmas, + "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported" + " on this target"); + return; + } + + pedwarn (input_location, OPT_pedantic, + "ISO C does not support %<#pragma STDC FLOAT_CONST_DECIMAL64%>"); + + switch (handle_stdc_pragma ("STDC FLOAT_CONST_DECIMAL64")) + { + case PRAGMA_ON: + set_float_const_decimal64 (); + break; + case PRAGMA_OFF: + case PRAGMA_DEFAULT: + clear_float_const_decimal64 (); + break; + case PRAGMA_BAD: + break; + } +} + +/* A vector of registered pragma callbacks. */ + +DEF_VEC_O (pragma_handler); +DEF_VEC_ALLOC_O (pragma_handler, heap); + +static VEC(pragma_handler, heap) *registered_pragmas; + +typedef struct +{ + const char *space; + const char *name; +} pragma_ns_name; + +DEF_VEC_O (pragma_ns_name); +DEF_VEC_ALLOC_O (pragma_ns_name, heap); + +static VEC(pragma_ns_name, heap) *registered_pp_pragmas; + +struct omp_pragma_def { const char *name; unsigned int id; }; +static const struct omp_pragma_def omp_pragmas[] = { + { "atomic", PRAGMA_OMP_ATOMIC }, + { "barrier", PRAGMA_OMP_BARRIER }, + { "critical", PRAGMA_OMP_CRITICAL }, + { "flush", PRAGMA_OMP_FLUSH }, + { "for", PRAGMA_OMP_FOR }, + { "master", PRAGMA_OMP_MASTER }, + { "ordered", PRAGMA_OMP_ORDERED }, + { "parallel", PRAGMA_OMP_PARALLEL }, + { "section", PRAGMA_OMP_SECTION }, + { "sections", PRAGMA_OMP_SECTIONS }, + { "single", PRAGMA_OMP_SINGLE }, + { "task", PRAGMA_OMP_TASK }, + { "taskwait", PRAGMA_OMP_TASKWAIT }, + { "threadprivate", PRAGMA_OMP_THREADPRIVATE } +}; + +void +c_pp_lookup_pragma (unsigned int id, const char **space, const char **name) +{ + const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas); + int i; + + for (i = 0; i < n_omp_pragmas; ++i) + if (omp_pragmas[i].id == id) + { + *space = "omp"; + *name = omp_pragmas[i].name; + return; + } + + if (id >= PRAGMA_FIRST_EXTERNAL + && (id < PRAGMA_FIRST_EXTERNAL + + VEC_length (pragma_ns_name, registered_pp_pragmas))) + { + *space = VEC_index (pragma_ns_name, registered_pp_pragmas, + id - PRAGMA_FIRST_EXTERNAL)->space; + *name = VEC_index (pragma_ns_name, registered_pp_pragmas, + id - PRAGMA_FIRST_EXTERNAL)->name; + return; + } + + gcc_unreachable (); +} + +/* Front-end wrappers for pragma registration to avoid dragging + cpplib.h in almost everywhere. */ + +static void +c_register_pragma_1 (const char *space, const char *name, + pragma_handler handler, bool allow_expansion) +{ + unsigned id; + + if (flag_preprocess_only) + { + pragma_ns_name ns_name; + + if (!allow_expansion) + return; + + ns_name.space = space; + ns_name.name = name; + VEC_safe_push (pragma_ns_name, heap, registered_pp_pragmas, &ns_name); + id = VEC_length (pragma_ns_name, registered_pp_pragmas); + id += PRAGMA_FIRST_EXTERNAL - 1; + } + else + { + VEC_safe_push (pragma_handler, heap, registered_pragmas, &handler); + id = VEC_length (pragma_handler, registered_pragmas); + id += PRAGMA_FIRST_EXTERNAL - 1; + + /* The C++ front end allocates 6 bits in cp_token; the C front end + allocates 7 bits in c_token. At present this is sufficient. */ + gcc_assert (id < 64); + } + + cpp_register_deferred_pragma (parse_in, space, name, id, + allow_expansion, false); +} + +void +c_register_pragma (const char *space, const char *name, pragma_handler handler) +{ + c_register_pragma_1 (space, name, handler, false); +} + +void +c_register_pragma_with_expansion (const char *space, const char *name, + pragma_handler handler) +{ + c_register_pragma_1 (space, name, handler, true); +} + +void +c_invoke_pragma_handler (unsigned int id) +{ + pragma_handler handler; + + id -= PRAGMA_FIRST_EXTERNAL; + handler = *VEC_index (pragma_handler, registered_pragmas, id); + + handler (parse_in); +} + +/* Set up front-end pragmas. */ +void +init_pragma (void) +{ + if (flag_openmp) + { + const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas); + int i; + + for (i = 0; i < n_omp_pragmas; ++i) + cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas[i].name, + omp_pragmas[i].id, true, true); + } + + if (!flag_preprocess_only) + cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess", + PRAGMA_GCC_PCH_PREPROCESS, false, false); + +#ifdef HANDLE_PRAGMA_PACK +#ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION + c_register_pragma_with_expansion (0, "pack", handle_pragma_pack); +#else + c_register_pragma (0, "pack", handle_pragma_pack); +#endif +#endif +#ifdef HANDLE_PRAGMA_WEAK + c_register_pragma (0, "weak", handle_pragma_weak); +#endif +#ifdef HANDLE_PRAGMA_VISIBILITY + c_register_pragma ("GCC", "visibility", handle_pragma_visibility); +#endif + + c_register_pragma ("GCC", "diagnostic", handle_pragma_diagnostic); + c_register_pragma ("GCC", "target", handle_pragma_target); + c_register_pragma ("GCC", "optimize", handle_pragma_optimize); + c_register_pragma ("GCC", "push_options", handle_pragma_push_options); + c_register_pragma ("GCC", "pop_options", handle_pragma_pop_options); + c_register_pragma ("GCC", "reset_options", handle_pragma_reset_options); + + c_register_pragma ("STDC", "FLOAT_CONST_DECIMAL64", + handle_pragma_float_const_decimal64); + + c_register_pragma_with_expansion (0, "redefine_extname", handle_pragma_redefine_extname); + c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix); + + c_register_pragma_with_expansion (0, "message", handle_pragma_message); + +#ifdef REGISTER_TARGET_PRAGMAS + REGISTER_TARGET_PRAGMAS (); +#endif + + /* Allow plugins to register their own pragmas. */ + invoke_plugin_callbacks (PLUGIN_PRAGMAS, NULL); +} + +#include "gt-c-family-c-pragma.h" diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h new file mode 100644 index 0000000..eab23db --- /dev/null +++ b/gcc/c-family/c-pragma.h @@ -0,0 +1,133 @@ +/* Pragma related interfaces. + Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + 2007, 2008 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 +. */ + +#ifndef GCC_C_PRAGMA_H +#define GCC_C_PRAGMA_H + +#include /* For enum cpp_ttype. */ + +/* Pragma identifiers built in to the front end parsers. Identifiers + for ancillary handlers will follow these. */ +typedef enum pragma_kind { + PRAGMA_NONE = 0, + + PRAGMA_OMP_ATOMIC, + PRAGMA_OMP_BARRIER, + PRAGMA_OMP_CRITICAL, + PRAGMA_OMP_FLUSH, + PRAGMA_OMP_FOR, + PRAGMA_OMP_MASTER, + PRAGMA_OMP_ORDERED, + PRAGMA_OMP_PARALLEL, + PRAGMA_OMP_PARALLEL_FOR, + PRAGMA_OMP_PARALLEL_SECTIONS, + PRAGMA_OMP_SECTION, + PRAGMA_OMP_SECTIONS, + PRAGMA_OMP_SINGLE, + PRAGMA_OMP_TASK, + PRAGMA_OMP_TASKWAIT, + PRAGMA_OMP_THREADPRIVATE, + + PRAGMA_GCC_PCH_PREPROCESS, + + PRAGMA_FIRST_EXTERNAL +} pragma_kind; + + +/* All clauses defined by OpenMP 2.5 and 3.0. + Used internally by both C and C++ parsers. */ +typedef enum pragma_omp_clause { + PRAGMA_OMP_CLAUSE_NONE = 0, + + PRAGMA_OMP_CLAUSE_COLLAPSE, + PRAGMA_OMP_CLAUSE_COPYIN, + PRAGMA_OMP_CLAUSE_COPYPRIVATE, + PRAGMA_OMP_CLAUSE_DEFAULT, + PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, + PRAGMA_OMP_CLAUSE_IF, + PRAGMA_OMP_CLAUSE_LASTPRIVATE, + PRAGMA_OMP_CLAUSE_NOWAIT, + PRAGMA_OMP_CLAUSE_NUM_THREADS, + PRAGMA_OMP_CLAUSE_ORDERED, + PRAGMA_OMP_CLAUSE_PRIVATE, + PRAGMA_OMP_CLAUSE_REDUCTION, + PRAGMA_OMP_CLAUSE_SCHEDULE, + PRAGMA_OMP_CLAUSE_SHARED, + PRAGMA_OMP_CLAUSE_UNTIED +} pragma_omp_clause; + +extern struct cpp_reader* parse_in; + +#define HANDLE_PRAGMA_WEAK SUPPORTS_WEAK + +#ifdef HANDLE_SYSV_PRAGMA +/* We always support #pragma pack for SYSV pragmas. */ +#ifndef HANDLE_PRAGMA_PACK +#define HANDLE_PRAGMA_PACK 1 +#endif +#endif /* HANDLE_SYSV_PRAGMA */ + + +#ifdef HANDLE_PRAGMA_PACK_PUSH_POP +/* If we are supporting #pragma pack(push... then we automatically + support #pragma pack() */ +#define HANDLE_PRAGMA_PACK 1 +#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ + +/* It's safe to always leave visibility pragma enabled as if + visibility is not supported on the host OS platform the + statements are ignored. */ +#define HANDLE_PRAGMA_VISIBILITY 1 +extern void push_visibility (const char *, int); +extern bool pop_visibility (int); + +extern void init_pragma (void); + +/* Front-end wrappers for pragma registration. */ +typedef void (*pragma_handler)(struct cpp_reader *); +extern void c_register_pragma (const char *, const char *, pragma_handler); +extern void c_register_pragma_with_expansion (const char *, const char *, + pragma_handler); +extern void c_invoke_pragma_handler (unsigned int); + +extern void maybe_apply_pragma_weak (tree); +extern void maybe_apply_pending_pragma_weaks (void); +extern tree maybe_apply_renaming_pragma (tree, tree); +extern void add_to_renaming_pragma_list (tree, tree); + +extern enum cpp_ttype pragma_lex (tree *); + +/* Flags for use with c_lex_with_flags. The values here were picked + so that 0 means to translate and join strings. */ +#define C_LEX_STRING_NO_TRANSLATE 1 /* Do not lex strings into + execution character set. */ +#define C_LEX_STRING_NO_JOIN 2 /* Do not concatenate strings + nor translate them into execution + character set. */ + +/* This is not actually available to pragma parsers. It's merely a + convenient location to declare this function for c-lex, after + having enum cpp_ttype declared. */ +extern enum cpp_ttype c_lex_with_flags (tree *, location_t *, unsigned char *, + int); + +extern void c_pp_lookup_pragma (unsigned int, const char **, const char **); + +#endif /* GCC_C_PRAGMA_H */ diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c new file mode 100644 index 0000000..7f4b238 --- /dev/null +++ b/gcc/c-family/c-pretty-print.c @@ -0,0 +1,2282 @@ +/* Subroutines common to both C and C++ pretty-printers. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + 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 "tree.h" +#include "intl.h" +#include "c-pretty-print.h" +#include "tree-pretty-print.h" +#include "tree-iterator.h" +#include "diagnostic.h" + +/* Translate if being used for diagnostics, but not for dump files or + __PRETTY_FUNCTION. */ +#define M_(msgid) (pp_translate_identifiers (pp) ? _(msgid) : (msgid)) + +/* The pretty-printer code is primarily designed to closely follow + (GNU) C and C++ grammars. That is to be contrasted with spaghetti + codes we used to have in the past. Following a structured + approach (preferably the official grammars) is believed to make it + much easier to add extensions and nifty pretty-printing effects that + takes expression or declaration contexts into account. */ + + +#define pp_c_maybe_whitespace(PP) \ + do { \ + if (pp_base (PP)->padding == pp_before) \ + pp_c_whitespace (PP); \ + } while (0) + +/* literal */ +static void pp_c_char (c_pretty_printer *, int); + +/* postfix-expression */ +static void pp_c_initializer_list (c_pretty_printer *, tree); +static void pp_c_brace_enclosed_initializer_list (c_pretty_printer *, tree); + +static void pp_c_multiplicative_expression (c_pretty_printer *, tree); +static void pp_c_additive_expression (c_pretty_printer *, tree); +static void pp_c_shift_expression (c_pretty_printer *, tree); +static void pp_c_relational_expression (c_pretty_printer *, tree); +static void pp_c_equality_expression (c_pretty_printer *, tree); +static void pp_c_and_expression (c_pretty_printer *, tree); +static void pp_c_exclusive_or_expression (c_pretty_printer *, tree); +static void pp_c_inclusive_or_expression (c_pretty_printer *, tree); +static void pp_c_logical_and_expression (c_pretty_printer *, tree); +static void pp_c_conditional_expression (c_pretty_printer *, tree); +static void pp_c_assignment_expression (c_pretty_printer *, tree); + +/* declarations. */ + + +/* Helper functions. */ + +void +pp_c_whitespace (c_pretty_printer *pp) +{ + pp_space (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_left_paren (c_pretty_printer *pp) +{ + pp_left_paren (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_right_paren (c_pretty_printer *pp) +{ + pp_right_paren (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_left_brace (c_pretty_printer *pp) +{ + pp_left_brace (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_right_brace (c_pretty_printer *pp) +{ + pp_right_brace (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_left_bracket (c_pretty_printer *pp) +{ + pp_left_bracket (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_right_bracket (c_pretty_printer *pp) +{ + pp_right_bracket (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_dot (c_pretty_printer *pp) +{ + pp_dot (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_ampersand (c_pretty_printer *pp) +{ + pp_ampersand (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_star (c_pretty_printer *pp) +{ + pp_star (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_arrow (c_pretty_printer *pp) +{ + pp_arrow (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_semicolon (c_pretty_printer *pp) +{ + pp_semicolon (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_complement (c_pretty_printer *pp) +{ + pp_complement (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_exclamation (c_pretty_printer *pp) +{ + pp_exclamation (pp); + pp_base (pp)->padding = pp_none; +} + +/* Print out the external representation of QUALIFIERS. */ + +void +pp_c_cv_qualifiers (c_pretty_printer *pp, int qualifiers, bool func_type) +{ + const char *p = pp_last_position_in_text (pp); + bool previous = false; + + if (!qualifiers) + return; + + /* The C programming language does not have references, but it is much + simpler to handle those here rather than going through the same + logic in the C++ pretty-printer. */ + if (p != NULL && (*p == '*' || *p == '&')) + pp_c_whitespace (pp); + + if (qualifiers & TYPE_QUAL_CONST) + { + pp_c_ws_string (pp, func_type ? "__attribute__((const))" : "const"); + previous = true; + } + + if (qualifiers & TYPE_QUAL_VOLATILE) + { + if (previous) + pp_c_whitespace (pp); + pp_c_ws_string (pp, func_type ? "__attribute__((noreturn))" : "volatile"); + previous = true; + } + + if (qualifiers & TYPE_QUAL_RESTRICT) + { + if (previous) + pp_c_whitespace (pp); + pp_c_ws_string (pp, flag_isoc99 ? "restrict" : "__restrict__"); + } +} + +/* Pretty-print T using the type-cast notation '( type-name )'. */ + +static void +pp_c_type_cast (c_pretty_printer *pp, tree t) +{ + pp_c_left_paren (pp); + pp_type_id (pp, t); + pp_c_right_paren (pp); +} + +/* We're about to pretty-print a pointer type as indicated by T. + Output a whitespace, if needed, preparing for subsequent output. */ + +void +pp_c_space_for_pointer_operator (c_pretty_printer *pp, tree t) +{ + if (POINTER_TYPE_P (t)) + { + tree pointee = strip_pointer_operator (TREE_TYPE (t)); + if (TREE_CODE (pointee) != ARRAY_TYPE + && TREE_CODE (pointee) != FUNCTION_TYPE) + pp_c_whitespace (pp); + } +} + + +/* Declarations. */ + +/* C++ cv-qualifiers are called type-qualifiers in C. Print out the + cv-qualifiers of T. If T is a declaration then it is the cv-qualifier + of its type. Take care of possible extensions. + + type-qualifier-list: + type-qualifier + type-qualifier-list type-qualifier + + type-qualifier: + const + restrict -- C99 + __restrict__ -- GNU C + address-space-qualifier -- GNU C + volatile + + address-space-qualifier: + identifier -- GNU C */ + +void +pp_c_type_qualifier_list (c_pretty_printer *pp, tree t) +{ + int qualifiers; + + if (!t || t == error_mark_node) + return; + + if (!TYPE_P (t)) + t = TREE_TYPE (t); + + qualifiers = TYPE_QUALS (t); + pp_c_cv_qualifiers (pp, qualifiers, + TREE_CODE (t) == FUNCTION_TYPE); + + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t))) + { + const char *as = c_addr_space_name (TYPE_ADDR_SPACE (t)); + pp_c_identifier (pp, as); + } +} + +/* pointer: + * type-qualifier-list(opt) + * type-qualifier-list(opt) pointer */ + +static void +pp_c_pointer (c_pretty_printer *pp, tree t) +{ + if (!TYPE_P (t) && TREE_CODE (t) != TYPE_DECL) + t = TREE_TYPE (t); + switch (TREE_CODE (t)) + { + case POINTER_TYPE: + /* It is easier to handle C++ reference types here. */ + case REFERENCE_TYPE: + if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE) + pp_c_pointer (pp, TREE_TYPE (t)); + if (TREE_CODE (t) == POINTER_TYPE) + pp_c_star (pp); + else + pp_c_ampersand (pp); + pp_c_type_qualifier_list (pp, t); + break; + + /* ??? This node is now in GENERIC and so shouldn't be here. But + we'll fix that later. */ + case DECL_EXPR: + pp_declaration (pp, DECL_EXPR_DECL (t)); + pp_needs_newline (pp) = true; + break; + + default: + pp_unsupported_tree (pp, t); + } +} + +/* type-specifier: + void + char + short + int + long + float + double + signed + unsigned + _Bool -- C99 + _Complex -- C99 + _Imaginary -- C99 + struct-or-union-specifier + enum-specifier + typedef-name. + + GNU extensions. + simple-type-specifier: + __complex__ + __vector__ */ + +void +pp_c_type_specifier (c_pretty_printer *pp, tree t) +{ + const enum tree_code code = TREE_CODE (t); + switch (code) + { + case ERROR_MARK: + pp_c_ws_string (pp, M_("")); + break; + + case IDENTIFIER_NODE: + pp_c_tree_decl_identifier (pp, t); + break; + + case VOID_TYPE: + case BOOLEAN_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + if (TYPE_NAME (t)) + { + t = TYPE_NAME (t); + pp_c_type_specifier (pp, t); + } + else + { + int prec = TYPE_PRECISION (t); + if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (t))) + t = c_common_type_for_mode (TYPE_MODE (t), TYPE_SATURATING (t)); + else + t = c_common_type_for_mode (TYPE_MODE (t), TYPE_UNSIGNED (t)); + if (TYPE_NAME (t)) + { + pp_c_type_specifier (pp, t); + if (TYPE_PRECISION (t) != prec) + { + pp_string (pp, ":"); + pp_decimal_int (pp, prec); + } + } + else + { + switch (code) + { + case INTEGER_TYPE: + pp_string (pp, (TYPE_UNSIGNED (t) + ? M_(""); + } + } + break; + + case TYPE_DECL: + if (DECL_NAME (t)) + pp_id_expression (pp, t); + else + pp_c_ws_string (pp, M_("")); + break; + + case UNION_TYPE: + case RECORD_TYPE: + case ENUMERAL_TYPE: + if (code == UNION_TYPE) + pp_c_ws_string (pp, "union"); + else if (code == RECORD_TYPE) + pp_c_ws_string (pp, "struct"); + else if (code == ENUMERAL_TYPE) + pp_c_ws_string (pp, "enum"); + else + pp_c_ws_string (pp, M_("")); + + if (TYPE_NAME (t)) + pp_id_expression (pp, TYPE_NAME (t)); + else + pp_c_ws_string (pp, M_("")); + break; + + default: + pp_unsupported_tree (pp, t); + break; + } +} + +/* specifier-qualifier-list: + type-specifier specifier-qualifier-list-opt + type-qualifier specifier-qualifier-list-opt + + + Implementation note: Because of the non-linearities in array or + function declarations, this routine prints not just the + specifier-qualifier-list of such entities or types of such entities, + but also the 'pointer' production part of their declarators. The + remaining part is done by pp_declarator or pp_c_abstract_declarator. */ + +void +pp_c_specifier_qualifier_list (c_pretty_printer *pp, tree t) +{ + const enum tree_code code = TREE_CODE (t); + + if (TREE_CODE (t) != POINTER_TYPE) + pp_c_type_qualifier_list (pp, t); + switch (code) + { + case REFERENCE_TYPE: + case POINTER_TYPE: + { + /* Get the types-specifier of this type. */ + tree pointee = strip_pointer_operator (TREE_TYPE (t)); + pp_c_specifier_qualifier_list (pp, pointee); + if (TREE_CODE (pointee) == ARRAY_TYPE + || TREE_CODE (pointee) == FUNCTION_TYPE) + { + pp_c_whitespace (pp); + pp_c_left_paren (pp); + } + else if (!c_dialect_cxx ()) + pp_c_whitespace (pp); + pp_ptr_operator (pp, t); + } + break; + + case FUNCTION_TYPE: + case ARRAY_TYPE: + pp_c_specifier_qualifier_list (pp, TREE_TYPE (t)); + break; + + case VECTOR_TYPE: + case COMPLEX_TYPE: + if (code == COMPLEX_TYPE) + pp_c_ws_string (pp, flag_isoc99 ? "_Complex" : "__complex__"); + else if (code == VECTOR_TYPE) + { + pp_c_ws_string (pp, "__vector"); + pp_c_left_paren (pp); + pp_wide_integer (pp, TYPE_VECTOR_SUBPARTS (t)); + pp_c_right_paren (pp); + pp_c_whitespace (pp); + } + pp_c_specifier_qualifier_list (pp, TREE_TYPE (t)); + break; + + default: + pp_simple_type_specifier (pp, t); + break; + } +} + +/* parameter-type-list: + parameter-list + parameter-list , ... + + parameter-list: + parameter-declaration + parameter-list , parameter-declaration + + parameter-declaration: + declaration-specifiers declarator + declaration-specifiers abstract-declarator(opt) */ + +void +pp_c_parameter_type_list (c_pretty_printer *pp, tree t) +{ + bool want_parm_decl = DECL_P (t) && !(pp->flags & pp_c_flag_abstract); + tree parms = want_parm_decl ? DECL_ARGUMENTS (t) : TYPE_ARG_TYPES (t); + pp_c_left_paren (pp); + if (parms == void_list_node) + pp_c_ws_string (pp, "void"); + else + { + bool first = true; + for ( ; parms && parms != void_list_node; parms = TREE_CHAIN (parms)) + { + if (!first) + pp_separate_with (pp, ','); + first = false; + pp_declaration_specifiers + (pp, want_parm_decl ? parms : TREE_VALUE (parms)); + if (want_parm_decl) + pp_declarator (pp, parms); + else + pp_abstract_declarator (pp, TREE_VALUE (parms)); + } + } + pp_c_right_paren (pp); +} + +/* abstract-declarator: + pointer + pointer(opt) direct-abstract-declarator */ + +static void +pp_c_abstract_declarator (c_pretty_printer *pp, tree t) +{ + if (TREE_CODE (t) == POINTER_TYPE) + { + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) + pp_c_right_paren (pp); + t = TREE_TYPE (t); + } + + pp_direct_abstract_declarator (pp, t); +} + +/* direct-abstract-declarator: + ( abstract-declarator ) + direct-abstract-declarator(opt) [ assignment-expression(opt) ] + direct-abstract-declarator(opt) [ * ] + direct-abstract-declarator(opt) ( parameter-type-list(opt) ) */ + +void +pp_c_direct_abstract_declarator (c_pretty_printer *pp, tree t) +{ + switch (TREE_CODE (t)) + { + case POINTER_TYPE: + pp_abstract_declarator (pp, t); + break; + + case FUNCTION_TYPE: + pp_c_parameter_type_list (pp, t); + pp_direct_abstract_declarator (pp, TREE_TYPE (t)); + break; + + case ARRAY_TYPE: + pp_c_left_bracket (pp); + if (TYPE_DOMAIN (t) && TYPE_MAX_VALUE (TYPE_DOMAIN (t))) + { + tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (t)); + tree type = TREE_TYPE (maxval); + + if (host_integerp (maxval, 0)) + pp_wide_integer (pp, tree_low_cst (maxval, 0) + 1); + else + pp_expression (pp, fold_build2 (PLUS_EXPR, type, maxval, + build_int_cst (type, 1))); + } + pp_c_right_bracket (pp); + pp_direct_abstract_declarator (pp, TREE_TYPE (t)); + break; + + case IDENTIFIER_NODE: + case VOID_TYPE: + case BOOLEAN_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case VECTOR_TYPE: + case COMPLEX_TYPE: + case TYPE_DECL: + break; + + default: + pp_unsupported_tree (pp, t); + break; + } +} + +/* type-name: + specifier-qualifier-list abstract-declarator(opt) */ + +void +pp_c_type_id (c_pretty_printer *pp, tree t) +{ + pp_c_specifier_qualifier_list (pp, t); + pp_abstract_declarator (pp, t); +} + +/* storage-class-specifier: + typedef + extern + static + auto + register */ + +void +pp_c_storage_class_specifier (c_pretty_printer *pp, tree t) +{ + if (TREE_CODE (t) == TYPE_DECL) + pp_c_ws_string (pp, "typedef"); + else if (DECL_P (t)) + { + if (DECL_REGISTER (t)) + pp_c_ws_string (pp, "register"); + else if (TREE_STATIC (t) && TREE_CODE (t) == VAR_DECL) + pp_c_ws_string (pp, "static"); + } +} + +/* function-specifier: + inline */ + +void +pp_c_function_specifier (c_pretty_printer *pp, tree t) +{ + if (TREE_CODE (t) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (t)) + pp_c_ws_string (pp, "inline"); +} + +/* declaration-specifiers: + storage-class-specifier declaration-specifiers(opt) + type-specifier declaration-specifiers(opt) + type-qualifier declaration-specifiers(opt) + function-specifier declaration-specifiers(opt) */ + +void +pp_c_declaration_specifiers (c_pretty_printer *pp, tree t) +{ + pp_storage_class_specifier (pp, t); + pp_function_specifier (pp, t); + pp_c_specifier_qualifier_list (pp, DECL_P (t) ? TREE_TYPE (t) : t); +} + +/* direct-declarator + identifier + ( declarator ) + direct-declarator [ type-qualifier-list(opt) assignment-expression(opt) ] + direct-declarator [ static type-qualifier-list(opt) assignment-expression(opt)] + direct-declarator [ type-qualifier-list static assignment-expression ] + direct-declarator [ type-qualifier-list * ] + direct-declarator ( parameter-type-list ) + direct-declarator ( identifier-list(opt) ) */ + +void +pp_c_direct_declarator (c_pretty_printer *pp, tree t) +{ + switch (TREE_CODE (t)) + { + case VAR_DECL: + case PARM_DECL: + case TYPE_DECL: + case FIELD_DECL: + case LABEL_DECL: + pp_c_space_for_pointer_operator (pp, TREE_TYPE (t)); + pp_c_tree_decl_identifier (pp, t); + break; + + case ARRAY_TYPE: + case POINTER_TYPE: + pp_abstract_declarator (pp, TREE_TYPE (t)); + break; + + case FUNCTION_TYPE: + pp_parameter_list (pp, t); + pp_abstract_declarator (pp, TREE_TYPE (t)); + break; + + case FUNCTION_DECL: + pp_c_space_for_pointer_operator (pp, TREE_TYPE (TREE_TYPE (t))); + pp_c_tree_decl_identifier (pp, t); + if (pp_c_base (pp)->flags & pp_c_flag_abstract) + pp_abstract_declarator (pp, TREE_TYPE (t)); + else + { + pp_parameter_list (pp, t); + pp_abstract_declarator (pp, TREE_TYPE (TREE_TYPE (t))); + } + break; + + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + case ENUMERAL_TYPE: + case UNION_TYPE: + case RECORD_TYPE: + break; + + default: + pp_unsupported_tree (pp, t); + break; + } +} + + +/* declarator: + pointer(opt) direct-declarator */ + +void +pp_c_declarator (c_pretty_printer *pp, tree t) +{ + switch (TREE_CODE (t)) + { + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + case ENUMERAL_TYPE: + case UNION_TYPE: + case RECORD_TYPE: + break; + + case VAR_DECL: + case PARM_DECL: + case FIELD_DECL: + case ARRAY_TYPE: + case FUNCTION_TYPE: + case FUNCTION_DECL: + case TYPE_DECL: + pp_direct_declarator (pp, t); + break; + + + default: + pp_unsupported_tree (pp, t); + break; + } +} + +/* declaration: + declaration-specifiers init-declarator-list(opt) ; */ + +void +pp_c_declaration (c_pretty_printer *pp, tree t) +{ + pp_declaration_specifiers (pp, t); + pp_c_init_declarator (pp, t); +} + +/* Pretty-print ATTRIBUTES using GNU C extension syntax. */ + +void +pp_c_attributes (c_pretty_printer *pp, tree attributes) +{ + if (attributes == NULL_TREE) + return; + + pp_c_ws_string (pp, "__attribute__"); + pp_c_left_paren (pp); + pp_c_left_paren (pp); + for (; attributes != NULL_TREE; attributes = TREE_CHAIN (attributes)) + { + pp_tree_identifier (pp, TREE_PURPOSE (attributes)); + if (TREE_VALUE (attributes)) + pp_c_call_argument_list (pp, TREE_VALUE (attributes)); + + if (TREE_CHAIN (attributes)) + pp_separate_with (pp, ','); + } + pp_c_right_paren (pp); + pp_c_right_paren (pp); +} + +/* function-definition: + declaration-specifiers declarator compound-statement */ + +void +pp_c_function_definition (c_pretty_printer *pp, tree t) +{ + pp_declaration_specifiers (pp, t); + pp_declarator (pp, t); + pp_needs_newline (pp) = true; + pp_statement (pp, DECL_SAVED_TREE (t)); + pp_newline (pp); + pp_flush (pp); +} + + +/* Expressions. */ + +/* Print out a c-char. This is called solely for characters which are + in the *target* execution character set. We ought to convert them + back to the *host* execution character set before printing, but we + have no way to do this at present. A decent compromise is to print + all characters as if they were in the host execution character set, + and not attempt to recover any named escape characters, but render + all unprintables as octal escapes. If the host and target character + sets are the same, this produces relatively readable output. If they + are not the same, strings may appear as gibberish, but that's okay + (in fact, it may well be what the reader wants, e.g. if they are looking + to see if conversion to the target character set happened correctly). + + A special case: we need to prefix \, ", and ' with backslashes. It is + correct to do so for the *host*'s \, ", and ', because the rest of the + file appears in the host character set. */ + +static void +pp_c_char (c_pretty_printer *pp, int c) +{ + if (ISPRINT (c)) + { + switch (c) + { + case '\\': pp_string (pp, "\\\\"); break; + case '\'': pp_string (pp, "\\\'"); break; + case '\"': pp_string (pp, "\\\""); break; + default: pp_character (pp, c); + } + } + else + pp_scalar (pp, "\\%03o", (unsigned) c); +} + +/* Print out a STRING literal. */ + +void +pp_c_string_literal (c_pretty_printer *pp, tree s) +{ + const char *p = TREE_STRING_POINTER (s); + int n = TREE_STRING_LENGTH (s) - 1; + int i; + pp_doublequote (pp); + for (i = 0; i < n; ++i) + pp_c_char (pp, p[i]); + pp_doublequote (pp); +} + +/* Pretty-print an INTEGER literal. */ + +static void +pp_c_integer_constant (c_pretty_printer *pp, tree i) +{ + tree type = TREE_TYPE (i); + + if (TREE_INT_CST_HIGH (i) == 0) + pp_wide_integer (pp, TREE_INT_CST_LOW (i)); + else + { + unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (i); + HOST_WIDE_INT high = TREE_INT_CST_HIGH (i); + if (tree_int_cst_sgn (i) < 0) + { + pp_character (pp, '-'); + high = ~high + !low; + low = -low; + } + sprintf (pp_buffer (pp)->digit_buffer, HOST_WIDE_INT_PRINT_DOUBLE_HEX, + (unsigned HOST_WIDE_INT) high, (unsigned HOST_WIDE_INT) low); + pp_string (pp, pp_buffer (pp)->digit_buffer); + } + if (TYPE_UNSIGNED (type)) + pp_character (pp, 'u'); + if (type == long_integer_type_node || type == long_unsigned_type_node) + pp_character (pp, 'l'); + else if (type == long_long_integer_type_node + || type == long_long_unsigned_type_node) + pp_string (pp, "ll"); + else if (type == int128_integer_type_node + || type == int128_unsigned_type_node) + pp_string (pp, "I128"); +} + +/* Print out a CHARACTER literal. */ + +static void +pp_c_character_constant (c_pretty_printer *pp, tree c) +{ + tree type = TREE_TYPE (c); + if (type == wchar_type_node) + pp_character (pp, 'L'); + pp_quote (pp); + if (host_integerp (c, TYPE_UNSIGNED (type))) + pp_c_char (pp, tree_low_cst (c, TYPE_UNSIGNED (type))); + else + pp_scalar (pp, "\\x%x", (unsigned) TREE_INT_CST_LOW (c)); + pp_quote (pp); +} + +/* Print out a BOOLEAN literal. */ + +static void +pp_c_bool_constant (c_pretty_printer *pp, tree b) +{ + if (b == boolean_false_node) + { + if (c_dialect_cxx ()) + pp_c_ws_string (pp, "false"); + else if (flag_isoc99) + pp_c_ws_string (pp, "_False"); + else + pp_unsupported_tree (pp, b); + } + else if (b == boolean_true_node) + { + if (c_dialect_cxx ()) + pp_c_ws_string (pp, "true"); + else if (flag_isoc99) + pp_c_ws_string (pp, "_True"); + else + pp_unsupported_tree (pp, b); + } + else if (TREE_CODE (b) == INTEGER_CST) + pp_c_integer_constant (pp, b); + else + pp_unsupported_tree (pp, b); +} + +/* Attempt to print out an ENUMERATOR. Return true on success. Else return + false; that means the value was obtained by a cast, in which case + print out the type-id part of the cast-expression -- the casted value + is then printed by pp_c_integer_literal. */ + +static bool +pp_c_enumeration_constant (c_pretty_printer *pp, tree e) +{ + bool value_is_named = true; + tree type = TREE_TYPE (e); + tree value; + + /* Find the name of this constant. */ + for (value = TYPE_VALUES (type); + value != NULL_TREE && !tree_int_cst_equal (TREE_VALUE (value), e); + value = TREE_CHAIN (value)) + ; + + if (value != NULL_TREE) + pp_id_expression (pp, TREE_PURPOSE (value)); + else + { + /* Value must have been cast. */ + pp_c_type_cast (pp, type); + value_is_named = false; + } + + return value_is_named; +} + +/* Print out a REAL value as a decimal-floating-constant. */ + +static void +pp_c_floating_constant (c_pretty_printer *pp, tree r) +{ + real_to_decimal (pp_buffer (pp)->digit_buffer, &TREE_REAL_CST (r), + sizeof (pp_buffer (pp)->digit_buffer), 0, 1); + pp_string (pp, pp_buffer(pp)->digit_buffer); + if (TREE_TYPE (r) == float_type_node) + pp_character (pp, 'f'); + else if (TREE_TYPE (r) == long_double_type_node) + pp_character (pp, 'l'); + else if (TREE_TYPE (r) == dfloat128_type_node) + pp_string (pp, "dl"); + else if (TREE_TYPE (r) == dfloat64_type_node) + pp_string (pp, "dd"); + else if (TREE_TYPE (r) == dfloat32_type_node) + pp_string (pp, "df"); +} + +/* Print out a FIXED value as a decimal-floating-constant. */ + +static void +pp_c_fixed_constant (c_pretty_printer *pp, tree r) +{ + fixed_to_decimal (pp_buffer (pp)->digit_buffer, &TREE_FIXED_CST (r), + sizeof (pp_buffer (pp)->digit_buffer)); + pp_string (pp, pp_buffer(pp)->digit_buffer); +} + +/* Pretty-print a compound literal expression. GNU extensions include + vector constants. */ + +static void +pp_c_compound_literal (c_pretty_printer *pp, tree e) +{ + tree type = TREE_TYPE (e); + pp_c_type_cast (pp, type); + + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + case UNION_TYPE: + case ARRAY_TYPE: + case VECTOR_TYPE: + case COMPLEX_TYPE: + pp_c_brace_enclosed_initializer_list (pp, e); + break; + + default: + pp_unsupported_tree (pp, e); + break; + } +} + +/* Pretty-print a COMPLEX_EXPR expression. */ + +static void +pp_c_complex_expr (c_pretty_printer *pp, tree e) +{ + /* Handle a few common special cases, otherwise fallback + to printing it as compound literal. */ + tree type = TREE_TYPE (e); + tree realexpr = TREE_OPERAND (e, 0); + tree imagexpr = TREE_OPERAND (e, 1); + + /* Cast of an COMPLEX_TYPE expression to a different COMPLEX_TYPE. */ + if (TREE_CODE (realexpr) == NOP_EXPR + && TREE_CODE (imagexpr) == NOP_EXPR + && TREE_TYPE (realexpr) == TREE_TYPE (type) + && TREE_TYPE (imagexpr) == TREE_TYPE (type) + && TREE_CODE (TREE_OPERAND (realexpr, 0)) == REALPART_EXPR + && TREE_CODE (TREE_OPERAND (imagexpr, 0)) == IMAGPART_EXPR + && TREE_OPERAND (TREE_OPERAND (realexpr, 0), 0) + == TREE_OPERAND (TREE_OPERAND (imagexpr, 0), 0)) + { + pp_c_type_cast (pp, type); + pp_expression (pp, TREE_OPERAND (TREE_OPERAND (realexpr, 0), 0)); + return; + } + + /* Cast of an scalar expression to COMPLEX_TYPE. */ + if ((integer_zerop (imagexpr) || real_zerop (imagexpr)) + && TREE_TYPE (realexpr) == TREE_TYPE (type)) + { + pp_c_type_cast (pp, type); + if (TREE_CODE (realexpr) == NOP_EXPR) + realexpr = TREE_OPERAND (realexpr, 0); + pp_expression (pp, realexpr); + return; + } + + pp_c_compound_literal (pp, e); +} + +/* constant: + integer-constant + floating-constant + fixed-point-constant + enumeration-constant + character-constant */ + +void +pp_c_constant (c_pretty_printer *pp, tree e) +{ + const enum tree_code code = TREE_CODE (e); + + switch (code) + { + case INTEGER_CST: + { + tree type = TREE_TYPE (e); + if (type == boolean_type_node) + pp_c_bool_constant (pp, e); + else if (type == char_type_node) + pp_c_character_constant (pp, e); + else if (TREE_CODE (type) == ENUMERAL_TYPE + && pp_c_enumeration_constant (pp, e)) + ; + else + pp_c_integer_constant (pp, e); + } + break; + + case REAL_CST: + pp_c_floating_constant (pp, e); + break; + + case FIXED_CST: + pp_c_fixed_constant (pp, e); + break; + + case STRING_CST: + pp_c_string_literal (pp, e); + break; + + case COMPLEX_CST: + /* Sometimes, we are confused and we think a complex literal + is a constant. Such thing is a compound literal which + grammatically belongs to postfix-expr production. */ + pp_c_compound_literal (pp, e); + break; + + default: + pp_unsupported_tree (pp, e); + break; + } +} + +/* Pretty-print a string such as an identifier, without changing its + encoding, preceded by whitespace is necessary. */ + +void +pp_c_ws_string (c_pretty_printer *pp, const char *str) +{ + pp_c_maybe_whitespace (pp); + pp_string (pp, str); + pp_base (pp)->padding = pp_before; +} + +/* Pretty-print an IDENTIFIER_NODE, which may contain UTF-8 sequences + that need converting to the locale encoding, preceded by whitespace + is necessary. */ + +void +pp_c_identifier (c_pretty_printer *pp, const char *id) +{ + pp_c_maybe_whitespace (pp); + pp_identifier (pp, id); + pp_base (pp)->padding = pp_before; +} + +/* Pretty-print a C primary-expression. + primary-expression: + identifier + constant + string-literal + ( expression ) */ + +void +pp_c_primary_expression (c_pretty_printer *pp, tree e) +{ + switch (TREE_CODE (e)) + { + case VAR_DECL: + case PARM_DECL: + case FIELD_DECL: + case CONST_DECL: + case FUNCTION_DECL: + case LABEL_DECL: + pp_c_tree_decl_identifier (pp, e); + break; + + case IDENTIFIER_NODE: + pp_c_tree_identifier (pp, e); + break; + + case ERROR_MARK: + pp_c_ws_string (pp, M_("")); + break; + + case RESULT_DECL: + pp_c_ws_string (pp, M_("")); + break; + + case INTEGER_CST: + case REAL_CST: + case FIXED_CST: + case STRING_CST: + pp_c_constant (pp, e); + break; + + case TARGET_EXPR: + pp_c_ws_string (pp, "__builtin_memcpy"); + pp_c_left_paren (pp); + pp_ampersand (pp); + pp_primary_expression (pp, TREE_OPERAND (e, 0)); + pp_separate_with (pp, ','); + pp_ampersand (pp); + pp_initializer (pp, TREE_OPERAND (e, 1)); + if (TREE_OPERAND (e, 2)) + { + pp_separate_with (pp, ','); + pp_c_expression (pp, TREE_OPERAND (e, 2)); + } + pp_c_right_paren (pp); + break; + + default: + /* FIXME: Make sure we won't get into an infinite loop. */ + pp_c_left_paren (pp); + pp_expression (pp, e); + pp_c_right_paren (pp); + break; + } +} + +/* Print out a C initializer -- also support C compound-literals. + initializer: + assignment-expression: + { initializer-list } + { initializer-list , } */ + +static void +pp_c_initializer (c_pretty_printer *pp, tree e) +{ + if (TREE_CODE (e) == CONSTRUCTOR) + pp_c_brace_enclosed_initializer_list (pp, e); + else + pp_expression (pp, e); +} + +/* init-declarator: + declarator: + declarator = initializer */ + +void +pp_c_init_declarator (c_pretty_printer *pp, tree t) +{ + pp_declarator (pp, t); + /* We don't want to output function definitions here. There are handled + elsewhere (and the syntactic form is bogus anyway). */ + if (TREE_CODE (t) != FUNCTION_DECL && DECL_INITIAL (t)) + { + tree init = DECL_INITIAL (t); + /* This C++ bit is handled here because it is easier to do so. + In templates, the C++ parser builds a TREE_LIST for a + direct-initialization; the TREE_PURPOSE is the variable to + initialize and the TREE_VALUE is the initializer. */ + if (TREE_CODE (init) == TREE_LIST) + { + pp_c_left_paren (pp); + pp_expression (pp, TREE_VALUE (init)); + pp_right_paren (pp); + } + else + { + pp_space (pp); + pp_equal (pp); + pp_space (pp); + pp_c_initializer (pp, init); + } + } +} + +/* initializer-list: + designation(opt) initializer + initializer-list , designation(opt) initializer + + designation: + designator-list = + + designator-list: + designator + designator-list designator + + designator: + [ constant-expression ] + identifier */ + +static void +pp_c_initializer_list (c_pretty_printer *pp, tree e) +{ + tree type = TREE_TYPE (e); + const enum tree_code code = TREE_CODE (type); + + if (TREE_CODE (e) == CONSTRUCTOR) + { + pp_c_constructor_elts (pp, CONSTRUCTOR_ELTS (e)); + return; + } + + switch (code) + { + case RECORD_TYPE: + case UNION_TYPE: + case ARRAY_TYPE: + { + tree init = TREE_OPERAND (e, 0); + for (; init != NULL_TREE; init = TREE_CHAIN (init)) + { + if (code == RECORD_TYPE || code == UNION_TYPE) + { + pp_c_dot (pp); + pp_c_primary_expression (pp, TREE_PURPOSE (init)); + } + else + { + pp_c_left_bracket (pp); + if (TREE_PURPOSE (init)) + pp_c_constant (pp, TREE_PURPOSE (init)); + pp_c_right_bracket (pp); + } + pp_c_whitespace (pp); + pp_equal (pp); + pp_c_whitespace (pp); + pp_initializer (pp, TREE_VALUE (init)); + if (TREE_CHAIN (init)) + pp_separate_with (pp, ','); + } + } + return; + + case VECTOR_TYPE: + if (TREE_CODE (e) == VECTOR_CST) + pp_c_expression_list (pp, TREE_VECTOR_CST_ELTS (e)); + else + break; + return; + + case COMPLEX_TYPE: + if (TREE_CODE (e) == COMPLEX_CST || TREE_CODE (e) == COMPLEX_EXPR) + { + const bool cst = TREE_CODE (e) == COMPLEX_CST; + pp_expression (pp, cst ? TREE_REALPART (e) : TREE_OPERAND (e, 0)); + pp_separate_with (pp, ','); + pp_expression (pp, cst ? TREE_IMAGPART (e) : TREE_OPERAND (e, 1)); + } + else + break; + return; + + default: + break; + } + + pp_unsupported_tree (pp, type); +} + +/* Pretty-print a brace-enclosed initializer-list. */ + +static void +pp_c_brace_enclosed_initializer_list (c_pretty_printer *pp, tree l) +{ + pp_c_left_brace (pp); + pp_c_initializer_list (pp, l); + pp_c_right_brace (pp); +} + + +/* This is a convenient function, used to bridge gap between C and C++ + grammars. + + id-expression: + identifier */ + +void +pp_c_id_expression (c_pretty_printer *pp, tree t) +{ + switch (TREE_CODE (t)) + { + case VAR_DECL: + case PARM_DECL: + case CONST_DECL: + case TYPE_DECL: + case FUNCTION_DECL: + case FIELD_DECL: + case LABEL_DECL: + pp_c_tree_decl_identifier (pp, t); + break; + + case IDENTIFIER_NODE: + pp_c_tree_identifier (pp, t); + break; + + default: + pp_unsupported_tree (pp, t); + break; + } +} + +/* 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 , } */ + +void +pp_c_postfix_expression (c_pretty_printer *pp, tree e) +{ + enum tree_code code = TREE_CODE (e); + switch (code) + { + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + pp_postfix_expression (pp, TREE_OPERAND (e, 0)); + pp_string (pp, code == POSTINCREMENT_EXPR ? "++" : "--"); + break; + + case ARRAY_REF: + pp_postfix_expression (pp, TREE_OPERAND (e, 0)); + pp_c_left_bracket (pp); + pp_expression (pp, TREE_OPERAND (e, 1)); + pp_c_right_bracket (pp); + break; + + case CALL_EXPR: + { + call_expr_arg_iterator iter; + tree arg; + pp_postfix_expression (pp, CALL_EXPR_FN (e)); + pp_c_left_paren (pp); + FOR_EACH_CALL_EXPR_ARG (arg, iter, e) + { + pp_expression (pp, arg); + if (more_call_expr_args_p (&iter)) + pp_separate_with (pp, ','); + } + pp_c_right_paren (pp); + break; + } + + case UNORDERED_EXPR: + pp_c_ws_string (pp, flag_isoc99 + ? "isunordered" + : "__builtin_isunordered"); + goto two_args_fun; + + case ORDERED_EXPR: + pp_c_ws_string (pp, flag_isoc99 + ? "!isunordered" + : "!__builtin_isunordered"); + goto two_args_fun; + + case UNLT_EXPR: + pp_c_ws_string (pp, flag_isoc99 + ? "!isgreaterequal" + : "!__builtin_isgreaterequal"); + goto two_args_fun; + + case UNLE_EXPR: + pp_c_ws_string (pp, flag_isoc99 + ? "!isgreater" + : "!__builtin_isgreater"); + goto two_args_fun; + + case UNGT_EXPR: + pp_c_ws_string (pp, flag_isoc99 + ? "!islessequal" + : "!__builtin_islessequal"); + goto two_args_fun; + + case UNGE_EXPR: + pp_c_ws_string (pp, flag_isoc99 + ? "!isless" + : "!__builtin_isless"); + goto two_args_fun; + + case UNEQ_EXPR: + pp_c_ws_string (pp, flag_isoc99 + ? "!islessgreater" + : "!__builtin_islessgreater"); + goto two_args_fun; + + case LTGT_EXPR: + pp_c_ws_string (pp, flag_isoc99 + ? "islessgreater" + : "__builtin_islessgreater"); + goto two_args_fun; + + two_args_fun: + pp_c_left_paren (pp); + pp_expression (pp, TREE_OPERAND (e, 0)); + pp_separate_with (pp, ','); + pp_expression (pp, TREE_OPERAND (e, 1)); + pp_c_right_paren (pp); + break; + + case ABS_EXPR: + pp_c_ws_string (pp, "__builtin_abs"); + pp_c_left_paren (pp); + pp_expression (pp, TREE_OPERAND (e, 0)); + pp_c_right_paren (pp); + break; + + case COMPONENT_REF: + { + tree object = TREE_OPERAND (e, 0); + if (TREE_CODE (object) == INDIRECT_REF) + { + pp_postfix_expression (pp, TREE_OPERAND (object, 0)); + pp_c_arrow (pp); + } + else + { + pp_postfix_expression (pp, object); + pp_c_dot (pp); + } + pp_expression (pp, TREE_OPERAND (e, 1)); + } + break; + + case BIT_FIELD_REF: + { + tree type = TREE_TYPE (e); + + type = signed_or_unsigned_type_for (TYPE_UNSIGNED (type), type); + if (type + && tree_int_cst_equal (TYPE_SIZE (type), TREE_OPERAND (e, 1))) + { + HOST_WIDE_INT bitpos = tree_low_cst (TREE_OPERAND (e, 2), 0); + HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (type), 0); + if ((bitpos % size) == 0) + { + pp_c_left_paren (pp); + pp_c_left_paren (pp); + pp_type_id (pp, type); + pp_c_star (pp); + pp_c_right_paren (pp); + pp_c_ampersand (pp); + pp_expression (pp, TREE_OPERAND (e, 0)); + pp_c_right_paren (pp); + pp_c_left_bracket (pp); + pp_wide_integer (pp, bitpos / size); + pp_c_right_bracket (pp); + break; + } + } + pp_unsupported_tree (pp, e); + } + break; + + case COMPLEX_CST: + case VECTOR_CST: + pp_c_compound_literal (pp, e); + break; + + case COMPLEX_EXPR: + pp_c_complex_expr (pp, e); + break; + + case COMPOUND_LITERAL_EXPR: + e = DECL_INITIAL (COMPOUND_LITERAL_EXPR_DECL (e)); + /* Fall through. */ + case CONSTRUCTOR: + pp_initializer (pp, e); + break; + + case VA_ARG_EXPR: + pp_c_ws_string (pp, "__builtin_va_arg"); + pp_c_left_paren (pp); + pp_assignment_expression (pp, TREE_OPERAND (e, 0)); + pp_separate_with (pp, ','); + pp_type_id (pp, TREE_TYPE (e)); + pp_c_right_paren (pp); + break; + + case ADDR_EXPR: + if (TREE_CODE (TREE_OPERAND (e, 0)) == FUNCTION_DECL) + { + pp_c_id_expression (pp, TREE_OPERAND (e, 0)); + break; + } + /* else fall through. */ + + default: + pp_primary_expression (pp, e); + break; + } +} + +/* Print out an expression-list; E is expected to be a TREE_LIST. */ + +void +pp_c_expression_list (c_pretty_printer *pp, tree e) +{ + for (; e != NULL_TREE; e = TREE_CHAIN (e)) + { + pp_expression (pp, TREE_VALUE (e)); + if (TREE_CHAIN (e)) + pp_separate_with (pp, ','); + } +} + +/* Print out V, which contains the elements of a constructor. */ + +void +pp_c_constructor_elts (c_pretty_printer *pp, VEC(constructor_elt,gc) *v) +{ + unsigned HOST_WIDE_INT ix; + tree value; + + FOR_EACH_CONSTRUCTOR_VALUE (v, ix, value) + { + pp_expression (pp, value); + if (ix != VEC_length (constructor_elt, v) - 1) + pp_separate_with (pp, ','); + } +} + +/* Print out an expression-list in parens, as if it were the argument + list to a function. */ + +void +pp_c_call_argument_list (c_pretty_printer *pp, tree t) +{ + pp_c_left_paren (pp); + if (t && TREE_CODE (t) == TREE_LIST) + pp_c_expression_list (pp, t); + pp_c_right_paren (pp); +} + +/* unary-expression: + postfix-expression + ++ cast-expression + -- cast-expression + unary-operator cast-expression + sizeof unary-expression + sizeof ( type-id ) + + unary-operator: one of + * & + - ! ~ + + GNU extensions. + unary-expression: + __alignof__ unary-expression + __alignof__ ( type-id ) + __real__ unary-expression + __imag__ unary-expression */ + +void +pp_c_unary_expression (c_pretty_printer *pp, tree e) +{ + enum tree_code code = TREE_CODE (e); + switch (code) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + pp_string (pp, code == PREINCREMENT_EXPR ? "++" : "--"); + pp_c_unary_expression (pp, TREE_OPERAND (e, 0)); + break; + + case ADDR_EXPR: + case INDIRECT_REF: + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case CONJ_EXPR: + /* String literal are used by address. */ + if (code == ADDR_EXPR && TREE_CODE (TREE_OPERAND (e, 0)) != STRING_CST) + pp_ampersand (pp); + else if (code == INDIRECT_REF) + pp_c_star (pp); + else if (code == NEGATE_EXPR) + pp_minus (pp); + else if (code == BIT_NOT_EXPR || code == CONJ_EXPR) + pp_complement (pp); + else if (code == TRUTH_NOT_EXPR) + pp_exclamation (pp); + pp_c_cast_expression (pp, TREE_OPERAND (e, 0)); + break; + + case REALPART_EXPR: + case IMAGPART_EXPR: + pp_c_ws_string (pp, code == REALPART_EXPR ? "__real__" : "__imag__"); + pp_c_whitespace (pp); + pp_unary_expression (pp, TREE_OPERAND (e, 0)); + break; + + default: + pp_postfix_expression (pp, e); + break; + } +} + +/* cast-expression: + unary-expression + ( type-name ) cast-expression */ + +void +pp_c_cast_expression (c_pretty_printer *pp, tree e) +{ + switch (TREE_CODE (e)) + { + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + CASE_CONVERT: + case VIEW_CONVERT_EXPR: + pp_c_type_cast (pp, TREE_TYPE (e)); + pp_c_cast_expression (pp, TREE_OPERAND (e, 0)); + break; + + default: + pp_unary_expression (pp, e); + } +} + +/* multiplicative-expression: + cast-expression + multiplicative-expression * cast-expression + multiplicative-expression / cast-expression + multiplicative-expression % cast-expression */ + +static void +pp_c_multiplicative_expression (c_pretty_printer *pp, tree e) +{ + enum tree_code code = TREE_CODE (e); + switch (code) + { + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case TRUNC_MOD_EXPR: + pp_multiplicative_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + if (code == MULT_EXPR) + pp_c_star (pp); + else if (code == TRUNC_DIV_EXPR) + pp_slash (pp); + else + pp_modulo (pp); + pp_c_whitespace (pp); + pp_c_cast_expression (pp, TREE_OPERAND (e, 1)); + break; + + default: + pp_c_cast_expression (pp, e); + break; + } +} + +/* additive-expression: + multiplicative-expression + additive-expression + multiplicative-expression + additive-expression - multiplicative-expression */ + +static void +pp_c_additive_expression (c_pretty_printer *pp, tree e) +{ + enum tree_code code = TREE_CODE (e); + switch (code) + { + case POINTER_PLUS_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + pp_c_additive_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) + pp_plus (pp); + else + pp_minus (pp); + pp_c_whitespace (pp); + pp_multiplicative_expression (pp, TREE_OPERAND (e, 1)); + break; + + default: + pp_multiplicative_expression (pp, e); + break; + } +} + +/* additive-expression: + additive-expression + shift-expression << additive-expression + shift-expression >> additive-expression */ + +static void +pp_c_shift_expression (c_pretty_printer *pp, tree e) +{ + enum tree_code code = TREE_CODE (e); + switch (code) + { + case LSHIFT_EXPR: + case RSHIFT_EXPR: + pp_c_shift_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + pp_string (pp, code == LSHIFT_EXPR ? "<<" : ">>"); + pp_c_whitespace (pp); + pp_c_additive_expression (pp, TREE_OPERAND (e, 1)); + break; + + default: + pp_c_additive_expression (pp, e); + } +} + +/* relational-expression: + shift-expression + relational-expression < shift-expression + relational-expression > shift-expression + relational-expression <= shift-expression + relational-expression >= shift-expression */ + +static void +pp_c_relational_expression (c_pretty_printer *pp, tree e) +{ + enum tree_code code = TREE_CODE (e); + switch (code) + { + case LT_EXPR: + case GT_EXPR: + case LE_EXPR: + case GE_EXPR: + pp_c_relational_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + if (code == LT_EXPR) + pp_less (pp); + else if (code == GT_EXPR) + pp_greater (pp); + else if (code == LE_EXPR) + pp_string (pp, "<="); + else if (code == GE_EXPR) + pp_string (pp, ">="); + pp_c_whitespace (pp); + pp_c_shift_expression (pp, TREE_OPERAND (e, 1)); + break; + + default: + pp_c_shift_expression (pp, e); + break; + } +} + +/* equality-expression: + relational-expression + equality-expression == relational-expression + equality-equality != relational-expression */ + +static void +pp_c_equality_expression (c_pretty_printer *pp, tree e) +{ + enum tree_code code = TREE_CODE (e); + switch (code) + { + case EQ_EXPR: + case NE_EXPR: + pp_c_equality_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + pp_string (pp, code == EQ_EXPR ? "==" : "!="); + pp_c_whitespace (pp); + pp_c_relational_expression (pp, TREE_OPERAND (e, 1)); + break; + + default: + pp_c_relational_expression (pp, e); + break; + } +} + +/* AND-expression: + equality-expression + AND-expression & equality-equality */ + +static void +pp_c_and_expression (c_pretty_printer *pp, tree e) +{ + if (TREE_CODE (e) == BIT_AND_EXPR) + { + pp_c_and_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + pp_ampersand (pp); + pp_c_whitespace (pp); + pp_c_equality_expression (pp, TREE_OPERAND (e, 1)); + } + else + pp_c_equality_expression (pp, e); +} + +/* exclusive-OR-expression: + AND-expression + exclusive-OR-expression ^ AND-expression */ + +static void +pp_c_exclusive_or_expression (c_pretty_printer *pp, tree e) +{ + if (TREE_CODE (e) == BIT_XOR_EXPR + || TREE_CODE (e) == TRUTH_XOR_EXPR) + { + pp_c_exclusive_or_expression (pp, TREE_OPERAND (e, 0)); + if (TREE_CODE (e) == BIT_XOR_EXPR) + pp_c_maybe_whitespace (pp); + else + pp_c_whitespace (pp); + pp_carret (pp); + pp_c_whitespace (pp); + pp_c_and_expression (pp, TREE_OPERAND (e, 1)); + } + else + pp_c_and_expression (pp, e); +} + +/* inclusive-OR-expression: + exclusive-OR-expression + inclusive-OR-expression | exclusive-OR-expression */ + +static void +pp_c_inclusive_or_expression (c_pretty_printer *pp, tree e) +{ + if (TREE_CODE (e) == BIT_IOR_EXPR) + { + pp_c_exclusive_or_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + pp_bar (pp); + pp_c_whitespace (pp); + pp_c_exclusive_or_expression (pp, TREE_OPERAND (e, 1)); + } + else + pp_c_exclusive_or_expression (pp, e); +} + +/* logical-AND-expression: + inclusive-OR-expression + logical-AND-expression && inclusive-OR-expression */ + +static void +pp_c_logical_and_expression (c_pretty_printer *pp, tree e) +{ + if (TREE_CODE (e) == TRUTH_ANDIF_EXPR + || TREE_CODE (e) == TRUTH_AND_EXPR) + { + pp_c_logical_and_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + pp_string (pp, "&&"); + pp_c_whitespace (pp); + pp_c_inclusive_or_expression (pp, TREE_OPERAND (e, 1)); + } + else + pp_c_inclusive_or_expression (pp, e); +} + +/* logical-OR-expression: + logical-AND-expression + logical-OR-expression || logical-AND-expression */ + +void +pp_c_logical_or_expression (c_pretty_printer *pp, tree e) +{ + if (TREE_CODE (e) == TRUTH_ORIF_EXPR + || TREE_CODE (e) == TRUTH_OR_EXPR) + { + pp_c_logical_or_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + pp_string (pp, "||"); + pp_c_whitespace (pp); + pp_c_logical_and_expression (pp, TREE_OPERAND (e, 1)); + } + else + pp_c_logical_and_expression (pp, e); +} + +/* conditional-expression: + logical-OR-expression + logical-OR-expression ? expression : conditional-expression */ + +static void +pp_c_conditional_expression (c_pretty_printer *pp, tree e) +{ + if (TREE_CODE (e) == COND_EXPR) + { + pp_c_logical_or_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + pp_question (pp); + pp_c_whitespace (pp); + pp_expression (pp, TREE_OPERAND (e, 1)); + pp_c_whitespace (pp); + pp_colon (pp); + pp_c_whitespace (pp); + pp_c_conditional_expression (pp, TREE_OPERAND (e, 2)); + } + else + pp_c_logical_or_expression (pp, e); +} + + +/* assignment-expression: + conditional-expression + unary-expression assignment-operator assignment-expression + + assignment-expression: one of + = *= /= %= += -= >>= <<= &= ^= |= */ + +static void +pp_c_assignment_expression (c_pretty_printer *pp, tree e) +{ + if (TREE_CODE (e) == MODIFY_EXPR + || TREE_CODE (e) == INIT_EXPR) + { + pp_c_unary_expression (pp, TREE_OPERAND (e, 0)); + pp_c_whitespace (pp); + pp_equal (pp); + pp_space (pp); + pp_c_expression (pp, TREE_OPERAND (e, 1)); + } + else + pp_c_conditional_expression (pp, e); +} + +/* expression: + assignment-expression + expression , assignment-expression + + Implementation note: instead of going through the usual recursion + chain, I take the liberty of dispatching nodes to the appropriate + functions. This makes some redundancy, but it worths it. That also + prevents a possible infinite recursion between pp_c_primary_expression () + and pp_c_expression (). */ + +void +pp_c_expression (c_pretty_printer *pp, tree e) +{ + switch (TREE_CODE (e)) + { + case INTEGER_CST: + pp_c_integer_constant (pp, e); + break; + + case REAL_CST: + pp_c_floating_constant (pp, e); + break; + + case FIXED_CST: + pp_c_fixed_constant (pp, e); + break; + + case STRING_CST: + pp_c_string_literal (pp, e); + break; + + case IDENTIFIER_NODE: + case FUNCTION_DECL: + case VAR_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + case FIELD_DECL: + case LABEL_DECL: + case ERROR_MARK: + pp_primary_expression (pp, e); + break; + + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case ARRAY_REF: + case CALL_EXPR: + case COMPONENT_REF: + case BIT_FIELD_REF: + case COMPLEX_CST: + case COMPLEX_EXPR: + case VECTOR_CST: + case ORDERED_EXPR: + case UNORDERED_EXPR: + case LTGT_EXPR: + case UNEQ_EXPR: + case UNLE_EXPR: + case UNLT_EXPR: + case UNGE_EXPR: + case UNGT_EXPR: + case ABS_EXPR: + case CONSTRUCTOR: + case COMPOUND_LITERAL_EXPR: + case VA_ARG_EXPR: + pp_postfix_expression (pp, e); + break; + + case CONJ_EXPR: + case ADDR_EXPR: + case INDIRECT_REF: + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case REALPART_EXPR: + case IMAGPART_EXPR: + pp_c_unary_expression (pp, e); + break; + + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + CASE_CONVERT: + case VIEW_CONVERT_EXPR: + pp_c_cast_expression (pp, e); + break; + + case MULT_EXPR: + case TRUNC_MOD_EXPR: + case TRUNC_DIV_EXPR: + pp_multiplicative_expression (pp, e); + break; + + case LSHIFT_EXPR: + case RSHIFT_EXPR: + pp_c_shift_expression (pp, e); + break; + + case LT_EXPR: + case GT_EXPR: + case LE_EXPR: + case GE_EXPR: + pp_c_relational_expression (pp, e); + break; + + case BIT_AND_EXPR: + pp_c_and_expression (pp, e); + break; + + case BIT_XOR_EXPR: + case TRUTH_XOR_EXPR: + pp_c_exclusive_or_expression (pp, e); + break; + + case BIT_IOR_EXPR: + pp_c_inclusive_or_expression (pp, e); + break; + + case TRUTH_ANDIF_EXPR: + case TRUTH_AND_EXPR: + pp_c_logical_and_expression (pp, e); + break; + + case TRUTH_ORIF_EXPR: + case TRUTH_OR_EXPR: + pp_c_logical_or_expression (pp, e); + break; + + case EQ_EXPR: + case NE_EXPR: + pp_c_equality_expression (pp, e); + break; + + case COND_EXPR: + pp_conditional_expression (pp, e); + break; + + case POINTER_PLUS_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + pp_c_additive_expression (pp, e); + break; + + case MODIFY_EXPR: + case INIT_EXPR: + pp_assignment_expression (pp, e); + break; + + case COMPOUND_EXPR: + pp_c_left_paren (pp); + pp_expression (pp, TREE_OPERAND (e, 0)); + pp_separate_with (pp, ','); + pp_assignment_expression (pp, TREE_OPERAND (e, 1)); + pp_c_right_paren (pp); + break; + + case NON_LVALUE_EXPR: + case SAVE_EXPR: + pp_expression (pp, TREE_OPERAND (e, 0)); + break; + + case TARGET_EXPR: + pp_postfix_expression (pp, TREE_OPERAND (e, 1)); + break; + + case BIND_EXPR: + case GOTO_EXPR: + /* We don't yet have a way of dumping statements in a + human-readable format. */ + pp_string (pp, "({...})"); + break; + + default: + pp_unsupported_tree (pp, e); + break; + } +} + + + +/* Statements. */ + +void +pp_c_statement (c_pretty_printer *pp, tree stmt) +{ + if (stmt == NULL) + return; + + if (pp_needs_newline (pp)) + pp_newline_and_indent (pp, 0); + + dump_generic_node (pp_base (pp), stmt, pp_indentation (pp), 0, true); +} + + +/* Initialize the PRETTY-PRINTER for handling C codes. */ + +void +pp_c_pretty_printer_init (c_pretty_printer *pp) +{ + pp->offset_list = 0; + + pp->declaration = pp_c_declaration; + pp->declaration_specifiers = pp_c_declaration_specifiers; + pp->declarator = pp_c_declarator; + pp->direct_declarator = pp_c_direct_declarator; + pp->type_specifier_seq = pp_c_specifier_qualifier_list; + pp->abstract_declarator = pp_c_abstract_declarator; + pp->direct_abstract_declarator = pp_c_direct_abstract_declarator; + pp->ptr_operator = pp_c_pointer; + pp->parameter_list = pp_c_parameter_type_list; + pp->type_id = pp_c_type_id; + pp->simple_type_specifier = pp_c_type_specifier; + pp->function_specifier = pp_c_function_specifier; + pp->storage_class_specifier = pp_c_storage_class_specifier; + + pp->statement = pp_c_statement; + + pp->constant = pp_c_constant; + pp->id_expression = pp_c_id_expression; + pp->primary_expression = pp_c_primary_expression; + pp->postfix_expression = pp_c_postfix_expression; + pp->unary_expression = pp_c_unary_expression; + pp->initializer = pp_c_initializer; + pp->multiplicative_expression = pp_c_multiplicative_expression; + pp->conditional_expression = pp_c_conditional_expression; + pp->assignment_expression = pp_c_assignment_expression; + pp->expression = pp_c_expression; +} + + +/* Print the tree T in full, on file FILE. */ + +void +print_c_tree (FILE *file, tree t) +{ + static c_pretty_printer pp_rec; + static bool initialized = 0; + c_pretty_printer *pp = &pp_rec; + + if (!initialized) + { + initialized = 1; + pp_construct (pp_base (pp), NULL, 0); + pp_c_pretty_printer_init (pp); + pp_needs_newline (pp) = true; + } + pp_base (pp)->buffer->stream = file; + + pp_statement (pp, t); + + pp_newline (pp); + pp_flush (pp); +} + +/* Print the tree T in full, on stderr. */ + +DEBUG_FUNCTION void +debug_c_tree (tree t) +{ + print_c_tree (stderr, t); + fputc ('\n', stderr); +} + +/* Output the DECL_NAME of T. If T has no DECL_NAME, output a string made + up of T's memory address. */ + +void +pp_c_tree_decl_identifier (c_pretty_printer *pp, tree t) +{ + const char *name; + + gcc_assert (DECL_P (t)); + + if (DECL_NAME (t)) + name = IDENTIFIER_POINTER (DECL_NAME (t)); + else + { + static char xname[8]; + sprintf (xname, "", ((unsigned)((uintptr_t)(t) & 0xffff))); + name = xname; + } + + pp_c_identifier (pp, name); +} diff --git a/gcc/c-family/c-pretty-print.h b/gcc/c-family/c-pretty-print.h new file mode 100644 index 0000000..60ef0bc --- /dev/null +++ b/gcc/c-family/c-pretty-print.h @@ -0,0 +1,213 @@ +/* Various declarations for the C and C++ pretty-printers. + Copyright (C) 2002, 2003, 2004, 2007, 2009 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 +. */ + +#ifndef GCC_C_PRETTY_PRINTER +#define GCC_C_PRETTY_PRINTER + +#include "tree.h" +#include "c-common.h" +#include "pretty-print.h" + + +typedef enum + { + pp_c_flag_abstract = 1 << 1, + pp_c_flag_last_bit = 2 + } pp_c_pretty_print_flags; + + +/* The data type used to bundle information necessary for pretty-printing + a C or C++ entity. */ +typedef struct c_pretty_print_info c_pretty_printer; + +/* The type of a C pretty-printer 'member' function. */ +typedef void (*c_pretty_print_fn) (c_pretty_printer *, tree); + +/* The datatype that contains information necessary for pretty-printing + a tree that represents a C construct. Any pretty-printer for a + language using C/c++ syntax can derive from this datatype and reuse + facilities provided here. It can do so by having a subobject of type + c_pretty_printer and override the macro pp_c_base to return a pointer + to that subobject. Such a pretty-printer has the responsibility to + initialize the pp_base() part, then call pp_c_pretty_printer_init + to set up the components that are specific to the C pretty-printer. + A derived pretty-printer can override any function listed in the + vtable below. See cp/cxx-pretty-print.h and cp/cxx-pretty-print.c + for an example of derivation. */ +struct c_pretty_print_info +{ + pretty_printer base; + /* Points to the first element of an array of offset-list. + Not used yet. */ + int *offset_list; + + pp_flags flags; + + /* These must be overridden by each of the C and C++ front-end to + reflect their understanding of syntactic productions when they differ. */ + c_pretty_print_fn declaration; + c_pretty_print_fn declaration_specifiers; + c_pretty_print_fn declarator; + c_pretty_print_fn abstract_declarator; + c_pretty_print_fn direct_abstract_declarator; + c_pretty_print_fn type_specifier_seq; + c_pretty_print_fn direct_declarator; + c_pretty_print_fn ptr_operator; + c_pretty_print_fn parameter_list; + c_pretty_print_fn type_id; + c_pretty_print_fn simple_type_specifier; + c_pretty_print_fn function_specifier; + c_pretty_print_fn storage_class_specifier; + c_pretty_print_fn initializer; + + c_pretty_print_fn statement; + + c_pretty_print_fn constant; + c_pretty_print_fn id_expression; + c_pretty_print_fn primary_expression; + c_pretty_print_fn postfix_expression; + c_pretty_print_fn unary_expression; + c_pretty_print_fn multiplicative_expression; + c_pretty_print_fn conditional_expression; + c_pretty_print_fn assignment_expression; + c_pretty_print_fn expression; +}; + +/* Override the pp_base macro. Derived pretty-printers should not + touch this macro. Instead they should override pp_c_base instead. */ +#undef pp_base +#define pp_base(PP) (&pp_c_base (PP)->base) + + +#define pp_c_tree_identifier(PPI, ID) \ + pp_c_identifier (PPI, IDENTIFIER_POINTER (ID)) + +#define pp_declaration(PPI, T) \ + pp_c_base (PPI)->declaration (pp_c_base (PPI), T) +#define pp_declaration_specifiers(PPI, D) \ + pp_c_base (PPI)->declaration_specifiers (pp_c_base (PPI), D) +#define pp_abstract_declarator(PP, D) \ + pp_c_base (PP)->abstract_declarator (pp_c_base (PP), D) +#define pp_type_specifier_seq(PPI, D) \ + pp_c_base (PPI)->type_specifier_seq (pp_c_base (PPI), D) +#define pp_declarator(PPI, D) \ + pp_c_base (PPI)->declarator (pp_c_base (PPI), D) +#define pp_direct_declarator(PPI, D) \ + pp_c_base (PPI)->direct_declarator (pp_c_base (PPI), D) +#define pp_direct_abstract_declarator(PP, D) \ + pp_c_base (PP)->direct_abstract_declarator (pp_c_base (PP), D) +#define pp_ptr_operator(PP, D) \ + pp_c_base (PP)->ptr_operator (pp_c_base (PP), D) +#define pp_parameter_list(PPI, T) \ + pp_c_base (PPI)->parameter_list (pp_c_base (PPI), T) +#define pp_type_id(PPI, D) \ + pp_c_base (PPI)->type_id (pp_c_base (PPI), D) +#define pp_simple_type_specifier(PP, T) \ + pp_c_base (PP)->simple_type_specifier (pp_c_base (PP), T) +#define pp_function_specifier(PP, D) \ + pp_c_base (PP)->function_specifier (pp_c_base (PP), D) +#define pp_storage_class_specifier(PP, D) \ + pp_c_base (PP)->storage_class_specifier (pp_c_base (PP), D); + +#define pp_statement(PPI, S) \ + pp_c_base (PPI)->statement (pp_c_base (PPI), S) + +#define pp_constant(PP, E) \ + pp_c_base (PP)->constant (pp_c_base (PP), E) +#define pp_id_expression(PP, E) \ + pp_c_base (PP)->id_expression (pp_c_base (PP), E) +#define pp_primary_expression(PPI, E) \ + pp_c_base (PPI)->primary_expression (pp_c_base (PPI), E) +#define pp_postfix_expression(PPI, E) \ + pp_c_base (PPI)->postfix_expression (pp_c_base (PPI), E) +#define pp_unary_expression(PPI, E) \ + pp_c_base (PPI)->unary_expression (pp_c_base (PPI), E) +#define pp_initializer(PPI, E) \ + pp_c_base (PPI)->initializer (pp_c_base (PPI), E) +#define pp_multiplicative_expression(PPI, E) \ + pp_c_base (PPI)->multiplicative_expression (pp_c_base (PPI), E) +#define pp_conditional_expression(PPI, E) \ + pp_c_base (PPI)->conditional_expression (pp_c_base (PPI), E) +#define pp_assignment_expression(PPI, E) \ + pp_c_base (PPI)->assignment_expression (pp_c_base (PPI), E) +#define pp_expression(PP, E) \ + pp_c_base (PP)->expression (pp_c_base (PP), E) + + +/* Returns the c_pretty_printer base object of PRETTY-PRINTER. This + macro must be overridden by any subclass of c_pretty_print_info. */ +#define pp_c_base(PP) (PP) + +extern void pp_c_pretty_printer_init (c_pretty_printer *); +void pp_c_whitespace (c_pretty_printer *); +void pp_c_left_paren (c_pretty_printer *); +void pp_c_right_paren (c_pretty_printer *); +void pp_c_left_brace (c_pretty_printer *); +void pp_c_right_brace (c_pretty_printer *); +void pp_c_left_bracket (c_pretty_printer *); +void pp_c_right_bracket (c_pretty_printer *); +void pp_c_dot (c_pretty_printer *); +void pp_c_ampersand (c_pretty_printer *); +void pp_c_star (c_pretty_printer *); +void pp_c_arrow (c_pretty_printer *); +void pp_c_semicolon (c_pretty_printer *); +void pp_c_complement (c_pretty_printer *); +void pp_c_exclamation (c_pretty_printer *); +void pp_c_space_for_pointer_operator (c_pretty_printer *, tree); + +/* Declarations. */ +void pp_c_tree_decl_identifier (c_pretty_printer *, tree); +void pp_c_function_definition (c_pretty_printer *, tree); +void pp_c_attributes (c_pretty_printer *, tree); +void pp_c_cv_qualifiers (c_pretty_printer *pp, int qualifiers, bool func_type); +void pp_c_type_qualifier_list (c_pretty_printer *, tree); +void pp_c_parameter_type_list (c_pretty_printer *, tree); +void pp_c_declaration (c_pretty_printer *, tree); +void pp_c_declaration_specifiers (c_pretty_printer *, tree); +void pp_c_declarator (c_pretty_printer *, tree); +void pp_c_direct_declarator (c_pretty_printer *, tree); +void pp_c_specifier_qualifier_list (c_pretty_printer *, tree); +void pp_c_function_specifier (c_pretty_printer *, tree); +void pp_c_type_id (c_pretty_printer *, tree); +void pp_c_direct_abstract_declarator (c_pretty_printer *, tree); +void pp_c_type_specifier (c_pretty_printer *, tree); +void pp_c_storage_class_specifier (c_pretty_printer *, tree); +/* Statements. */ +void pp_c_statement (c_pretty_printer *, tree); +/* Expressions. */ +void pp_c_expression (c_pretty_printer *, tree); +void pp_c_logical_or_expression (c_pretty_printer *, tree); +void pp_c_expression_list (c_pretty_printer *, tree); +void pp_c_constructor_elts (c_pretty_printer *, VEC(constructor_elt,gc) *); +void pp_c_call_argument_list (c_pretty_printer *, tree); +void pp_c_unary_expression (c_pretty_printer *, tree); +void pp_c_cast_expression (c_pretty_printer *, tree); +void pp_c_postfix_expression (c_pretty_printer *, tree); +void pp_c_primary_expression (c_pretty_printer *, tree); +void pp_c_init_declarator (c_pretty_printer *, tree); +void pp_c_constant (c_pretty_printer *, tree); +void pp_c_id_expression (c_pretty_printer *, tree); +void pp_c_ws_string (c_pretty_printer *, const char *); +void pp_c_identifier (c_pretty_printer *, const char *); +void pp_c_string_literal (c_pretty_printer *, tree); + +void print_c_tree (FILE *file, tree t); + +#endif /* GCC_C_PRETTY_PRINTER */ diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c new file mode 100644 index 0000000..683655f --- /dev/null +++ b/gcc/c-family/c-semantics.c @@ -0,0 +1,146 @@ +/* This file contains subroutine used by the C front-end to construct GENERIC. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 + Free Software Foundation, Inc. + Written by Benjamin Chelf (chelf@codesourcery.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 "tree.h" +#include "function.h" +#include "splay-tree.h" +#include "c-common.h" +/* In order for the format checking to accept the C frontend + diagnostic framework extensions, you must define this token before + including toplev.h. */ +#define GCC_DIAG_STYLE __gcc_cdiag__ +#include "toplev.h" +#include "flags.h" +#include "output.h" +#include "tree-iterator.h" + +/* Create an empty statement tree rooted at T. */ + +tree +push_stmt_list (void) +{ + tree t; + t = alloc_stmt_list (); + TREE_CHAIN (t) = cur_stmt_list; + cur_stmt_list = t; + return t; +} + +/* Finish the statement tree rooted at T. */ + +tree +pop_stmt_list (tree t) +{ + tree u = cur_stmt_list, chain; + + /* Pop statement lists until we reach the target level. The extra + nestings will be due to outstanding cleanups. */ + while (1) + { + chain = TREE_CHAIN (u); + TREE_CHAIN (u) = NULL_TREE; + if (chain) + STATEMENT_LIST_HAS_LABEL (chain) |= STATEMENT_LIST_HAS_LABEL (u); + if (t == u) + break; + u = chain; + } + cur_stmt_list = chain; + + /* If the statement list is completely empty, just return it. This is + just as good small as build_empty_stmt, with the advantage that + statement lists are merged when they appended to one another. So + using the STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P + statements. */ + if (TREE_SIDE_EFFECTS (t)) + { + tree_stmt_iterator i = tsi_start (t); + + /* If the statement list contained exactly one statement, then + extract it immediately. */ + if (tsi_one_before_end_p (i)) + { + u = tsi_stmt (i); + tsi_delink (&i); + free_stmt_list (t); + t = u; + } + } + + return t; +} + +/* Build a generic statement based on the given type of node and + arguments. Similar to `build_nt', except that we set + EXPR_LOCATION to LOC. */ +/* ??? This should be obsolete with the lineno_stmt productions + in the grammar. */ + +tree +build_stmt (location_t loc, enum tree_code code, ...) +{ + tree ret; + int length, i; + va_list p; + bool side_effects; + + /* This function cannot be used to construct variably-sized nodes. */ + gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp); + + va_start (p, code); + + ret = make_node (code); + TREE_TYPE (ret) = void_type_node; + length = TREE_CODE_LENGTH (code); + SET_EXPR_LOCATION (ret, loc); + + /* TREE_SIDE_EFFECTS will already be set for statements with + implicit side effects. Here we make sure it is set for other + expressions by checking whether the parameters have side + effects. */ + + side_effects = false; + for (i = 0; i < length; i++) + { + tree t = va_arg (p, tree); + if (t && !TYPE_P (t)) + side_effects |= TREE_SIDE_EFFECTS (t); + TREE_OPERAND (ret, i) = t; + } + + TREE_SIDE_EFFECTS (ret) |= side_effects; + + va_end (p); + return ret; +} + +/* Create a CASE_LABEL_EXPR tree node and return it. */ + +tree +build_case_label (location_t loc, + tree low_value, tree high_value, tree label_decl) +{ + return build_stmt (loc, CASE_LABEL_EXPR, low_value, high_value, label_decl); +} diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt new file mode 100644 index 0000000..01d6428 --- /dev/null +++ b/gcc/c-family/c.opt @@ -0,0 +1,1060 @@ +; Options for the C, ObjC, C++ and ObjC++ front ends. +; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +; 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 +; . + +; See the GCC internals manual for a description of this file's format. + +; Please try to keep this file in ASCII collating order. + +Language +C + +Language +ObjC + +Language +C++ + +Language +ObjC++ + +-output-pch= +C ObjC C++ ObjC++ Joined Separate + +A +C ObjC C++ ObjC++ Joined Separate +-A= Assert the to . Putting '-' before disables the to + +C +C ObjC C++ ObjC++ +Do not discard comments + +CC +C ObjC C++ ObjC++ +Do not discard comments in macro expansions + +D +C ObjC C++ ObjC++ Joined Separate +-D[=] Define a with as its value. If just is given, is taken to be 1 + +E +C ObjC C++ ObjC++ Undocumented + +F +C ObjC C++ ObjC++ Joined Separate +-F Add to the end of the main framework include path + +H +C ObjC C++ ObjC++ +Print the name of header files as they are used + +I +C ObjC C++ ObjC++ Joined Separate +-I Add to the end of the main include path + +M +C ObjC C++ ObjC++ +Generate make dependencies + +MD +C ObjC C++ ObjC++ Separate +Generate make dependencies and compile + +MF +C ObjC C++ ObjC++ Joined Separate +-MF Write dependency output to the given file + +MG +C ObjC C++ ObjC++ +Treat missing header files as generated files + +MM +C ObjC C++ ObjC++ +Like -M but ignore system header files + +MMD +C ObjC C++ ObjC++ Separate +Like -MD but ignore system header files + +MP +C ObjC C++ ObjC++ +Generate phony targets for all headers + +MQ +C ObjC C++ ObjC++ Joined Separate +-MQ Add a MAKE-quoted target + +MT +C ObjC C++ ObjC++ Joined Separate +-MT Add an unquoted target + +P +C ObjC C++ ObjC++ +Do not generate #line directives + +U +C ObjC C++ ObjC++ Joined Separate +-U Undefine + +Wabi +C ObjC C++ ObjC++ LTO Var(warn_abi) Warning +Warn about things that will change when compiling with an ABI-compliant compiler + +Wpsabi +C ObjC C++ ObjC++ LTO Var(warn_psabi) Init(1) Undocumented + +Waddress +C ObjC C++ ObjC++ Var(warn_address) Warning +Warn about suspicious uses of memory addresses + +Wall +C ObjC C++ ObjC++ Warning +Enable most warning messages + +Wassign-intercept +ObjC ObjC++ Var(warn_assign_intercept) Warning +Warn whenever an Objective-C assignment is being intercepted by the garbage collector + +Wbad-function-cast +C ObjC Var(warn_bad_function_cast) Warning +Warn about casting functions to incompatible types + +Wbuiltin-macro-redefined +C ObjC C++ ObjC++ Warning +Warn when a built-in preprocessor macro is undefined or redefined + +Wc++-compat +C ObjC Var(warn_cxx_compat) Warning +Warn about C constructs that are not in the common subset of C and C++ + +Wc++0x-compat +C++ ObjC++ Var(warn_cxx0x_compat) Warning +Warn about C++ constructs whose meaning differs between ISO C++ 1998 and ISO C++ 200x + +Wcast-qual +C ObjC C++ ObjC++ Var(warn_cast_qual) Warning +Warn about casts which discard qualifiers + +Wchar-subscripts +C ObjC C++ ObjC++ Var(warn_char_subscripts) Warning +Warn about subscripts whose type is \"char\" + +Wclobbered +C ObjC C++ ObjC++ Var(warn_clobbered) Init(-1) Warning +Warn about variables that might be changed by \"longjmp\" or \"vfork\" + +Wcomment +C ObjC C++ ObjC++ Warning +Warn about possibly nested block comments, and C++ comments spanning more than one physical line + +Wcomments +C ObjC C++ ObjC++ Warning +Synonym for -Wcomment + +Wconversion +C ObjC C++ ObjC++ Var(warn_conversion) Warning +Warn for implicit type conversions that may change a value + +Wconversion-null +C++ ObjC++ Var(warn_conversion_null) Init(1) Warning +Warn for converting NULL from/to a non-pointer type + +Wsign-conversion +C ObjC C++ ObjC++ Var(warn_sign_conversion) Init(-1) +Warn for implicit type conversions between signed and unsigned integers + +Wctor-dtor-privacy +C++ ObjC++ Var(warn_ctor_dtor_privacy) Warning +Warn when all constructors and destructors are private + +Wdeclaration-after-statement +C ObjC Var(warn_declaration_after_statement) Warning +Warn when a declaration is found after a statement + +Wdeprecated +C C++ ObjC ObjC++ Var(warn_deprecated) Init(1) Warning +Warn if a deprecated compiler feature, class, method, or field is used + +Wdiv-by-zero +C ObjC C++ ObjC++ Var(warn_div_by_zero) Init(1) Warning +Warn about compile-time integer division by zero + +Weffc++ +C++ ObjC++ Var(warn_ecpp) Warning +Warn about violations of Effective C++ style rules + +Wempty-body +C ObjC C++ ObjC++ Var(warn_empty_body) Init(-1) Warning +Warn about an empty body in an if or else statement + +Wendif-labels +C ObjC C++ ObjC++ Warning +Warn about stray tokens after #elif and #endif + +Wenum-compare +C ObjC C++ ObjC++ Var(warn_enum_compare) Init(-1) Warning +Warn about comparison of different enum types + +Werror +C ObjC C++ ObjC++ +; Documented in common.opt + +Werror-implicit-function-declaration +C ObjC RejectNegative Warning +This switch is deprecated; use -Werror=implicit-function-declaration instead + +Wfloat-equal +C ObjC C++ ObjC++ Var(warn_float_equal) Warning +Warn if testing floating point numbers for equality + +Wformat +C ObjC C++ ObjC++ Warning +Warn about printf/scanf/strftime/strfmon format string anomalies + +Wformat-extra-args +C ObjC C++ ObjC++ Var(warn_format_extra_args) Warning +Warn if passing too many arguments to a function for its format string + +Wformat-nonliteral +C ObjC C++ ObjC++ Var(warn_format_nonliteral) Warning +Warn about format strings that are not literals + +Wformat-contains-nul +C ObjC C++ ObjC++ Var(warn_format_contains_nul) Warning +Warn about format strings that contain NUL bytes + +Wformat-security +C ObjC C++ ObjC++ Var(warn_format_security) Warning +Warn about possible security problems with format functions + +Wformat-y2k +C ObjC C++ ObjC++ Var(warn_format_y2k) Warning +Warn about strftime formats yielding 2-digit years + +Wformat-zero-length +C ObjC Var(warn_format_zero_length) Warning +Warn about zero-length formats + +Wformat= +C ObjC C++ ObjC++ Joined Warning + +Wignored-qualifiers +C C++ Var(warn_ignored_qualifiers) Init(-1) Warning +Warn whenever type qualifiers are ignored. + +Winit-self +C ObjC C++ ObjC++ Var(warn_init_self) Warning +Warn about variables which are initialized to themselves + +Wimplicit +C ObjC Var(warn_implicit) Init(-1) Warning +Warn about implicit declarations + +Wimplicit-function-declaration +C ObjC Var(warn_implicit_function_declaration) Init(-1) Warning +Warn about implicit function declarations + +Wimplicit-int +C ObjC Var(warn_implicit_int) Init(-1) Warning +Warn when a declaration does not specify a type + +Wimport +C ObjC C++ ObjC++ Undocumented + +Wint-to-pointer-cast +C ObjC C++ ObjC++ Var(warn_int_to_pointer_cast) Init(1) Warning +Warn when there is a cast to a pointer from an integer of a different size + +Winvalid-offsetof +C++ ObjC++ Var(warn_invalid_offsetof) Init(1) Warning +Warn about invalid uses of the \"offsetof\" macro + +Winvalid-pch +C ObjC C++ ObjC++ Warning +Warn about PCH files that are found but not used + +Wjump-misses-init +C ObjC Var(warn_jump_misses_init) Init(-1) Warning +Warn when a jump misses a variable initialization + +Wlogical-op +C ObjC C++ ObjC++ Var(warn_logical_op) Init(0) Warning +Warn when a logical operator is suspiciously always evaluating to true or false + +Wlong-long +C ObjC C++ ObjC++ Var(warn_long_long) Init(-1) Warning +Do not warn about using \"long long\" when -pedantic + +Wmain +C ObjC C++ ObjC++ Var(warn_main) Init(-1) Warning +Warn about suspicious declarations of \"main\" + +Wmissing-braces +C ObjC C++ ObjC++ Var(warn_missing_braces) Warning +Warn about possibly missing braces around initializers + +Wmissing-declarations +C ObjC C++ ObjC++ Var(warn_missing_declarations) Warning +Warn about global functions without previous declarations + +Wmissing-field-initializers +C ObjC C++ ObjC++ Var(warn_missing_field_initializers) Init(-1) Warning +Warn about missing fields in struct initializers + +Wmissing-format-attribute +C ObjC C++ ObjC++ Var(warn_missing_format_attribute) Warning +Warn about functions which might be candidates for format attributes + +Wmissing-include-dirs +C ObjC C++ ObjC++ Warning +Warn about user-specified include directories that do not exist + +Wmissing-parameter-type +C ObjC Var(warn_missing_parameter_type) Init(-1) Warning +Warn about function parameters declared without a type specifier in K&R-style functions + +Wmissing-prototypes +C ObjC Var(warn_missing_prototypes) Warning +Warn about global functions without prototypes + +Wmultichar +C ObjC C++ ObjC++ Warning +Warn about use of multi-character character constants + +Wnested-externs +C ObjC Var(warn_nested_externs) Warning +Warn about \"extern\" declarations not at file scope + +Wnon-template-friend +C++ ObjC++ Var(warn_nontemplate_friend) Init(1) Warning +Warn when non-templatized friend functions are declared within a template + +Wnon-virtual-dtor +C++ ObjC++ Var(warn_nonvdtor) Warning +Warn about non-virtual destructors + +Wnonnull +C ObjC Var(warn_nonnull) Warning +Warn about NULL being passed to argument slots marked as requiring non-NULL + +Wnormalized= +C ObjC C++ ObjC++ Joined Warning +-Wnormalized= Warn about non-normalised Unicode strings + +Wold-style-cast +C++ ObjC++ Var(warn_old_style_cast) Warning +Warn if a C-style cast is used in a program + +Wold-style-declaration +C ObjC Var(warn_old_style_declaration) Init(-1) Warning +Warn for obsolescent usage in a declaration + +Wold-style-definition +C ObjC Var(warn_old_style_definition) Warning +Warn if an old-style parameter definition is used + +Woverlength-strings +C ObjC C++ ObjC++ Var(warn_overlength_strings) Init(-1) Warning +Warn if a string is longer than the maximum portable length specified by the standard + +Woverloaded-virtual +C++ ObjC++ Var(warn_overloaded_virtual) Warning +Warn about overloaded virtual function names + +Woverride-init +C ObjC Var(warn_override_init) Init(-1) Warning +Warn about overriding initializers without side effects + +Wpacked-bitfield-compat +C ObjC C++ ObjC++ Var(warn_packed_bitfield_compat) Init(-1) Warning +Warn about packed bit-fields whose offset changed in GCC 4.4 + +Wparentheses +C ObjC C++ ObjC++ Var(warn_parentheses) Warning +Warn about possibly missing parentheses + +Wpmf-conversions +C++ ObjC++ Var(warn_pmf2ptr) Init(1) Warning +Warn when converting the type of pointers to member functions + +Wpointer-arith +C ObjC C++ ObjC++ Var(warn_pointer_arith) Warning +Warn about function pointer arithmetic + +Wpointer-to-int-cast +C ObjC Var(warn_pointer_to_int_cast) Init(1) Warning +Warn when a pointer is cast to an integer of a different size + +Wpragmas +C ObjC C++ ObjC++ Var(warn_pragmas) Init(1) Warning +Warn about misuses of pragmas + +Wprotocol +ObjC ObjC++ Var(warn_protocol) Init(1) Warning +Warn if inherited methods are unimplemented + +Wredundant-decls +C ObjC C++ ObjC++ Var(warn_redundant_decls) Warning +Warn about multiple declarations of the same object + +Wreorder +C++ ObjC++ Var(warn_reorder) Warning +Warn when the compiler reorders code + +Wreturn-type +C ObjC C++ ObjC++ Var(warn_return_type) Warning +Warn whenever a function's return type defaults to \"int\" (C), or about inconsistent return types (C++) + +Wselector +ObjC ObjC++ Var(warn_selector) Warning +Warn if a selector has multiple methods + +Wsequence-point +C ObjC C++ ObjC++ Var(warn_sequence_point) Warning +Warn about possible violations of sequence point rules + +Wsign-compare +C ObjC C++ ObjC++ Var(warn_sign_compare) Init(-1) Warning +Warn about signed-unsigned comparisons + +Wsign-promo +C++ ObjC++ Var(warn_sign_promo) Warning +Warn when overload promotes from unsigned to signed + +Wstrict-null-sentinel +C++ ObjC++ Warning +Warn about uncasted NULL used as sentinel + +Wstrict-prototypes +C ObjC Var(warn_strict_prototypes) Warning +Warn about unprototyped function declarations + +Wstrict-selector-match +ObjC ObjC++ Var(warn_strict_selector_match) Warning +Warn if type signatures of candidate methods do not match exactly + +Wsync-nand +C C++ Var(warn_sync_nand) Init(1) Warning +Warn when __sync_fetch_and_nand and __sync_nand_and_fetch built-in functions are used + +Wsynth +C++ ObjC++ Var(warn_synth) Warning +Deprecated. This switch has no effect + +Wsystem-headers +C ObjC C++ ObjC++ Warning +; Documented in common.opt + +Wtraditional +C ObjC Var(warn_traditional) Warning +Warn about features not present in traditional C + +Wtraditional-conversion +C ObjC Var(warn_traditional_conversion) Warning +Warn of prototypes causing type conversions different from what would happen in the absence of prototype + +Wtrigraphs +C ObjC C++ ObjC++ Warning +Warn if trigraphs are encountered that might affect the meaning of the program + +Wundeclared-selector +ObjC ObjC++ Var(warn_undeclared_selector) Warning +Warn about @selector()s without previously declared methods + +Wundef +C ObjC C++ ObjC++ Warning +Warn if an undefined macro is used in an #if directive + +Wunknown-pragmas +C ObjC C++ ObjC++ Warning +Warn about unrecognized pragmas + +Wunsuffixed-float-constants +C ObjC Var(warn_unsuffixed_float_constants) Warning +Warn about unsuffixed float constants + +Wunused-macros +C ObjC C++ ObjC++ Warning +Warn about macros defined in the main file that are not used + +Wunused-result +C ObjC C++ ObjC++ Var(warn_unused_result) Init(1) Warning +Warn if a caller of a function, marked with attribute warn_unused_result, does not use its return value + +Wvariadic-macros +C ObjC C++ ObjC++ Warning +Do not warn about using variadic macros when -pedantic + +Wvla +C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning +Warn if a variable length array is used + +Wvolatile-register-var +C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning +Warn when a register variable is declared volatile + +Wwrite-strings +C ObjC C++ ObjC++ Var(warn_write_strings) Warning +In C++, nonzero means warn about deprecated conversion from string literals to `char *'. In C, similar warning, except that the conversion is of course not deprecated by the ISO C standard. + +Wpointer-sign +C ObjC Var(warn_pointer_sign) Init(-1) Warning +Warn when a pointer differs in signedness in an assignment + +ansi +C ObjC C++ ObjC++ +A synonym for -std=c89 (for C) or -std=c++98 (for C++) + +d +C ObjC C++ ObjC++ Joined +; Documented in common.opt. FIXME - what about -dI, -dD, -dN and -dD? + +faccess-control +C++ ObjC++ +Enforce class member access control semantics + +fall-virtual +C++ ObjC++ + +falt-external-templates +C++ ObjC++ +Change when template instances are emitted + +fasm +C ObjC C++ ObjC++ +Recognize the \"asm\" keyword + +fbuiltin +C ObjC C++ ObjC++ +Recognize built-in functions + +fbuiltin- +C ObjC C++ ObjC++ Joined + +fcheck-new +C++ ObjC++ +Check the return value of new + +fcond-mismatch +C ObjC C++ ObjC++ +Allow the arguments of the '?' operator to have different types + +fconserve-space +C++ ObjC++ +Reduce the size of object files + +fconstant-string-class= +ObjC ObjC++ Joined +-fconst-string-class= Use class for constant strings + +fdeduce-init-list +C++ ObjC++ Var(flag_deduce_init_list) Init(1) +-fno-deduce-init-list disable deduction of std::initializer_list for a template type parameter from a brace-enclosed initializer-list + +fdefault-inline +C++ ObjC++ +Inline member functions by default + +fdirectives-only +C ObjC C++ ObjC++ +Preprocess directives only. + +fdollars-in-identifiers +C ObjC C++ ObjC++ +Permit '$' as an identifier character + +felide-constructors +C++ ObjC++ + +fenforce-eh-specs +C++ ObjC++ +Generate code to check exception specifications + +fenum-int-equiv +C++ ObjC++ + +fexec-charset= +C ObjC C++ ObjC++ Joined RejectNegative +-fexec-charset= Convert all strings and character constants to character set + +fextended-identifiers +C ObjC C++ ObjC++ +Permit universal character names (\\u and \\U) in identifiers + +finput-charset= +C ObjC C++ ObjC++ Joined RejectNegative +-finput-charset= Specify the default character set for source files + + +fexternal-templates +C++ ObjC++ + +ffor-scope +C++ ObjC++ +Scope of for-init-statement variables is local to the loop + +ffreestanding +C ObjC C++ ObjC++ +Do not assume that standard C libraries and \"main\" exist + +fgnu-keywords +C++ ObjC++ +Recognize GNU-defined keywords + +fgnu-runtime +ObjC ObjC++ +Generate code for GNU runtime environment + +fgnu89-inline +C ObjC Var(flag_gnu89_inline) Init(-1) +Use traditional GNU semantics for inline functions + +fguiding-decls +C++ ObjC++ + +fhandle-exceptions +C++ ObjC++ Optimization + +fhonor-std +C++ ObjC++ + +fhosted +C ObjC +Assume normal C execution environment + +fhuge-objects +C++ ObjC++ +Enable support for huge objects + +fimplement-inlines +C++ ObjC++ +Export functions even if they can be inlined + +fimplicit-inline-templates +C++ ObjC++ +Emit implicit instantiations of inline templates + +fimplicit-templates +C++ ObjC++ +Emit implicit instantiations of templates + +ffriend-injection +C++ ObjC++ Var(flag_friend_injection) +Inject friend functions into enclosing namespace + +flabels-ok +C++ ObjC++ + +flax-vector-conversions +C ObjC C++ ObjC++ +Allow implicit conversions between vectors with differing numbers of subparts and/or differing element types. + +fms-extensions +C ObjC C++ ObjC++ +Don't warn about uses of Microsoft extensions + +fname-mangling-version- +C++ ObjC++ Joined + +fnew-abi +C++ ObjC++ + +fnext-runtime +ObjC ObjC++ +Generate code for NeXT (Apple Mac OS X) runtime environment + +fnil-receivers +ObjC ObjC++ +Assume that receivers of Objective-C messages may be nil + +fnonansi-builtins +C++ ObjC++ + +fnonnull-objects +C++ ObjC++ + +fnothrow-opt +C++ ObjC++ Optimization Var(flag_nothrow_opt) +Treat a throw() exception specification as noexcept to improve code size + +; Generate special '- .cxx_construct' and '- .cxx_destruct' methods +; to initialize any non-POD ivars in Objective-C++ classes. +fobjc-call-cxx-cdtors +ObjC++ Var(flag_objc_call_cxx_cdtors) +Generate special Objective-C methods to initialize/destroy non-POD C++ ivars, if needed + +fobjc-direct-dispatch +ObjC ObjC++ Var(flag_objc_direct_dispatch) +Allow fast jumps to the message dispatcher + +; Nonzero means that we will allow new ObjC exception syntax (@throw, +; @try, etc.) in source code. +fobjc-exceptions +ObjC ObjC++ Var(flag_objc_exceptions) +Enable Objective-C exception and synchronization syntax + +fobjc-gc +ObjC ObjC++ Var(flag_objc_gc) +Enable garbage collection (GC) in Objective-C/Objective-C++ programs + +; Nonzero means that we generate NeXT setjmp based exceptions. +fobjc-sjlj-exceptions +ObjC ObjC++ Var(flag_objc_sjlj_exceptions) Init(-1) +Enable Objective-C setjmp exception handling runtime + +fopenmp +C ObjC C++ ObjC++ Var(flag_openmp) +Enable OpenMP (implies -frecursive in Fortran) + +foperator-names +C++ ObjC++ +Recognize C++ keywords like \"compl\" and \"xor\" + +foptional-diags +C++ ObjC++ +Enable optional diagnostics + +fpch-deps +C ObjC C++ ObjC++ + +fpch-preprocess +C ObjC C++ ObjC++ +Look for and use PCH files even when preprocessing + +fpermissive +C++ ObjC++ +Downgrade conformance errors to warnings + +fpreprocessed +C ObjC C++ ObjC++ +Treat the input file as already preprocessed + +fpretty-templates +C++ ObjC++ +-fno-pretty-templates Do not pretty-print template specializations as the template signature followed by the arguments + +freplace-objc-classes +ObjC ObjC++ +Used in Fix-and-Continue mode to indicate that object files may be swapped in at runtime + +frepo +C++ ObjC++ +Enable automatic template instantiation + +frtti +C++ ObjC++ Optimization +Generate run time type descriptor information + +fshort-double +C ObjC C++ ObjC++ Optimization +Use the same size for double as for float + +fshort-enums +C ObjC C++ ObjC++ Optimization +Use the narrowest integer type possible for enumeration types + +fshort-wchar +C ObjC C++ ObjC++ Optimization +Force the underlying type for \"wchar_t\" to be \"unsigned short\" + +fsigned-bitfields +C ObjC C++ ObjC++ +When \"signed\" or \"unsigned\" is not given make the bitfield signed + +fsigned-char +C ObjC C++ ObjC++ LTO +Make \"char\" signed by default + +fsquangle +C++ ObjC++ + +fstats +C++ ObjC++ +Display statistics accumulated during compilation + +fstrict-enums +C++ ObjC++ Optimization Var(flag_strict_enums) +Assume that values of enumeration type are always within the minimum range of that type + +fstrict-prototype +C++ ObjC++ + +ftabstop= +C ObjC C++ ObjC++ Joined RejectNegative UInteger +-ftabstop= Distance between tab stops for column reporting + +ftemplate-depth- +C++ ObjC++ Joined RejectNegative UInteger Undocumented + +ftemplate-depth= +C++ ObjC++ Joined RejectNegative UInteger +-ftemplate-depth= Specify maximum template instantiation depth + +fthis-is-variable +C++ ObjC++ + +fthreadsafe-statics +C++ ObjC++ Optimization +-fno-threadsafe-statics Do not generate thread-safe code for initializing local statics + +funsigned-bitfields +C ObjC C++ ObjC++ +When \"signed\" or \"unsigned\" is not given make the bitfield unsigned + +funsigned-char +C ObjC C++ ObjC++ LTO +Make \"char\" unsigned by default + +fuse-cxa-atexit +C++ ObjC++ +Use __cxa_atexit to register destructors + +fuse-cxa-get-exception-ptr +C++ ObjC++ +Use __cxa_get_exception_ptr in exception handling + +fvisibility-inlines-hidden +C++ ObjC++ +Marks all inlined methods as having hidden visibility + +fvisibility-ms-compat +C++ ObjC++ Var(flag_visibility_ms_compat) +Changes visibility to match Microsoft Visual Studio by default + +fvtable-gc +C++ ObjC++ +Discard unused virtual functions + +fvtable-thunks +C++ ObjC++ +Implement vtables using thunks + +fweak +C++ ObjC++ +Emit common-like symbols as weak symbols + +fwide-exec-charset= +C ObjC C++ ObjC++ Joined RejectNegative +-fwide-exec-charset= Convert all wide strings and character constants to character set + +fworking-directory +C ObjC C++ ObjC++ +Generate a #line directive pointing at the current working directory + +fxref +C++ ObjC++ +Emit cross referencing information + +fzero-link +ObjC ObjC++ +Generate lazy class lookup (via objc_getClass()) for use in Zero-Link mode + +gen-decls +ObjC ObjC++ +Dump declarations to a .decl file + +femit-struct-debug-baseonly +C ObjC C++ ObjC++ +-femit-struct-debug-baseonly Aggressive reduced debug info for structs + +femit-struct-debug-reduced +C ObjC C++ ObjC++ +-femit-struct-debug-reduced Conservative reduced debug info for structs + +femit-struct-debug-detailed= +C ObjC C++ ObjC++ Joined +-femit-struct-debug-detailed= Detailed reduced debug info for structs + +idirafter +C ObjC C++ ObjC++ Joined Separate +-idirafter Add to the end of the system include path + +imacros +C ObjC C++ ObjC++ Joined Separate +-imacros Accept definition of macros in + +imultilib +C ObjC C++ ObjC++ Joined Separate +-imultilib Set to be the multilib include subdirectory + +include +C ObjC C++ ObjC++ Joined Separate +-include Include the contents of before other files + +iprefix +C ObjC C++ ObjC++ Joined Separate +-iprefix Specify as a prefix for next two options + +isysroot +C ObjC C++ ObjC++ Joined Separate +-isysroot Set to be the system root directory + +isystem +C ObjC C++ ObjC++ Joined Separate +-isystem Add to the start of the system include path + +iquote +C ObjC C++ ObjC++ Joined Separate +-iquote Add to the end of the quote include path + +iwithprefix +C ObjC C++ ObjC++ Joined Separate +-iwithprefix Add to the end of the system include path + +iwithprefixbefore +C ObjC C++ ObjC++ Joined Separate +-iwithprefixbefore Add to the end of the main include path + +lang-asm +C Undocumented + +lang-objc +C ObjC C++ ObjC++ Undocumented + +nostdinc +C ObjC C++ ObjC++ +Do not search standard system include directories (those specified with -isystem will still be used) + +nostdinc++ +C++ ObjC++ +Do not search standard system include directories for C++ + +o +C ObjC C++ ObjC++ Joined Separate +; Documented in common.opt + +pedantic +C ObjC C++ ObjC++ +; Documented in common.opt + +pedantic-errors +C ObjC C++ ObjC++ +; Documented in common.opt + +print-objc-runtime-info +ObjC ObjC++ +Generate C header of platform-specific features + +print-pch-checksum +C ObjC C++ ObjC++ +Print a checksum of the executable for PCH validity checking, and stop + +remap +C ObjC C++ ObjC++ +Remap file names when including files + +std=c++98 +C++ ObjC++ +Conform to the ISO 1998 C++ standard + +std=c++0x +C++ ObjC++ +Conform to the ISO 1998 C++ standard, with extensions that are likely to +become a part of the upcoming ISO C++ standard, dubbed C++0x. Note that the +extensions enabled by this mode are experimental and may be removed in +future releases of GCC. + +std=c1x +C ObjC +Conform to the ISO 201X C standard draft (experimental and incomplete support) + +std=c89 +C ObjC +Conform to the ISO 1990 C standard + +std=c90 +C ObjC +Conform to the ISO 1990 C standard + +std=c99 +C ObjC +Conform to the ISO 1999 C standard + +std=c9x +C ObjC +Deprecated in favor of -std=c99 + +std=gnu++98 +C++ ObjC++ +Conform to the ISO 1998 C++ standard with GNU extensions + +std=gnu++0x +C++ ObjC++ +Conform to the ISO 1998 C++ standard, with GNU extensions and +extensions that are likely to become a part of the upcoming ISO C++ +standard, dubbed C++0x. Note that the extensions enabled by this mode +are experimental and may be removed in future releases of GCC. + +std=gnu1x +C ObjC +Conform to the ISO 201X C standard draft with GNU extensions (experimental and incomplete support) + +std=gnu89 +C ObjC +Conform to the ISO 1990 C standard with GNU extensions + +std=gnu90 +C ObjC +Conform to the ISO 1990 C standard with GNU extensions + +std=gnu99 +C ObjC +Conform to the ISO 1999 C standard with GNU extensions + +std=gnu9x +C ObjC +Deprecated in favor of -std=gnu99 + +std=iso9899:1990 +C ObjC +Conform to the ISO 1990 C standard + +std=iso9899:199409 +C ObjC +Conform to the ISO 1990 C standard as amended in 1994 + +std=iso9899:1999 +C ObjC +Conform to the ISO 1999 C standard + +std=iso9899:199x +C ObjC +Deprecated in favor of -std=iso9899:1999 + +traditional-cpp +C ObjC C++ ObjC++ +Enable traditional preprocessing + +trigraphs +C ObjC C++ ObjC++ +-trigraphs Support ISO C trigraphs + +undef +C ObjC C++ ObjC++ +Do not predefine system-specific and GCC-specific macros + +v +Common C ObjC C++ ObjC++ +Enable verbose output + +w +C ObjC C++ ObjC++ +; Documented in common.opt + +; This comment is to ensure we retain the blank line above. diff --git a/gcc/c-family/stub-objc.c b/gcc/c-family/stub-objc.c new file mode 100644 index 0000000..b7748f7 --- /dev/null +++ b/gcc/c-family/stub-objc.c @@ -0,0 +1,327 @@ +/* Stub functions for Objective-C and Objective-C++ routines + that are called from within the C and C++ front-ends, + respectively. + Copyright (C) 1991, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2007, 2009 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 "tree.h" +#include "c-common.h" + +tree +objc_is_class_name (tree ARG_UNUSED (arg)) +{ + return 0; +} + +tree +objc_is_id (tree ARG_UNUSED (arg)) +{ + return 0; +} + +tree +objc_is_object_ptr (tree ARG_UNUSED (arg)) +{ + return 0; +} + +tree +objc_lookup_ivar (tree other, tree ARG_UNUSED (arg)) +{ + /* Just use whatever C/C++ found. */ + return other; +} + +void +objc_check_decl (tree ARG_UNUSED (decl)) +{ +} + +int +objc_is_reserved_word (tree ARG_UNUSED (ident)) +{ + return 0; +} + +bool +objc_compare_types (tree ARG_UNUSED (ltyp), tree ARG_UNUSED (rtyp), + int ARG_UNUSED (argno), tree ARG_UNUSED (callee)) +{ + return false; +} + +void +objc_volatilize_decl (tree ARG_UNUSED (decl)) +{ +} + +bool +objc_type_quals_match (tree ARG_UNUSED (ltyp), tree ARG_UNUSED (rtyp)) +{ + return false; +} + +tree +objc_rewrite_function_call (tree function, tree ARG_UNUSED (first_param)) +{ + return function; +} + +tree +objc_message_selector (void) +{ + return 0; +} + +void +objc_declare_alias (tree ARG_UNUSED (alias), tree ARG_UNUSED (orig)) +{ +} + +void +objc_declare_class (tree ARG_UNUSED (list)) +{ +} + +void +objc_declare_protocols (tree ARG_UNUSED (list)) +{ +} + +void +objc_start_protocol (tree ARG_UNUSED (proto), + tree ARG_UNUSED (protorefs)) +{ +} + +void +objc_start_class_interface (tree ARG_UNUSED (name), + tree ARG_UNUSED (super), + tree ARG_UNUSED (protos)) +{ +} + +void +objc_start_category_interface (tree ARG_UNUSED (name), + tree ARG_UNUSED (categ), + tree ARG_UNUSED (protos)) +{ +} + +void +objc_continue_interface (void) +{ +} + +void +objc_finish_interface (void) +{ +} + +void +objc_add_instance_variable (tree ARG_UNUSED (decl)) +{ +} + +void +objc_set_visibility (int ARG_UNUSED (vis)) +{ +} + +void +objc_set_method_type (enum tree_code ARG_UNUSED (code)) +{ +} + +void +objc_start_class_implementation (tree ARG_UNUSED (name), + tree ARG_UNUSED (super)) +{ +} + +void +objc_start_category_implementation (tree ARG_UNUSED (name), + tree ARG_UNUSED (categ)) +{ +} + +void +objc_continue_implementation (void) +{ +} + +void +objc_clear_super_receiver (void) +{ +} + +void +objc_finish_implementation (void) +{ +} + +void +objc_add_method_declaration (tree ARG_UNUSED (signature)) +{ +} + +void +objc_start_method_definition (tree ARG_UNUSED (signature)) +{ +} + +void +objc_finish_method_definition (tree ARG_UNUSED (fndecl)) +{ +} + +tree +objc_build_keyword_decl (tree ARG_UNUSED (selector), + tree ARG_UNUSED (type), + tree ARG_UNUSED (identifier)) +{ + return 0; +} + +tree +objc_build_method_signature (tree ARG_UNUSED (rettype), + tree ARG_UNUSED (selectors), + tree ARG_UNUSED (optparms), + bool ARG_UNUSED (ellipsis)) +{ + return 0; +} + +tree +objc_build_encode_expr (tree ARG_UNUSED (expr)) +{ + return 0; +} + +tree +objc_build_protocol_expr (tree ARG_UNUSED (expr)) +{ + return 0; +} + +tree +objc_build_selector_expr (location_t ARG_UNUSED (loc), tree ARG_UNUSED (expr)) +{ + return 0; +} + +tree +objc_build_message_expr (tree ARG_UNUSED (expr)) +{ + return 0; +} + +tree +objc_build_string_object (tree ARG_UNUSED (str)) +{ + return 0; +} + +tree +objc_get_class_reference (tree ARG_UNUSED (name)) +{ + return 0; +} + +tree +objc_get_protocol_qualified_type (tree ARG_UNUSED (name), + tree ARG_UNUSED (protos)) +{ + return 0; +} + +int +objc_static_init_needed_p (void) +{ + return 0; +} + +tree +objc_generate_static_init_call (tree ARG_UNUSED (ctors)) +{ + return 0; +} + +int +objc_is_public (tree ARG_UNUSED (expr), tree ARG_UNUSED (identifier)) +{ + return 1; +} + +tree +objc_get_class_ivars (tree ARG_UNUSED (name)) +{ + return 0; +} + +tree +objc_build_throw_stmt (location_t ARG_UNUSED (loc), tree ARG_UNUSED (expr)) +{ + return 0; +} + +tree +objc_build_synchronized (location_t ARG_UNUSED (start_locus), + tree ARG_UNUSED (mutex), tree ARG_UNUSED (body)) +{ + return 0; +} + +void +objc_begin_try_stmt (location_t ARG_UNUSED (try_locus), tree ARG_UNUSED (body)) +{ +} + +void +objc_begin_catch_clause (tree ARG_UNUSED (decl)) +{ +} + +void +objc_finish_catch_clause (void) +{ +} + +void +objc_build_finally_clause (location_t ARG_UNUSED (finally_locus), + tree ARG_UNUSED (body)) +{ +} + +tree +objc_finish_try_stmt (void) +{ + return 0; +} + +tree +objc_generate_write_barrier (tree ARG_UNUSED (lhs), + enum tree_code ARG_UNUSED (modifycode), + tree ARG_UNUSED (rhs)) +{ + return 0; +} diff --git a/gcc/c-format.c b/gcc/c-format.c deleted file mode 100644 index 2c73ead..0000000 --- a/gcc/c-format.c +++ /dev/null @@ -1,2870 +0,0 @@ -/* Check calls to formatted I/O functions (-Wformat). - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 - 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 "tree.h" -#include "flags.h" -#include "c-common.h" -#include "toplev.h" -#include "intl.h" -#include "diagnostic-core.h" -#include "langhooks.h" -#include "c-format.h" -#include "alloc-pool.h" - -/* Set format warning options according to a -Wformat=n option. */ - -void -set_Wformat (int setting) -{ - warn_format = setting; - warn_format_extra_args = setting; - warn_format_zero_length = setting; - warn_format_contains_nul = setting; - if (setting != 1) - { - warn_format_nonliteral = setting; - warn_format_security = setting; - warn_format_y2k = setting; - } - /* Make sure not to disable -Wnonnull if -Wformat=0 is specified. */ - if (setting) - warn_nonnull = setting; -} - - -/* Handle attributes associated with format checking. */ - -/* This must be in the same order as format_types, except for - format_type_error. Target-specific format types do not have - matching enum values. */ -enum format_type { printf_format_type, asm_fprintf_format_type, - gcc_diag_format_type, gcc_tdiag_format_type, - gcc_cdiag_format_type, - gcc_cxxdiag_format_type, gcc_gfc_format_type, - format_type_error = -1}; - -typedef struct function_format_info -{ - int format_type; /* type of format (printf, scanf, etc.) */ - unsigned HOST_WIDE_INT format_num; /* number of format argument */ - unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */ -} function_format_info; - -static bool decode_format_attr (tree, function_format_info *, int); -static int decode_format_type (const char *); - -static bool check_format_string (tree argument, - unsigned HOST_WIDE_INT format_num, - int flags, bool *no_add_attrs); -static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value, - int validated_p); -static const char *convert_format_name_to_system_name (const char *attr_name); -static bool cmp_attribs (const char *tattr_name, const char *attr_name); - -/* Handle a "format_arg" attribute; arguments as in - struct attribute_spec.handler. */ -tree -handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name), - tree args, int flags, bool *no_add_attrs) -{ - tree type = *node; - tree format_num_expr = TREE_VALUE (args); - unsigned HOST_WIDE_INT format_num = 0; - tree argument; - - if (!get_constant (format_num_expr, &format_num, 0)) - { - error ("format string has invalid operand number"); - *no_add_attrs = true; - return NULL_TREE; - } - - argument = TYPE_ARG_TYPES (type); - if (argument) - { - if (!check_format_string (argument, format_num, flags, no_add_attrs)) - return NULL_TREE; - } - - if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE - || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) - != char_type_node)) - { - if (!(flags & (int) ATTR_FLAG_BUILT_IN)) - error ("function does not return string type"); - *no_add_attrs = true; - return NULL_TREE; - } - - return NULL_TREE; -} - -/* Verify that the format_num argument is actually a string, in case - the format attribute is in error. */ -static bool -check_format_string (tree argument, unsigned HOST_WIDE_INT format_num, - int flags, bool *no_add_attrs) -{ - unsigned HOST_WIDE_INT i; - - for (i = 1; i != format_num; i++) - { - if (argument == 0) - break; - argument = TREE_CHAIN (argument); - } - - if (!argument - || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE - || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) - != char_type_node)) - { - if (!(flags & (int) ATTR_FLAG_BUILT_IN)) - error ("format string argument not a string type"); - *no_add_attrs = true; - return false; - } - - return true; -} - -/* Verify EXPR is a constant, and store its value. - If validated_p is true there should be no errors. - Returns true on success, false otherwise. */ -static bool -get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p) -{ - if (TREE_CODE (expr) != INTEGER_CST || TREE_INT_CST_HIGH (expr) != 0) - { - gcc_assert (!validated_p); - return false; - } - - *value = TREE_INT_CST_LOW (expr); - - return true; -} - -/* Decode the arguments to a "format" attribute into a - function_format_info structure. It is already known that the list - is of the right length. If VALIDATED_P is true, then these - attributes have already been validated and must not be erroneous; - if false, it will give an error message. Returns true if the - attributes are successfully decoded, false otherwise. */ - -static bool -decode_format_attr (tree args, function_format_info *info, int validated_p) -{ - tree format_type_id = TREE_VALUE (args); - tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); - tree first_arg_num_expr - = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); - - if (TREE_CODE (format_type_id) != IDENTIFIER_NODE) - { - gcc_assert (!validated_p); - error ("unrecognized format specifier"); - return false; - } - else - { - const char *p = IDENTIFIER_POINTER (format_type_id); - - p = convert_format_name_to_system_name (p); - - info->format_type = decode_format_type (p); - - if (info->format_type == format_type_error) - { - gcc_assert (!validated_p); - warning (OPT_Wformat, "%qE is an unrecognized format function type", - format_type_id); - return false; - } - } - - if (!get_constant (format_num_expr, &info->format_num, validated_p)) - { - error ("format string has invalid operand number"); - return false; - } - - if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p)) - { - error ("%<...%> has invalid operand number"); - return false; - } - - if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num) - { - gcc_assert (!validated_p); - error ("format string argument follows the args to be formatted"); - return false; - } - - return true; -} - -/* Check a call to a format function against a parameter list. */ - -/* The C standard version C++ is treated as equivalent to - or inheriting from, for the purpose of format features supported. */ -#define CPLUSPLUS_STD_VER STD_C94 -/* The C standard version we are checking formats against when pedantic. */ -#define C_STD_VER ((int) (c_dialect_cxx () \ - ? CPLUSPLUS_STD_VER \ - : (flag_isoc99 \ - ? STD_C99 \ - : (flag_isoc94 ? STD_C94 : STD_C89)))) -/* The name to give to the standard version we are warning about when - pedantic. FEATURE_VER is the version in which the feature warned out - appeared, which is higher than C_STD_VER. */ -#define C_STD_NAME(FEATURE_VER) (c_dialect_cxx () \ - ? "ISO C++" \ - : ((FEATURE_VER) == STD_EXT \ - ? "ISO C" \ - : "ISO C90")) -/* Adjust a C standard version, which may be STD_C9L, to account for - -Wno-long-long. Returns other standard versions unchanged. */ -#define ADJ_STD(VER) ((int) ((VER) == STD_C9L \ - ? (warn_long_long ? STD_C99 : STD_C89) \ - : (VER))) - -/* Structure describing details of a type expected in format checking, - and the type to check against it. */ -typedef struct format_wanted_type -{ - /* The type wanted. */ - tree wanted_type; - /* The name of this type to use in diagnostics. */ - const char *wanted_type_name; - /* Should be type checked just for scalar width identity. */ - int scalar_identity_flag; - /* The level of indirection through pointers at which this type occurs. */ - int pointer_count; - /* Whether, when pointer_count is 1, to allow any character type when - pedantic, rather than just the character or void type specified. */ - int char_lenient_flag; - /* Whether the argument, dereferenced once, is written into and so the - argument must not be a pointer to a const-qualified type. */ - int writing_in_flag; - /* Whether the argument, dereferenced once, is read from and so - must not be a NULL pointer. */ - int reading_from_flag; - /* If warnings should be of the form "field precision should have - type 'int'", the name to use (in this case "field precision"), - otherwise NULL, for "format expects type 'long'" type - messages. */ - const char *name; - /* The actual parameter to check against the wanted type. */ - tree param; - /* The argument number of that parameter. */ - int arg_num; - /* The next type to check for this format conversion, or NULL if none. */ - struct format_wanted_type *next; -} format_wanted_type; - -/* Convenience macro for format_length_info meaning unused. */ -#define NO_FMT NULL, FMT_LEN_none, STD_C89 - -static const format_length_info printf_length_specs[] = -{ - { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 }, - { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 }, - { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 }, - { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 }, - { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 }, - { "Z", FMT_LEN_z, STD_EXT, NO_FMT, 0 }, - { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 }, - { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 }, - { "H", FMT_LEN_H, STD_EXT, NO_FMT, 0 }, - { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT, 0 }, - { NO_FMT, NO_FMT, 0 } -}; - -/* Length specifiers valid for asm_fprintf. */ -static const format_length_info asm_fprintf_length_specs[] = -{ - { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 }, - { "w", FMT_LEN_none, STD_C89, NO_FMT, 0 }, - { NO_FMT, NO_FMT, 0 } -}; - -/* Length specifiers valid for GCC diagnostics. */ -static const format_length_info gcc_diag_length_specs[] = -{ - { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 }, - { "w", FMT_LEN_none, STD_C89, NO_FMT, 0 }, - { NO_FMT, NO_FMT, 0 } -}; - -/* The custom diagnostics all accept the same length specifiers. */ -#define gcc_tdiag_length_specs gcc_diag_length_specs -#define gcc_cdiag_length_specs gcc_diag_length_specs -#define gcc_cxxdiag_length_specs gcc_diag_length_specs - -/* This differs from printf_length_specs only in that "Z" is not accepted. */ -static const format_length_info scanf_length_specs[] = -{ - { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 }, - { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 }, - { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 }, - { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 }, - { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 }, - { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 }, - { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 }, - { "H", FMT_LEN_H, STD_EXT, NO_FMT, 0 }, - { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT, 0 }, - { NO_FMT, NO_FMT, 0 } -}; - - -/* All tables for strfmon use STD_C89 everywhere, since -pedantic warnings - make no sense for a format type not part of any C standard version. */ -static const format_length_info strfmon_length_specs[] = -{ - /* A GNU extension. */ - { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 }, - { NO_FMT, NO_FMT, 0 } -}; - - -/* For now, the Fortran front-end routines only use l as length modifier. */ -static const format_length_info gcc_gfc_length_specs[] = -{ - { "l", FMT_LEN_l, STD_C89, NO_FMT, 0 }, - { NO_FMT, NO_FMT, 0 } -}; - - -static const format_flag_spec printf_flag_specs[] = -{ - { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 }, - { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, - { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, - { '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 }, - { '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 }, - { '\'', 0, 0, N_("''' flag"), N_("the ''' printf flag"), STD_EXT }, - { 'I', 0, 0, N_("'I' flag"), N_("the 'I' printf flag"), STD_EXT }, - { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, - { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, - { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, - { 0, 0, 0, NULL, NULL, STD_C89 } -}; - - -static const format_flag_pair printf_flag_pairs[] = -{ - { ' ', '+', 1, 0 }, - { '0', '-', 1, 0 }, - { '0', 'p', 1, 'i' }, - { 0, 0, 0, 0 } -}; - -static const format_flag_spec asm_fprintf_flag_specs[] = -{ - { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 }, - { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, - { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, - { '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 }, - { '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 }, - { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, - { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, - { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, - { 0, 0, 0, NULL, NULL, STD_C89 } -}; - -static const format_flag_pair asm_fprintf_flag_pairs[] = -{ - { ' ', '+', 1, 0 }, - { '0', '-', 1, 0 }, - { '0', 'p', 1, 'i' }, - { 0, 0, 0, 0 } -}; - -static const format_flag_pair gcc_diag_flag_pairs[] = -{ - { 0, 0, 0, 0 } -}; - -#define gcc_tdiag_flag_pairs gcc_diag_flag_pairs -#define gcc_cdiag_flag_pairs gcc_diag_flag_pairs -#define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs - -static const format_flag_pair gcc_gfc_flag_pairs[] = -{ - { 0, 0, 0, 0 } -}; - -static const format_flag_spec gcc_diag_flag_specs[] = -{ - { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, - { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, - { 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 }, - { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, - { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, - { 0, 0, 0, NULL, NULL, STD_C89 } -}; - -#define gcc_tdiag_flag_specs gcc_diag_flag_specs -#define gcc_cdiag_flag_specs gcc_diag_flag_specs -#define gcc_cxxdiag_flag_specs gcc_diag_flag_specs - -static const format_flag_spec scanf_flag_specs[] = -{ - { '*', 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 }, - { 'a', 0, 0, N_("'a' flag"), N_("the 'a' scanf flag"), STD_EXT }, - { 'm', 0, 0, N_("'m' flag"), N_("the 'm' scanf flag"), STD_EXT }, - { 'w', 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 }, - { 'L', 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 }, - { '\'', 0, 0, N_("''' flag"), N_("the ''' scanf flag"), STD_EXT }, - { 'I', 0, 0, N_("'I' flag"), N_("the 'I' scanf flag"), STD_EXT }, - { 0, 0, 0, NULL, NULL, STD_C89 } -}; - - -static const format_flag_pair scanf_flag_pairs[] = -{ - { '*', 'L', 0, 0 }, - { 'a', 'm', 0, 0 }, - { 0, 0, 0, 0 } -}; - - -static const format_flag_spec strftime_flag_specs[] = -{ - { '_', 0, 0, N_("'_' flag"), N_("the '_' strftime flag"), STD_EXT }, - { '-', 0, 0, N_("'-' flag"), N_("the '-' strftime flag"), STD_EXT }, - { '0', 0, 0, N_("'0' flag"), N_("the '0' strftime flag"), STD_EXT }, - { '^', 0, 0, N_("'^' flag"), N_("the '^' strftime flag"), STD_EXT }, - { '#', 0, 0, N_("'#' flag"), N_("the '#' strftime flag"), STD_EXT }, - { 'w', 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT }, - { 'E', 0, 0, N_("'E' modifier"), N_("the 'E' strftime modifier"), STD_C99 }, - { 'O', 0, 0, N_("'O' modifier"), N_("the 'O' strftime modifier"), STD_C99 }, - { 'O', 'o', 0, NULL, N_("the 'O' modifier"), STD_EXT }, - { 0, 0, 0, NULL, NULL, STD_C89 } -}; - - -static const format_flag_pair strftime_flag_pairs[] = -{ - { 'E', 'O', 0, 0 }, - { '_', '-', 0, 0 }, - { '_', '0', 0, 0 }, - { '-', '0', 0, 0 }, - { '^', '#', 0, 0 }, - { 0, 0, 0, 0 } -}; - - -static const format_flag_spec strfmon_flag_specs[] = -{ - { '=', 0, 1, N_("fill character"), N_("fill character in strfmon format"), STD_C89 }, - { '^', 0, 0, N_("'^' flag"), N_("the '^' strfmon flag"), STD_C89 }, - { '+', 0, 0, N_("'+' flag"), N_("the '+' strfmon flag"), STD_C89 }, - { '(', 0, 0, N_("'(' flag"), N_("the '(' strfmon flag"), STD_C89 }, - { '!', 0, 0, N_("'!' flag"), N_("the '!' strfmon flag"), STD_C89 }, - { '-', 0, 0, N_("'-' flag"), N_("the '-' strfmon flag"), STD_C89 }, - { 'w', 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 }, - { '#', 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 }, - { 'p', 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 }, - { 'L', 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 }, - { 0, 0, 0, NULL, NULL, STD_C89 } -}; - -static const format_flag_pair strfmon_flag_pairs[] = -{ - { '+', '(', 0, 0 }, - { 0, 0, 0, 0 } -}; - - -static const format_char_info print_char_table[] = -{ - /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "-wp0 +'I", "i", NULL }, - { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL }, - { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0'I", "i", NULL }, - { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL }, - { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#I", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c", NULL }, - { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "", "W", NULL }, - /* C99 conversion specifiers. */ - { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL }, - { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL }, - /* X/Open conversion specifiers. */ - { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, - { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL }, - /* GNU conversion specifiers. */ - { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL }, - { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info asm_fprintf_char_table[] = -{ - /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +", "i", NULL }, - { "oxX", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0", "i", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, - - /* asm_fprintf conversion specifiers. */ - { "O", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "R", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "I", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "L", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "U", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, - { "@", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info gcc_diag_char_table[] = -{ - /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, - - /* Custom conversion specifiers. */ - - /* These will require a "tree" at runtime. */ - { "K", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - - { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info gcc_tdiag_char_table[] = -{ - /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, - - /* Custom conversion specifiers. */ - - /* These will require a "tree" at runtime. */ - { "DFKTEV", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, - - { "v", 0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL }, - - { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info gcc_cdiag_char_table[] = -{ - /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, - - /* Custom conversion specifiers. */ - - /* These will require a "tree" at runtime. */ - { "DEFKTV", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, - - { "v", 0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL }, - - { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info gcc_cxxdiag_char_table[] = -{ - /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, - - /* Custom conversion specifiers. */ - - /* These will require a "tree" at runtime. */ - { "ADEFKTV",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL }, - - { "v", 0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL }, - - /* These accept either an 'int' or an 'enum tree_code' (which is handled as an 'int'.) */ - { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - - { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info gcc_gfc_char_table[] = -{ - /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL }, - - /* gfc conversion specifiers. */ - - { "C", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - - /* This will require a "locus" at runtime. */ - { "L", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "R", NULL }, - - { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info scan_char_table[] = -{ - /* C89 conversion specifiers. */ - { "di", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "*w'I", "W", NULL }, - { "u", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "*w'I", "W", NULL }, - { "oxX", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, - { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "*w'", "W", NULL }, - { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*mw", "cW", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "cW", NULL }, - { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "cW[", NULL }, - { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, - { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "", "W", NULL }, - /* C99 conversion specifiers. */ - { "F", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "*w'", "W", NULL }, - { "aA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, - /* X/Open conversion specifiers. */ - { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*mw", "W", NULL }, - { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "W", NULL }, - { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info time_char_table[] = -{ - /* C89 conversion specifiers. */ - { "ABZab", 0, STD_C89, NOLENGTHS, "^#", "", NULL }, - { "cx", 0, STD_C89, NOLENGTHS, "E", "3", NULL }, - { "HIMSUWdmw", 0, STD_C89, NOLENGTHS, "-_0Ow", "", NULL }, - { "j", 0, STD_C89, NOLENGTHS, "-_0Ow", "o", NULL }, - { "p", 0, STD_C89, NOLENGTHS, "#", "", NULL }, - { "X", 0, STD_C89, NOLENGTHS, "E", "", NULL }, - { "y", 0, STD_C89, NOLENGTHS, "EO-_0w", "4", NULL }, - { "Y", 0, STD_C89, NOLENGTHS, "-_0EOw", "o", NULL }, - { "%", 0, STD_C89, NOLENGTHS, "", "", NULL }, - /* C99 conversion specifiers. */ - { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o", NULL }, - { "D", 0, STD_C99, NOLENGTHS, "", "2", NULL }, - { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "", NULL }, - { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "", NULL }, - { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o", NULL }, - { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o", NULL }, - { "h", 0, STD_C99, NOLENGTHS, "^#", "", NULL }, - { "z", 0, STD_C99, NOLENGTHS, "O", "o", NULL }, - /* GNU conversion specifiers. */ - { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "", NULL }, - { "P", 0, STD_EXT, NOLENGTHS, "", "", NULL }, - { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info monetary_char_table[] = -{ - { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "", NULL }, - { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } -}; - -/* This must be in the same order as enum format_type. */ -static const format_kind_info format_types_orig[] = -{ - { "gnu_printf", printf_length_specs, print_char_table, " +#0-'I", NULL, - printf_flag_specs, printf_flag_pairs, - FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK, - 'w', 0, 'p', 0, 'L', 0, - &integer_type_node, &integer_type_node - }, - { "asm_fprintf", asm_fprintf_length_specs, asm_fprintf_char_table, " +#0-", NULL, - asm_fprintf_flag_specs, asm_fprintf_flag_pairs, - FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK, - 'w', 0, 'p', 0, 'L', 0, - NULL, NULL - }, - { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "q+#", NULL, - gcc_diag_flag_specs, gcc_diag_flag_pairs, - FMT_FLAG_ARG_CONVERT, - 0, 0, 'p', 0, 'L', 0, - NULL, &integer_type_node - }, - { "gcc_tdiag", gcc_tdiag_length_specs, gcc_tdiag_char_table, "q+#", NULL, - gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs, - FMT_FLAG_ARG_CONVERT, - 0, 0, 'p', 0, 'L', 0, - NULL, &integer_type_node - }, - { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "q+#", NULL, - gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs, - FMT_FLAG_ARG_CONVERT, - 0, 0, 'p', 0, 'L', 0, - NULL, &integer_type_node - }, - { "gcc_cxxdiag", gcc_cxxdiag_length_specs, gcc_cxxdiag_char_table, "q+#", NULL, - gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs, - FMT_FLAG_ARG_CONVERT, - 0, 0, 'p', 0, 'L', 0, - NULL, &integer_type_node - }, - { "gcc_gfc", gcc_gfc_length_specs, gcc_gfc_char_table, "", NULL, - NULL, gcc_gfc_flag_pairs, - FMT_FLAG_ARG_CONVERT, - 0, 0, 0, 0, 0, 0, - NULL, NULL - }, - { "gnu_scanf", scanf_length_specs, scan_char_table, "*'I", NULL, - scanf_flag_specs, scanf_flag_pairs, - FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK, - 'w', 0, 0, '*', 'L', 'm', - NULL, NULL - }, - { "gnu_strftime", NULL, time_char_table, "_-0^#", "EO", - strftime_flag_specs, strftime_flag_pairs, - FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0, - NULL, NULL - }, - { "gnu_strfmon", strfmon_length_specs, monetary_char_table, "=^+(!-", NULL, - strfmon_flag_specs, strfmon_flag_pairs, - FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0, - NULL, NULL - } -}; - -/* This layer of indirection allows GCC to reassign format_types with - new data if necessary, while still allowing the original data to be - const. */ -static const format_kind_info *format_types = format_types_orig; -/* We can modify this one. We also add target-specific format types - to the end of the array. */ -static format_kind_info *dynamic_format_types; - -static int n_format_types = ARRAY_SIZE (format_types_orig); - -/* Structure detailing the results of checking a format function call - where the format expression may be a conditional expression with - many leaves resulting from nested conditional expressions. */ -typedef struct -{ - /* Number of leaves of the format argument that could not be checked - as they were not string literals. */ - int number_non_literal; - /* Number of leaves of the format argument that were null pointers or - string literals, but had extra format arguments. */ - int number_extra_args; - /* Number of leaves of the format argument that were null pointers or - string literals, but had extra format arguments and used $ operand - numbers. */ - int number_dollar_extra_args; - /* Number of leaves of the format argument that were wide string - literals. */ - int number_wide; - /* Number of leaves of the format argument that were empty strings. */ - int number_empty; - /* Number of leaves of the format argument that were unterminated - strings. */ - int number_unterminated; - /* Number of leaves of the format argument that were not counted above. */ - int number_other; -} format_check_results; - -typedef struct -{ - format_check_results *res; - function_format_info *info; - tree params; -} format_check_context; - -static void check_format_info (function_format_info *, tree); -static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT); -static void check_format_info_main (format_check_results *, - function_format_info *, - const char *, int, tree, - unsigned HOST_WIDE_INT, alloc_pool); - -static void init_dollar_format_checking (int, tree); -static int maybe_read_dollar_number (const char **, int, - tree, tree *, const format_kind_info *); -static bool avoid_dollar_number (const char *); -static void finish_dollar_format_checking (format_check_results *, int); - -static const format_flag_spec *get_flag_spec (const format_flag_spec *, - int, const char *); - -static void check_format_types (format_wanted_type *, const char *, int); -static void format_type_warning (const char *, const char *, int, tree, - int, const char *, tree, int); - -/* Decode a format type from a string, returning the type, or - format_type_error if not valid, in which case the caller should print an - error message. */ -static int -decode_format_type (const char *s) -{ - int i; - int slen; - - s = convert_format_name_to_system_name (s); - slen = strlen (s); - for (i = 0; i < n_format_types; i++) - { - int alen; - if (!strcmp (s, format_types[i].name)) - return i; - alen = strlen (format_types[i].name); - if (slen == alen + 4 && s[0] == '_' && s[1] == '_' - && s[slen - 1] == '_' && s[slen - 2] == '_' - && !strncmp (s + 2, format_types[i].name, alen)) - return i; - } - return format_type_error; -} - - -/* Check the argument list of a call to printf, scanf, etc. - ATTRS are the attributes on the function type. There are NARGS argument - values in the array ARGARRAY. - Also, if -Wmissing-format-attribute, - warn for calls to vprintf or vscanf in functions with no such format - attribute themselves. */ - -void -check_function_format (tree attrs, int nargs, tree *argarray) -{ - tree a; - - /* See if this function has any format attributes. */ - for (a = attrs; a; a = TREE_CHAIN (a)) - { - if (is_attribute_p ("format", TREE_PURPOSE (a))) - { - /* Yup; check it. */ - function_format_info info; - decode_format_attr (TREE_VALUE (a), &info, 1); - if (warn_format) - { - /* FIXME: Rewrite all the internal functions in this file - to use the ARGARRAY directly instead of constructing this - temporary list. */ - tree params = NULL_TREE; - int i; - for (i = nargs - 1; i >= 0; i--) - params = tree_cons (NULL_TREE, argarray[i], params); - check_format_info (&info, params); - } - if (warn_missing_format_attribute && info.first_arg_num == 0 - && (format_types[info.format_type].flags - & (int) FMT_FLAG_ARG_CONVERT)) - { - tree c; - for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); - c; - c = TREE_CHAIN (c)) - if (is_attribute_p ("format", TREE_PURPOSE (c)) - && (decode_format_type (IDENTIFIER_POINTER - (TREE_VALUE (TREE_VALUE (c)))) - == info.format_type)) - break; - if (c == NULL_TREE) - { - /* Check if the current function has a parameter to which - the format attribute could be attached; if not, it - can't be a candidate for a format attribute, despite - the vprintf-like or vscanf-like call. */ - tree args; - for (args = DECL_ARGUMENTS (current_function_decl); - args != 0; - args = TREE_CHAIN (args)) - { - if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE - && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args))) - == char_type_node)) - break; - } - if (args != 0) - warning (OPT_Wmissing_format_attribute, "function might " - "be possible candidate for %qs format attribute", - format_types[info.format_type].name); - } - } - } - } -} - - -/* Variables used by the checking of $ operand number formats. */ -static char *dollar_arguments_used = NULL; -static char *dollar_arguments_pointer_p = NULL; -static int dollar_arguments_alloc = 0; -static int dollar_arguments_count; -static int dollar_first_arg_num; -static int dollar_max_arg_used; -static int dollar_format_warned; - -/* Initialize the checking for a format string that may contain $ - parameter number specifications; we will need to keep track of whether - each parameter has been used. FIRST_ARG_NUM is the number of the first - argument that is a parameter to the format, or 0 for a vprintf-style - function; PARAMS is the list of arguments starting at this argument. */ - -static void -init_dollar_format_checking (int first_arg_num, tree params) -{ - tree oparams = params; - - dollar_first_arg_num = first_arg_num; - dollar_arguments_count = 0; - dollar_max_arg_used = 0; - dollar_format_warned = 0; - if (first_arg_num > 0) - { - while (params) - { - dollar_arguments_count++; - params = TREE_CHAIN (params); - } - } - if (dollar_arguments_alloc < dollar_arguments_count) - { - if (dollar_arguments_used) - free (dollar_arguments_used); - if (dollar_arguments_pointer_p) - free (dollar_arguments_pointer_p); - dollar_arguments_alloc = dollar_arguments_count; - dollar_arguments_used = XNEWVEC (char, dollar_arguments_alloc); - dollar_arguments_pointer_p = XNEWVEC (char, dollar_arguments_alloc); - } - if (dollar_arguments_alloc) - { - memset (dollar_arguments_used, 0, dollar_arguments_alloc); - if (first_arg_num > 0) - { - int i = 0; - params = oparams; - while (params) - { - dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params))) - == POINTER_TYPE); - params = TREE_CHAIN (params); - i++; - } - } - } -} - - -/* Look for a decimal number followed by a $ in *FORMAT. If DOLLAR_NEEDED - is set, it is an error if one is not found; otherwise, it is OK. If - such a number is found, check whether it is within range and mark that - numbered operand as being used for later checking. Returns the operand - number if found and within range, zero if no such number was found and - this is OK, or -1 on error. PARAMS points to the first operand of the - format; PARAM_PTR is made to point to the parameter referred to. If - a $ format is found, *FORMAT is updated to point just after it. */ - -static int -maybe_read_dollar_number (const char **format, - int dollar_needed, tree params, tree *param_ptr, - const format_kind_info *fki) -{ - int argnum; - int overflow_flag; - const char *fcp = *format; - if (!ISDIGIT (*fcp)) - { - if (dollar_needed) - { - warning (OPT_Wformat, "missing $ operand number in format"); - return -1; - } - else - return 0; - } - argnum = 0; - overflow_flag = 0; - while (ISDIGIT (*fcp)) - { - int nargnum; - nargnum = 10 * argnum + (*fcp - '0'); - if (nargnum < 0 || nargnum / 10 != argnum) - overflow_flag = 1; - argnum = nargnum; - fcp++; - } - if (*fcp != '$') - { - if (dollar_needed) - { - warning (OPT_Wformat, "missing $ operand number in format"); - return -1; - } - else - return 0; - } - *format = fcp + 1; - if (pedantic && !dollar_format_warned) - { - warning (OPT_Wformat, "%s does not support %%n$ operand number formats", - C_STD_NAME (STD_EXT)); - dollar_format_warned = 1; - } - if (overflow_flag || argnum == 0 - || (dollar_first_arg_num && argnum > dollar_arguments_count)) - { - warning (OPT_Wformat, "operand number out of range in format"); - return -1; - } - if (argnum > dollar_max_arg_used) - dollar_max_arg_used = argnum; - /* For vprintf-style functions we may need to allocate more memory to - track which arguments are used. */ - while (dollar_arguments_alloc < dollar_max_arg_used) - { - int nalloc; - nalloc = 2 * dollar_arguments_alloc + 16; - dollar_arguments_used = XRESIZEVEC (char, dollar_arguments_used, - nalloc); - dollar_arguments_pointer_p = XRESIZEVEC (char, dollar_arguments_pointer_p, - nalloc); - memset (dollar_arguments_used + dollar_arguments_alloc, 0, - nalloc - dollar_arguments_alloc); - dollar_arguments_alloc = nalloc; - } - if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE) - && dollar_arguments_used[argnum - 1] == 1) - { - dollar_arguments_used[argnum - 1] = 2; - warning (OPT_Wformat, "format argument %d used more than once in %s format", - argnum, fki->name); - } - else - dollar_arguments_used[argnum - 1] = 1; - if (dollar_first_arg_num) - { - int i; - *param_ptr = params; - for (i = 1; i < argnum && *param_ptr != 0; i++) - *param_ptr = TREE_CHAIN (*param_ptr); - - /* This case shouldn't be caught here. */ - gcc_assert (*param_ptr); - } - else - *param_ptr = 0; - return argnum; -} - -/* Ensure that FORMAT does not start with a decimal number followed by - a $; give a diagnostic and return true if it does, false otherwise. */ - -static bool -avoid_dollar_number (const char *format) -{ - if (!ISDIGIT (*format)) - return false; - while (ISDIGIT (*format)) - format++; - if (*format == '$') - { - warning (OPT_Wformat, "$ operand number used after format without operand number"); - return true; - } - return false; -} - - -/* Finish the checking for a format string that used $ operand number formats - instead of non-$ formats. We check for unused operands before used ones - (a serious error, since the implementation of the format function - can't know what types to pass to va_arg to find the later arguments). - and for unused operands at the end of the format (if we know how many - arguments the format had, so not for vprintf). If there were operand - numbers out of range on a non-vprintf-style format, we won't have reached - here. If POINTER_GAP_OK, unused arguments are OK if all arguments are - pointers. */ - -static void -finish_dollar_format_checking (format_check_results *res, int pointer_gap_ok) -{ - int i; - bool found_pointer_gap = false; - for (i = 0; i < dollar_max_arg_used; i++) - { - if (!dollar_arguments_used[i]) - { - if (pointer_gap_ok && (dollar_first_arg_num == 0 - || dollar_arguments_pointer_p[i])) - found_pointer_gap = true; - else - warning (OPT_Wformat, - "format argument %d unused before used argument %d in $-style format", - i + 1, dollar_max_arg_used); - } - } - if (found_pointer_gap - || (dollar_first_arg_num - && dollar_max_arg_used < dollar_arguments_count)) - { - res->number_other--; - res->number_dollar_extra_args++; - } -} - - -/* Retrieve the specification for a format flag. SPEC contains the - specifications for format flags for the applicable kind of format. - FLAG is the flag in question. If PREDICATES is NULL, the basic - spec for that flag must be retrieved and must exist. If - PREDICATES is not NULL, it is a string listing possible predicates - for the spec entry; if an entry predicated on any of these is - found, it is returned, otherwise NULL is returned. */ - -static const format_flag_spec * -get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates) -{ - int i; - for (i = 0; spec[i].flag_char != 0; i++) - { - if (spec[i].flag_char != flag) - continue; - if (predicates != NULL) - { - if (spec[i].predicate != 0 - && strchr (predicates, spec[i].predicate) != 0) - return &spec[i]; - } - else if (spec[i].predicate == 0) - return &spec[i]; - } - gcc_assert (predicates); - return NULL; -} - - -/* Check the argument list of a call to printf, scanf, etc. - INFO points to the function_format_info structure. - PARAMS is the list of argument values. */ - -static void -check_format_info (function_format_info *info, tree params) -{ - format_check_context format_ctx; - unsigned HOST_WIDE_INT arg_num; - tree format_tree; - format_check_results res; - /* Skip to format argument. If the argument isn't available, there's - no work for us to do; prototype checking will catch the problem. */ - for (arg_num = 1; ; ++arg_num) - { - if (params == 0) - return; - if (arg_num == info->format_num) - break; - params = TREE_CHAIN (params); - } - format_tree = TREE_VALUE (params); - params = TREE_CHAIN (params); - if (format_tree == 0) - return; - - res.number_non_literal = 0; - res.number_extra_args = 0; - res.number_dollar_extra_args = 0; - res.number_wide = 0; - res.number_empty = 0; - res.number_unterminated = 0; - res.number_other = 0; - - format_ctx.res = &res; - format_ctx.info = info; - format_ctx.params = params; - - check_function_arguments_recurse (check_format_arg, &format_ctx, - format_tree, arg_num); - - if (res.number_non_literal > 0) - { - /* Functions taking a va_list normally pass a non-literal format - string. These functions typically are declared with - first_arg_num == 0, so avoid warning in those cases. */ - if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT)) - { - /* For strftime-like formats, warn for not checking the format - string; but there are no arguments to check. */ - warning (OPT_Wformat_nonliteral, - "format not a string literal, format string not checked"); - } - else if (info->first_arg_num != 0) - { - /* If there are no arguments for the format at all, we may have - printf (foo) which is likely to be a security hole. */ - while (arg_num + 1 < info->first_arg_num) - { - if (params == 0) - break; - params = TREE_CHAIN (params); - ++arg_num; - } - if (params == 0 && warn_format_security) - warning (OPT_Wformat_security, - "format not a string literal and no format arguments"); - else if (params == 0 && warn_format_nonliteral) - warning (OPT_Wformat_nonliteral, - "format not a string literal and no format arguments"); - else - warning (OPT_Wformat_nonliteral, - "format not a string literal, argument types not checked"); - } - } - - /* If there were extra arguments to the format, normally warn. However, - the standard does say extra arguments are ignored, so in the specific - case where we have multiple leaves (conditional expressions or - ngettext) allow extra arguments if at least one leaf didn't have extra - arguments, but was otherwise OK (either non-literal or checked OK). - If the format is an empty string, this should be counted similarly to the - case of extra format arguments. */ - if (res.number_extra_args > 0 && res.number_non_literal == 0 - && res.number_other == 0) - warning (OPT_Wformat_extra_args, "too many arguments for format"); - if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0 - && res.number_other == 0) - warning (OPT_Wformat_extra_args, "unused arguments in $-style format"); - if (res.number_empty > 0 && res.number_non_literal == 0 - && res.number_other == 0) - warning (OPT_Wformat_zero_length, "zero-length %s format string", - format_types[info->format_type].name); - - if (res.number_wide > 0) - warning (OPT_Wformat, "format is a wide character string"); - - if (res.number_unterminated > 0) - warning (OPT_Wformat, "unterminated format string"); -} - -/* Callback from check_function_arguments_recurse to check a - format string. FORMAT_TREE is the format parameter. ARG_NUM - is the number of the format argument. CTX points to a - format_check_context. */ - -static void -check_format_arg (void *ctx, tree format_tree, - unsigned HOST_WIDE_INT arg_num) -{ - format_check_context *format_ctx = (format_check_context *) ctx; - format_check_results *res = format_ctx->res; - function_format_info *info = format_ctx->info; - tree params = format_ctx->params; - - int format_length; - HOST_WIDE_INT offset; - const char *format_chars; - tree array_size = 0; - tree array_init; - alloc_pool fwt_pool; - - if (integer_zerop (format_tree)) - { - /* Skip to first argument to check, so we can see if this format - has any arguments (it shouldn't). */ - while (arg_num + 1 < info->first_arg_num) - { - if (params == 0) - return; - params = TREE_CHAIN (params); - ++arg_num; - } - - if (params == 0) - res->number_other++; - else - res->number_extra_args++; - - return; - } - - offset = 0; - if (TREE_CODE (format_tree) == POINTER_PLUS_EXPR) - { - tree arg0, arg1; - - arg0 = TREE_OPERAND (format_tree, 0); - arg1 = TREE_OPERAND (format_tree, 1); - STRIP_NOPS (arg0); - STRIP_NOPS (arg1); - if (TREE_CODE (arg1) == INTEGER_CST) - format_tree = arg0; - else - { - res->number_non_literal++; - return; - } - if (!host_integerp (arg1, 0) - || (offset = tree_low_cst (arg1, 0)) < 0) - { - res->number_non_literal++; - return; - } - } - if (TREE_CODE (format_tree) != ADDR_EXPR) - { - res->number_non_literal++; - return; - } - format_tree = TREE_OPERAND (format_tree, 0); - if (TREE_CODE (format_tree) == ARRAY_REF - && host_integerp (TREE_OPERAND (format_tree, 1), 0) - && (offset += tree_low_cst (TREE_OPERAND (format_tree, 1), 0)) >= 0) - format_tree = TREE_OPERAND (format_tree, 0); - if (TREE_CODE (format_tree) == VAR_DECL - && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE - && (array_init = decl_constant_value (format_tree)) != format_tree - && TREE_CODE (array_init) == STRING_CST) - { - /* Extract the string constant initializer. Note that this may include - a trailing NUL character that is not in the array (e.g. - const char a[3] = "foo";). */ - array_size = DECL_SIZE_UNIT (format_tree); - format_tree = array_init; - } - if (TREE_CODE (format_tree) != STRING_CST) - { - res->number_non_literal++; - return; - } - if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree))) != char_type_node) - { - res->number_wide++; - return; - } - format_chars = TREE_STRING_POINTER (format_tree); - format_length = TREE_STRING_LENGTH (format_tree); - if (array_size != 0) - { - /* Variable length arrays can't be initialized. */ - gcc_assert (TREE_CODE (array_size) == INTEGER_CST); - - if (host_integerp (array_size, 0)) - { - HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size); - if (array_size_value > 0 - && array_size_value == (int) array_size_value - && format_length > array_size_value) - format_length = array_size_value; - } - } - if (offset) - { - if (offset >= format_length) - { - res->number_non_literal++; - return; - } - format_chars += offset; - format_length -= offset; - } - if (format_length < 1 || format_chars[--format_length] != 0) - { - res->number_unterminated++; - return; - } - if (format_length == 0) - { - res->number_empty++; - return; - } - - /* Skip to first argument to check. */ - while (arg_num + 1 < info->first_arg_num) - { - if (params == 0) - return; - params = TREE_CHAIN (params); - ++arg_num; - } - /* Provisionally increment res->number_other; check_format_info_main - will decrement it if it finds there are extra arguments, but this way - need not adjust it for every return. */ - res->number_other++; - fwt_pool = create_alloc_pool ("format_wanted_type pool", - sizeof (format_wanted_type), 10); - check_format_info_main (res, info, format_chars, format_length, - params, arg_num, fwt_pool); - free_alloc_pool (fwt_pool); -} - - -/* Do the main part of checking a call to a format function. FORMAT_CHARS - is the NUL-terminated format string (which at this point may contain - internal NUL characters); FORMAT_LENGTH is its length (excluding the - terminating NUL character). ARG_NUM is one less than the number of - the first format argument to check; PARAMS points to that format - argument in the list of arguments. */ - -static void -check_format_info_main (format_check_results *res, - function_format_info *info, const char *format_chars, - int format_length, tree params, - unsigned HOST_WIDE_INT arg_num, alloc_pool fwt_pool) -{ - const char *orig_format_chars = format_chars; - tree first_fillin_param = params; - - const format_kind_info *fki = &format_types[info->format_type]; - const format_flag_spec *flag_specs = fki->flag_specs; - const format_flag_pair *bad_flag_pairs = fki->bad_flag_pairs; - - /* -1 if no conversions taking an operand have been found; 0 if one has - and it didn't use $; 1 if $ formats are in use. */ - int has_operand_number = -1; - - init_dollar_format_checking (info->first_arg_num, first_fillin_param); - - while (1) - { - int i; - int suppressed = FALSE; - const char *length_chars = NULL; - enum format_lengths length_chars_val = FMT_LEN_none; - enum format_std_version length_chars_std = STD_C89; - int format_char; - tree cur_param; - tree wanted_type; - int main_arg_num = 0; - tree main_arg_params = 0; - enum format_std_version wanted_type_std; - const char *wanted_type_name; - format_wanted_type width_wanted_type; - format_wanted_type precision_wanted_type; - format_wanted_type main_wanted_type; - format_wanted_type *first_wanted_type = NULL; - format_wanted_type *last_wanted_type = NULL; - const format_length_info *fli = NULL; - const format_char_info *fci = NULL; - char flag_chars[256]; - int alloc_flag = 0; - int scalar_identity_flag = 0; - const char *format_start = format_chars; - if (*format_chars == 0) - { - if (format_chars - orig_format_chars != format_length) - warning (OPT_Wformat_contains_nul, "embedded %<\\0%> in format"); - if (info->first_arg_num != 0 && params != 0 - && has_operand_number <= 0) - { - res->number_other--; - res->number_extra_args++; - } - if (has_operand_number > 0) - finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK); - return; - } - if (*format_chars++ != '%') - continue; - if (*format_chars == 0) - { - warning (OPT_Wformat, "spurious trailing %<%%%> in format"); - continue; - } - if (*format_chars == '%') - { - ++format_chars; - continue; - } - flag_chars[0] = 0; - - if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0) - { - /* Possibly read a $ operand number at the start of the format. - If one was previously used, one is required here. If one - is not used here, we can't immediately conclude this is a - format without them, since it could be printf %m or scanf %*. */ - int opnum; - opnum = maybe_read_dollar_number (&format_chars, 0, - first_fillin_param, - &main_arg_params, fki); - if (opnum == -1) - return; - else if (opnum > 0) - { - has_operand_number = 1; - main_arg_num = opnum + info->first_arg_num - 1; - } - } - else if (fki->flags & FMT_FLAG_USE_DOLLAR) - { - if (avoid_dollar_number (format_chars)) - return; - } - - /* Read any format flags, but do not yet validate them beyond removing - duplicates, since in general validation depends on the rest of - the format. */ - while (*format_chars != 0 - && strchr (fki->flag_chars, *format_chars) != 0) - { - const format_flag_spec *s = get_flag_spec (flag_specs, - *format_chars, NULL); - if (strchr (flag_chars, *format_chars) != 0) - { - warning (OPT_Wformat, "repeated %s in format", _(s->name)); - } - else - { - i = strlen (flag_chars); - flag_chars[i++] = *format_chars; - flag_chars[i] = 0; - } - if (s->skip_next_char) - { - ++format_chars; - if (*format_chars == 0) - { - warning (OPT_Wformat, "missing fill character at end of strfmon format"); - return; - } - } - ++format_chars; - } - - /* Read any format width, possibly * or *m$. */ - if (fki->width_char != 0) - { - if (fki->width_type != NULL && *format_chars == '*') - { - i = strlen (flag_chars); - flag_chars[i++] = fki->width_char; - flag_chars[i] = 0; - /* "...a field width...may be indicated by an asterisk. - In this case, an int argument supplies the field width..." */ - ++format_chars; - if (has_operand_number != 0) - { - int opnum; - opnum = maybe_read_dollar_number (&format_chars, - has_operand_number == 1, - first_fillin_param, - ¶ms, fki); - if (opnum == -1) - return; - else if (opnum > 0) - { - has_operand_number = 1; - arg_num = opnum + info->first_arg_num - 1; - } - else - has_operand_number = 0; - } - else - { - if (avoid_dollar_number (format_chars)) - return; - } - if (info->first_arg_num != 0) - { - if (params == 0) - { - warning (OPT_Wformat, "too few arguments for format"); - return; - } - cur_param = TREE_VALUE (params); - if (has_operand_number <= 0) - { - params = TREE_CHAIN (params); - ++arg_num; - } - width_wanted_type.wanted_type = *fki->width_type; - width_wanted_type.wanted_type_name = NULL; - width_wanted_type.pointer_count = 0; - width_wanted_type.char_lenient_flag = 0; - width_wanted_type.scalar_identity_flag = 0; - width_wanted_type.writing_in_flag = 0; - width_wanted_type.reading_from_flag = 0; - width_wanted_type.name = _("field width"); - width_wanted_type.param = cur_param; - width_wanted_type.arg_num = arg_num; - width_wanted_type.next = NULL; - if (last_wanted_type != 0) - last_wanted_type->next = &width_wanted_type; - if (first_wanted_type == 0) - first_wanted_type = &width_wanted_type; - last_wanted_type = &width_wanted_type; - } - } - else - { - /* Possibly read a numeric width. If the width is zero, - we complain if appropriate. */ - int non_zero_width_char = FALSE; - int found_width = FALSE; - while (ISDIGIT (*format_chars)) - { - found_width = TRUE; - if (*format_chars != '0') - non_zero_width_char = TRUE; - ++format_chars; - } - if (found_width && !non_zero_width_char && - (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD)) - warning (OPT_Wformat, "zero width in %s format", fki->name); - if (found_width) - { - i = strlen (flag_chars); - flag_chars[i++] = fki->width_char; - flag_chars[i] = 0; - } - } - } - - /* Read any format left precision (must be a number, not *). */ - if (fki->left_precision_char != 0 && *format_chars == '#') - { - ++format_chars; - i = strlen (flag_chars); - flag_chars[i++] = fki->left_precision_char; - flag_chars[i] = 0; - if (!ISDIGIT (*format_chars)) - warning (OPT_Wformat, "empty left precision in %s format", fki->name); - while (ISDIGIT (*format_chars)) - ++format_chars; - } - - /* Read any format precision, possibly * or *m$. */ - if (fki->precision_char != 0 && *format_chars == '.') - { - ++format_chars; - i = strlen (flag_chars); - flag_chars[i++] = fki->precision_char; - flag_chars[i] = 0; - if (fki->precision_type != NULL && *format_chars == '*') - { - /* "...a...precision...may be indicated by an asterisk. - In this case, an int argument supplies the...precision." */ - ++format_chars; - if (has_operand_number != 0) - { - int opnum; - opnum = maybe_read_dollar_number (&format_chars, - has_operand_number == 1, - first_fillin_param, - ¶ms, fki); - if (opnum == -1) - return; - else if (opnum > 0) - { - has_operand_number = 1; - arg_num = opnum + info->first_arg_num - 1; - } - else - has_operand_number = 0; - } - else - { - if (avoid_dollar_number (format_chars)) - return; - } - if (info->first_arg_num != 0) - { - if (params == 0) - { - warning (OPT_Wformat, "too few arguments for format"); - return; - } - cur_param = TREE_VALUE (params); - if (has_operand_number <= 0) - { - params = TREE_CHAIN (params); - ++arg_num; - } - precision_wanted_type.wanted_type = *fki->precision_type; - precision_wanted_type.wanted_type_name = NULL; - precision_wanted_type.pointer_count = 0; - precision_wanted_type.char_lenient_flag = 0; - precision_wanted_type.scalar_identity_flag = 0; - precision_wanted_type.writing_in_flag = 0; - precision_wanted_type.reading_from_flag = 0; - precision_wanted_type.name = _("field precision"); - precision_wanted_type.param = cur_param; - precision_wanted_type.arg_num = arg_num; - precision_wanted_type.next = NULL; - if (last_wanted_type != 0) - last_wanted_type->next = &precision_wanted_type; - if (first_wanted_type == 0) - first_wanted_type = &precision_wanted_type; - last_wanted_type = &precision_wanted_type; - } - } - else - { - if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK) - && !ISDIGIT (*format_chars)) - warning (OPT_Wformat, "empty precision in %s format", fki->name); - while (ISDIGIT (*format_chars)) - ++format_chars; - } - } - - if (fki->alloc_char && fki->alloc_char == *format_chars) - { - i = strlen (flag_chars); - flag_chars[i++] = fki->alloc_char; - flag_chars[i] = 0; - format_chars++; - } - - /* Handle the scanf allocation kludge. */ - if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) - { - if (*format_chars == 'a' && !flag_isoc99) - { - if (format_chars[1] == 's' || format_chars[1] == 'S' - || format_chars[1] == '[') - { - /* 'a' is used as a flag. */ - i = strlen (flag_chars); - flag_chars[i++] = 'a'; - flag_chars[i] = 0; - format_chars++; - } - } - } - - /* Read any length modifier, if this kind of format has them. */ - fli = fki->length_char_specs; - length_chars = NULL; - length_chars_val = FMT_LEN_none; - length_chars_std = STD_C89; - scalar_identity_flag = 0; - if (fli) - { - while (fli->name != 0 - && strncmp (fli->name, format_chars, strlen (fli->name))) - fli++; - if (fli->name != 0) - { - format_chars += strlen (fli->name); - if (fli->double_name != 0 && fli->name[0] == *format_chars) - { - format_chars++; - length_chars = fli->double_name; - length_chars_val = fli->double_index; - length_chars_std = fli->double_std; - } - else - { - length_chars = fli->name; - length_chars_val = fli->index; - length_chars_std = fli->std; - scalar_identity_flag = fli->scalar_identity_flag; - } - i = strlen (flag_chars); - flag_chars[i++] = fki->length_code_char; - flag_chars[i] = 0; - } - if (pedantic) - { - /* Warn if the length modifier is non-standard. */ - if (ADJ_STD (length_chars_std) > C_STD_VER) - warning (OPT_Wformat, - "%s does not support the %qs %s length modifier", - C_STD_NAME (length_chars_std), length_chars, - fki->name); - } - } - - /* Read any modifier (strftime E/O). */ - if (fki->modifier_chars != NULL) - { - while (*format_chars != 0 - && strchr (fki->modifier_chars, *format_chars) != 0) - { - if (strchr (flag_chars, *format_chars) != 0) - { - const format_flag_spec *s = get_flag_spec (flag_specs, - *format_chars, NULL); - warning (OPT_Wformat, "repeated %s in format", _(s->name)); - } - else - { - i = strlen (flag_chars); - flag_chars[i++] = *format_chars; - flag_chars[i] = 0; - } - ++format_chars; - } - } - - format_char = *format_chars; - if (format_char == 0 - || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK) - && format_char == '%')) - { - warning (OPT_Wformat, "conversion lacks type at end of format"); - continue; - } - format_chars++; - fci = fki->conversion_specs; - while (fci->format_chars != 0 - && strchr (fci->format_chars, format_char) == 0) - ++fci; - if (fci->format_chars == 0) - { - if (ISGRAPH (format_char)) - warning (OPT_Wformat, "unknown conversion type character %qc in format", - format_char); - else - warning (OPT_Wformat, "unknown conversion type character 0x%x in format", - format_char); - continue; - } - if (pedantic) - { - if (ADJ_STD (fci->std) > C_STD_VER) - warning (OPT_Wformat, "%s does not support the %<%%%c%> %s format", - C_STD_NAME (fci->std), format_char, fki->name); - } - - /* Validate the individual flags used, removing any that are invalid. */ - { - int d = 0; - for (i = 0; flag_chars[i] != 0; i++) - { - const format_flag_spec *s = get_flag_spec (flag_specs, - flag_chars[i], NULL); - flag_chars[i - d] = flag_chars[i]; - if (flag_chars[i] == fki->length_code_char) - continue; - if (strchr (fci->flag_chars, flag_chars[i]) == 0) - { - warning (OPT_Wformat, "%s used with %<%%%c%> %s format", - _(s->name), format_char, fki->name); - d++; - continue; - } - if (pedantic) - { - const format_flag_spec *t; - if (ADJ_STD (s->std) > C_STD_VER) - warning (OPT_Wformat, "%s does not support %s", - C_STD_NAME (s->std), _(s->long_name)); - t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2); - if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std)) - { - const char *long_name = (t->long_name != NULL - ? t->long_name - : s->long_name); - if (ADJ_STD (t->std) > C_STD_VER) - warning (OPT_Wformat, - "%s does not support %s with the %<%%%c%> %s format", - C_STD_NAME (t->std), _(long_name), - format_char, fki->name); - } - } - } - flag_chars[i - d] = 0; - } - - if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) - && strchr (flag_chars, 'a') != 0) - alloc_flag = 1; - if (fki->alloc_char && strchr (flag_chars, fki->alloc_char) != 0) - alloc_flag = 1; - - if (fki->suppression_char - && strchr (flag_chars, fki->suppression_char) != 0) - suppressed = 1; - - /* Validate the pairs of flags used. */ - for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++) - { - const format_flag_spec *s, *t; - if (strchr (flag_chars, bad_flag_pairs[i].flag_char1) == 0) - continue; - if (strchr (flag_chars, bad_flag_pairs[i].flag_char2) == 0) - continue; - if (bad_flag_pairs[i].predicate != 0 - && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0) - continue; - s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL); - t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL); - if (bad_flag_pairs[i].ignored) - { - if (bad_flag_pairs[i].predicate != 0) - warning (OPT_Wformat, - "%s ignored with %s and %<%%%c%> %s format", - _(s->name), _(t->name), format_char, - fki->name); - else - warning (OPT_Wformat, "%s ignored with %s in %s format", - _(s->name), _(t->name), fki->name); - } - else - { - if (bad_flag_pairs[i].predicate != 0) - warning (OPT_Wformat, - "use of %s and %s together with %<%%%c%> %s format", - _(s->name), _(t->name), format_char, - fki->name); - else - warning (OPT_Wformat, "use of %s and %s together in %s format", - _(s->name), _(t->name), fki->name); - } - } - - /* Give Y2K warnings. */ - if (warn_format_y2k) - { - int y2k_level = 0; - if (strchr (fci->flags2, '4') != 0) - if (strchr (flag_chars, 'E') != 0) - y2k_level = 3; - else - y2k_level = 2; - else if (strchr (fci->flags2, '3') != 0) - y2k_level = 3; - else if (strchr (fci->flags2, '2') != 0) - y2k_level = 2; - if (y2k_level == 3) - warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of " - "year in some locales", format_char); - else if (y2k_level == 2) - warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of " - "year", format_char); - } - - if (strchr (fci->flags2, '[') != 0) - { - /* Skip over scan set, in case it happens to have '%' in it. */ - if (*format_chars == '^') - ++format_chars; - /* Find closing bracket; if one is hit immediately, then - it's part of the scan set rather than a terminator. */ - if (*format_chars == ']') - ++format_chars; - while (*format_chars && *format_chars != ']') - ++format_chars; - if (*format_chars != ']') - /* The end of the format string was reached. */ - warning (OPT_Wformat, "no closing %<]%> for %<%%[%> format"); - } - - wanted_type = 0; - wanted_type_name = 0; - if (fki->flags & (int) FMT_FLAG_ARG_CONVERT) - { - wanted_type = (fci->types[length_chars_val].type - ? *fci->types[length_chars_val].type : 0); - wanted_type_name = fci->types[length_chars_val].name; - wanted_type_std = fci->types[length_chars_val].std; - if (wanted_type == 0) - { - warning (OPT_Wformat, - "use of %qs length modifier with %qc type character", - length_chars, format_char); - /* Heuristic: skip one argument when an invalid length/type - combination is encountered. */ - arg_num++; - if (params == 0) - { - warning (OPT_Wformat, "too few arguments for format"); - return; - } - params = TREE_CHAIN (params); - continue; - } - else if (pedantic - /* Warn if non-standard, provided it is more non-standard - than the length and type characters that may already - have been warned for. */ - && ADJ_STD (wanted_type_std) > ADJ_STD (length_chars_std) - && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std)) - { - if (ADJ_STD (wanted_type_std) > C_STD_VER) - warning (OPT_Wformat, - "%s does not support the %<%%%s%c%> %s format", - C_STD_NAME (wanted_type_std), length_chars, - format_char, fki->name); - } - } - - main_wanted_type.next = NULL; - - /* Finally. . .check type of argument against desired type! */ - if (info->first_arg_num == 0) - continue; - if ((fci->pointer_count == 0 && wanted_type == void_type_node) - || suppressed) - { - if (main_arg_num != 0) - { - if (suppressed) - warning (OPT_Wformat, "operand number specified with " - "suppressed assignment"); - else - warning (OPT_Wformat, "operand number specified for format " - "taking no argument"); - } - } - else - { - format_wanted_type *wanted_type_ptr; - - if (main_arg_num != 0) - { - arg_num = main_arg_num; - params = main_arg_params; - } - else - { - ++arg_num; - if (has_operand_number > 0) - { - warning (OPT_Wformat, "missing $ operand number in format"); - return; - } - else - has_operand_number = 0; - } - - wanted_type_ptr = &main_wanted_type; - while (fci) - { - if (params == 0) - { - warning (OPT_Wformat, "too few arguments for format"); - return; - } - - cur_param = TREE_VALUE (params); - params = TREE_CHAIN (params); - - wanted_type_ptr->wanted_type = wanted_type; - wanted_type_ptr->wanted_type_name = wanted_type_name; - wanted_type_ptr->pointer_count = fci->pointer_count + alloc_flag; - wanted_type_ptr->char_lenient_flag = 0; - if (strchr (fci->flags2, 'c') != 0) - wanted_type_ptr->char_lenient_flag = 1; - wanted_type_ptr->scalar_identity_flag = 0; - if (scalar_identity_flag) - wanted_type_ptr->scalar_identity_flag = 1; - wanted_type_ptr->writing_in_flag = 0; - wanted_type_ptr->reading_from_flag = 0; - if (alloc_flag) - wanted_type_ptr->writing_in_flag = 1; - else - { - if (strchr (fci->flags2, 'W') != 0) - wanted_type_ptr->writing_in_flag = 1; - if (strchr (fci->flags2, 'R') != 0) - wanted_type_ptr->reading_from_flag = 1; - } - wanted_type_ptr->name = NULL; - wanted_type_ptr->param = cur_param; - wanted_type_ptr->arg_num = arg_num; - wanted_type_ptr->next = NULL; - if (last_wanted_type != 0) - last_wanted_type->next = wanted_type_ptr; - if (first_wanted_type == 0) - first_wanted_type = wanted_type_ptr; - last_wanted_type = wanted_type_ptr; - - fci = fci->chain; - if (fci) - { - wanted_type_ptr = (format_wanted_type *) - pool_alloc (fwt_pool); - arg_num++; - wanted_type = *fci->types[length_chars_val].type; - wanted_type_name = fci->types[length_chars_val].name; - } - } - } - - if (first_wanted_type != 0) - check_format_types (first_wanted_type, format_start, - format_chars - format_start); - } -} - - -/* Check the argument types from a single format conversion (possibly - including width and precision arguments). */ -static void -check_format_types (format_wanted_type *types, const char *format_start, - int format_length) -{ - for (; types != 0; types = types->next) - { - tree cur_param; - tree cur_type; - tree orig_cur_type; - tree wanted_type; - int arg_num; - int i; - int char_type_flag; - cur_param = types->param; - cur_type = TREE_TYPE (cur_param); - if (cur_type == error_mark_node) - continue; - orig_cur_type = cur_type; - char_type_flag = 0; - wanted_type = types->wanted_type; - arg_num = types->arg_num; - - /* The following should not occur here. */ - gcc_assert (wanted_type); - gcc_assert (wanted_type != void_type_node || types->pointer_count); - - if (types->pointer_count == 0) - wanted_type = lang_hooks.types.type_promotes_to (wanted_type); - - wanted_type = TYPE_MAIN_VARIANT (wanted_type); - - STRIP_NOPS (cur_param); - - /* Check the types of any additional pointer arguments - that precede the "real" argument. */ - for (i = 0; i < types->pointer_count; ++i) - { - if (TREE_CODE (cur_type) == POINTER_TYPE) - { - cur_type = TREE_TYPE (cur_type); - if (cur_type == error_mark_node) - break; - - /* Check for writing through a NULL pointer. */ - if (types->writing_in_flag - && i == 0 - && cur_param != 0 - && integer_zerop (cur_param)) - warning (OPT_Wformat, "writing through null pointer " - "(argument %d)", arg_num); - - /* Check for reading through a NULL pointer. */ - if (types->reading_from_flag - && i == 0 - && cur_param != 0 - && integer_zerop (cur_param)) - warning (OPT_Wformat, "reading through null pointer " - "(argument %d)", arg_num); - - if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR) - cur_param = TREE_OPERAND (cur_param, 0); - else - cur_param = 0; - - /* See if this is an attempt to write into a const type with - scanf or with printf "%n". Note: the writing in happens - at the first indirection only, if for example - void * const * is passed to scanf %p; passing - const void ** is simply passing an incompatible type. */ - if (types->writing_in_flag - && i == 0 - && (TYPE_READONLY (cur_type) - || (cur_param != 0 - && (CONSTANT_CLASS_P (cur_param) - || (DECL_P (cur_param) - && TREE_READONLY (cur_param)))))) - warning (OPT_Wformat, "writing into constant object " - "(argument %d)", arg_num); - - /* If there are extra type qualifiers beyond the first - indirection, then this makes the types technically - incompatible. */ - if (i > 0 - && pedantic - && (TYPE_READONLY (cur_type) - || TYPE_VOLATILE (cur_type) - || TYPE_RESTRICT (cur_type))) - warning (OPT_Wformat, "extra type qualifiers in format " - "argument (argument %d)", - arg_num); - - } - else - { - format_type_warning (types->name, format_start, format_length, - wanted_type, types->pointer_count, - types->wanted_type_name, orig_cur_type, - arg_num); - break; - } - } - - if (i < types->pointer_count) - continue; - - cur_type = TYPE_MAIN_VARIANT (cur_type); - - /* Check whether the argument type is a character type. This leniency - only applies to certain formats, flagged with 'c'. - */ - if (types->char_lenient_flag) - char_type_flag = (cur_type == char_type_node - || cur_type == signed_char_type_node - || cur_type == unsigned_char_type_node); - - /* Check the type of the "real" argument, if there's a type we want. */ - if (lang_hooks.types_compatible_p (wanted_type, cur_type)) - continue; - /* If we want 'void *', allow any pointer type. - (Anything else would already have got a warning.) - With -pedantic, only allow pointers to void and to character - types. */ - if (wanted_type == void_type_node - && (!pedantic || (i == 1 && char_type_flag))) - continue; - /* Don't warn about differences merely in signedness, unless - -pedantic. With -pedantic, warn if the type is a pointer - target and not a character type, and for character types at - a second level of indirection. */ - if (TREE_CODE (wanted_type) == INTEGER_TYPE - && TREE_CODE (cur_type) == INTEGER_TYPE - && (!pedantic || i == 0 || (i == 1 && char_type_flag)) - && (TYPE_UNSIGNED (wanted_type) - ? wanted_type == c_common_unsigned_type (cur_type) - : wanted_type == c_common_signed_type (cur_type))) - continue; - /* Likewise, "signed char", "unsigned char" and "char" are - equivalent but the above test won't consider them equivalent. */ - if (wanted_type == char_type_node - && (!pedantic || i < 2) - && char_type_flag) - continue; - if (types->scalar_identity_flag - && (TREE_CODE (cur_type) == TREE_CODE (wanted_type) - || (INTEGRAL_TYPE_P (cur_type) - && INTEGRAL_TYPE_P (wanted_type))) - && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type)) - continue; - /* Now we have a type mismatch. */ - format_type_warning (types->name, format_start, format_length, - wanted_type, types->pointer_count, - types->wanted_type_name, orig_cur_type, arg_num); - } -} - - -/* Give a warning about a format argument of different type from that - expected. DESCR is a description such as "field precision", or - NULL for an ordinary format. For an ordinary format, FORMAT_START - points to where the format starts in the format string and - FORMAT_LENGTH is its length. WANTED_TYPE is the type the argument - should have after POINTER_COUNT pointer dereferences. - WANTED_NAME_NAME is a possibly more friendly name of WANTED_TYPE, - or NULL if the ordinary name of the type should be used. ARG_TYPE - is the type of the actual argument. ARG_NUM is the number of that - argument. */ -static void -format_type_warning (const char *descr, const char *format_start, - int format_length, tree wanted_type, int pointer_count, - const char *wanted_type_name, tree arg_type, int arg_num) -{ - char *p; - /* If ARG_TYPE is a typedef with a misleading name (for example, - size_t but not the standard size_t expected by printf %zu), avoid - printing the typedef name. */ - if (wanted_type_name - && TYPE_NAME (arg_type) - && TREE_CODE (TYPE_NAME (arg_type)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (arg_type)) - && !strcmp (wanted_type_name, - lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2))) - arg_type = TYPE_MAIN_VARIANT (arg_type); - /* The format type and name exclude any '*' for pointers, so those - must be formatted manually. For all the types we currently have, - this is adequate, but formats taking pointers to functions or - arrays would require the full type to be built up in order to - print it with %T. */ - p = (char *) alloca (pointer_count + 2); - if (pointer_count == 0) - p[0] = 0; - else if (c_dialect_cxx ()) - { - memset (p, '*', pointer_count); - p[pointer_count] = 0; - } - else - { - p[0] = ' '; - memset (p + 1, '*', pointer_count); - p[pointer_count + 1] = 0; - } - if (wanted_type_name) - { - if (descr) - warning (OPT_Wformat, "%s should have type %<%s%s%>, " - "but argument %d has type %qT", - descr, wanted_type_name, p, arg_num, arg_type); - else - warning (OPT_Wformat, "format %q.*s expects type %<%s%s%>, " - "but argument %d has type %qT", - format_length, format_start, wanted_type_name, p, - arg_num, arg_type); - } - else - { - if (descr) - warning (OPT_Wformat, "%s should have type %<%T%s%>, " - "but argument %d has type %qT", - descr, wanted_type, p, arg_num, arg_type); - else - warning (OPT_Wformat, "format %q.*s expects type %<%T%s%>, " - "but argument %d has type %qT", - format_length, format_start, wanted_type, p, arg_num, arg_type); - } -} - - -/* Given a format_char_info array FCI, and a character C, this function - returns the index into the conversion_specs where that specifier's - data is located. The character must exist. */ -static unsigned int -find_char_info_specifier_index (const format_char_info *fci, int c) -{ - unsigned i; - - for (i = 0; fci->format_chars; i++, fci++) - if (strchr (fci->format_chars, c)) - return i; - - /* We shouldn't be looking for a non-existent specifier. */ - gcc_unreachable (); -} - -/* Given a format_length_info array FLI, and a character C, this - function returns the index into the conversion_specs where that - modifier's data is located. The character must exist. */ -static unsigned int -find_length_info_modifier_index (const format_length_info *fli, int c) -{ - unsigned i; - - for (i = 0; fli->name; i++, fli++) - if (strchr (fli->name, c)) - return i; - - /* We shouldn't be looking for a non-existent modifier. */ - gcc_unreachable (); -} - -/* Determine the type of HOST_WIDE_INT in the code being compiled for - use in GCC's __asm_fprintf__ custom format attribute. You must - have set dynamic_format_types before calling this function. */ -static void -init_dynamic_asm_fprintf_info (void) -{ - static tree hwi; - - if (!hwi) - { - format_length_info *new_asm_fprintf_length_specs; - unsigned int i; - - /* Find the underlying type for HOST_WIDE_INT. For the %w - length modifier to work, one must have issued: "typedef - HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code - prior to using that modifier. */ - hwi = maybe_get_identifier ("__gcc_host_wide_int__"); - if (!hwi) - { - error ("%<__gcc_host_wide_int__%> is not defined as a type"); - return; - } - hwi = identifier_global_value (hwi); - if (!hwi || TREE_CODE (hwi) != TYPE_DECL) - { - error ("%<__gcc_host_wide_int__%> is not defined as a type"); - return; - } - hwi = DECL_ORIGINAL_TYPE (hwi); - gcc_assert (hwi); - if (hwi != long_integer_type_node && hwi != long_long_integer_type_node) - { - error ("%<__gcc_host_wide_int__%> is not defined as %" - " or %"); - return; - } - - /* Create a new (writable) copy of asm_fprintf_length_specs. */ - new_asm_fprintf_length_specs = (format_length_info *) - xmemdup (asm_fprintf_length_specs, - sizeof (asm_fprintf_length_specs), - sizeof (asm_fprintf_length_specs)); - - /* HOST_WIDE_INT must be one of 'long' or 'long long'. */ - i = find_length_info_modifier_index (new_asm_fprintf_length_specs, 'w'); - if (hwi == long_integer_type_node) - new_asm_fprintf_length_specs[i].index = FMT_LEN_l; - else if (hwi == long_long_integer_type_node) - new_asm_fprintf_length_specs[i].index = FMT_LEN_ll; - else - gcc_unreachable (); - - /* Assign the new data for use. */ - dynamic_format_types[asm_fprintf_format_type].length_char_specs = - new_asm_fprintf_length_specs; - } -} - -/* Determine the type of a "locus" in the code being compiled for use - in GCC's __gcc_gfc__ custom format attribute. You must have set - dynamic_format_types before calling this function. */ -static void -init_dynamic_gfc_info (void) -{ - static tree locus; - - if (!locus) - { - static format_char_info *gfc_fci; - - /* For the GCC __gcc_gfc__ custom format specifier to work, one - must have declared 'locus' prior to using this attribute. If - we haven't seen this declarations then you shouldn't use the - specifier requiring that type. */ - if ((locus = maybe_get_identifier ("locus"))) - { - locus = identifier_global_value (locus); - if (locus) - { - if (TREE_CODE (locus) != TYPE_DECL - || TREE_TYPE (locus) == error_mark_node) - { - error ("% is not defined as a type"); - locus = 0; - } - else - locus = TREE_TYPE (locus); - } - } - - /* Assign the new data for use. */ - - /* Handle the __gcc_gfc__ format specifics. */ - if (!gfc_fci) - dynamic_format_types[gcc_gfc_format_type].conversion_specs = - gfc_fci = (format_char_info *) - xmemdup (gcc_gfc_char_table, - sizeof (gcc_gfc_char_table), - sizeof (gcc_gfc_char_table)); - if (locus) - { - const unsigned i = find_char_info_specifier_index (gfc_fci, 'L'); - gfc_fci[i].types[0].type = &locus; - gfc_fci[i].pointer_count = 1; - } - } -} - -/* Determine the types of "tree" and "location_t" in the code being - compiled for use in GCC's diagnostic custom format attributes. You - must have set dynamic_format_types before calling this function. */ -static void -init_dynamic_diag_info (void) -{ - static tree t, loc, hwi; - - if (!loc || !t || !hwi) - { - static format_char_info *diag_fci, *tdiag_fci, *cdiag_fci, *cxxdiag_fci; - static format_length_info *diag_ls; - unsigned int i; - - /* For the GCC-diagnostics custom format specifiers to work, one - must have declared 'tree' and/or 'location_t' prior to using - those attributes. If we haven't seen these declarations then - you shouldn't use the specifiers requiring these types. - However we don't force a hard ICE because we may see only one - or the other type. */ - if ((loc = maybe_get_identifier ("location_t"))) - { - loc = identifier_global_value (loc); - if (loc) - { - if (TREE_CODE (loc) != TYPE_DECL) - { - error ("% is not defined as a type"); - loc = 0; - } - else - loc = TREE_TYPE (loc); - } - } - - /* We need to grab the underlying 'union tree_node' so peek into - an extra type level. */ - if ((t = maybe_get_identifier ("tree"))) - { - t = identifier_global_value (t); - if (t) - { - if (TREE_CODE (t) != TYPE_DECL) - { - error ("% is not defined as a type"); - t = 0; - } - else if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) - { - error ("% is not defined as a pointer type"); - t = 0; - } - else - t = TREE_TYPE (TREE_TYPE (t)); - } - } - - /* Find the underlying type for HOST_WIDE_INT. For the %w - length modifier to work, one must have issued: "typedef - HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code - prior to using that modifier. */ - if ((hwi = maybe_get_identifier ("__gcc_host_wide_int__"))) - { - hwi = identifier_global_value (hwi); - if (hwi) - { - if (TREE_CODE (hwi) != TYPE_DECL) - { - error ("%<__gcc_host_wide_int__%> is not defined as a type"); - hwi = 0; - } - else - { - hwi = DECL_ORIGINAL_TYPE (hwi); - gcc_assert (hwi); - if (hwi != long_integer_type_node - && hwi != long_long_integer_type_node) - { - error ("%<__gcc_host_wide_int__%> is not defined" - " as % or %"); - hwi = 0; - } - } - } - } - - /* Assign the new data for use. */ - - /* All the GCC diag formats use the same length specs. */ - if (!diag_ls) - dynamic_format_types[gcc_diag_format_type].length_char_specs = - dynamic_format_types[gcc_tdiag_format_type].length_char_specs = - dynamic_format_types[gcc_cdiag_format_type].length_char_specs = - dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs = - diag_ls = (format_length_info *) - xmemdup (gcc_diag_length_specs, - sizeof (gcc_diag_length_specs), - sizeof (gcc_diag_length_specs)); - if (hwi) - { - /* HOST_WIDE_INT must be one of 'long' or 'long long'. */ - i = find_length_info_modifier_index (diag_ls, 'w'); - if (hwi == long_integer_type_node) - diag_ls[i].index = FMT_LEN_l; - else if (hwi == long_long_integer_type_node) - diag_ls[i].index = FMT_LEN_ll; - else - gcc_unreachable (); - } - - /* Handle the __gcc_diag__ format specifics. */ - if (!diag_fci) - dynamic_format_types[gcc_diag_format_type].conversion_specs = - diag_fci = (format_char_info *) - xmemdup (gcc_diag_char_table, - sizeof (gcc_diag_char_table), - sizeof (gcc_diag_char_table)); - if (t) - { - i = find_char_info_specifier_index (diag_fci, 'K'); - diag_fci[i].types[0].type = &t; - diag_fci[i].pointer_count = 1; - } - - /* Handle the __gcc_tdiag__ format specifics. */ - if (!tdiag_fci) - dynamic_format_types[gcc_tdiag_format_type].conversion_specs = - tdiag_fci = (format_char_info *) - xmemdup (gcc_tdiag_char_table, - sizeof (gcc_tdiag_char_table), - sizeof (gcc_tdiag_char_table)); - if (t) - { - /* All specifiers taking a tree share the same struct. */ - i = find_char_info_specifier_index (tdiag_fci, 'D'); - tdiag_fci[i].types[0].type = &t; - tdiag_fci[i].pointer_count = 1; - i = find_char_info_specifier_index (tdiag_fci, 'K'); - tdiag_fci[i].types[0].type = &t; - tdiag_fci[i].pointer_count = 1; - } - - /* Handle the __gcc_cdiag__ format specifics. */ - if (!cdiag_fci) - dynamic_format_types[gcc_cdiag_format_type].conversion_specs = - cdiag_fci = (format_char_info *) - xmemdup (gcc_cdiag_char_table, - sizeof (gcc_cdiag_char_table), - sizeof (gcc_cdiag_char_table)); - if (t) - { - /* All specifiers taking a tree share the same struct. */ - i = find_char_info_specifier_index (cdiag_fci, 'D'); - cdiag_fci[i].types[0].type = &t; - cdiag_fci[i].pointer_count = 1; - i = find_char_info_specifier_index (cdiag_fci, 'K'); - cdiag_fci[i].types[0].type = &t; - cdiag_fci[i].pointer_count = 1; - } - - /* Handle the __gcc_cxxdiag__ format specifics. */ - if (!cxxdiag_fci) - dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs = - cxxdiag_fci = (format_char_info *) - xmemdup (gcc_cxxdiag_char_table, - sizeof (gcc_cxxdiag_char_table), - sizeof (gcc_cxxdiag_char_table)); - if (t) - { - /* All specifiers taking a tree share the same struct. */ - i = find_char_info_specifier_index (cxxdiag_fci, 'D'); - cxxdiag_fci[i].types[0].type = &t; - cxxdiag_fci[i].pointer_count = 1; - i = find_char_info_specifier_index (cxxdiag_fci, 'K'); - cxxdiag_fci[i].types[0].type = &t; - cxxdiag_fci[i].pointer_count = 1; - } - } -} - -#ifdef TARGET_FORMAT_TYPES -extern const format_kind_info TARGET_FORMAT_TYPES[]; -#endif - -#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES -extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[]; -#endif -#ifdef TARGET_OVERRIDES_FORMAT_INIT - extern void TARGET_OVERRIDES_FORMAT_INIT (void); -#endif - -/* Attributes such as "printf" are equivalent to those such as - "gnu_printf" unless this is overridden by a target. */ -static const target_ovr_attr gnu_target_overrides_format_attributes[] = -{ - { "gnu_printf", "printf" }, - { "gnu_scanf", "scanf" }, - { "gnu_strftime", "strftime" }, - { "gnu_strfmon", "strfmon" }, - { NULL, NULL } -}; - -/* Translate to unified attribute name. This is used in decode_format_type and - decode_format_attr. In attr_name the user specified argument is passed. It - returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES - or the attr_name passed to this function, if there is no matching entry. */ -static const char * -convert_format_name_to_system_name (const char *attr_name) -{ - int i; - - if (attr_name == NULL || *attr_name == 0 - || strncmp (attr_name, "gcc_", 4) == 0) - return attr_name; -#ifdef TARGET_OVERRIDES_FORMAT_INIT - TARGET_OVERRIDES_FORMAT_INIT (); -#endif - -#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES - /* Check if format attribute is overridden by target. */ - if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL - && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0) - { - for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i) - { - if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, - attr_name)) - return attr_name; - if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst, - attr_name)) - return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src; - } - } -#endif - /* Otherwise default to gnu format. */ - for (i = 0; - gnu_target_overrides_format_attributes[i].named_attr_src != NULL; - ++i) - { - if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src, - attr_name)) - return attr_name; - if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst, - attr_name)) - return gnu_target_overrides_format_attributes[i].named_attr_src; - } - - return attr_name; -} - -/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute, - counting "name" and "__name__" as the same, false otherwise. */ -static bool -cmp_attribs (const char *tattr_name, const char *attr_name) -{ - int alen = strlen (attr_name); - int slen = (tattr_name ? strlen (tattr_name) : 0); - if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_' - && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_') - { - attr_name += 2; - alen -= 4; - } - if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0) - return false; - return true; -} - -/* Handle a "format" attribute; arguments as in - struct attribute_spec.handler. */ -tree -handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args, - int flags, bool *no_add_attrs) -{ - tree type = *node; - function_format_info info; - tree argument; - -#ifdef TARGET_FORMAT_TYPES - /* If the target provides additional format types, we need to - add them to FORMAT_TYPES at first use. */ - if (TARGET_FORMAT_TYPES != NULL && !dynamic_format_types) - { - dynamic_format_types = XNEWVEC (format_kind_info, - n_format_types + TARGET_N_FORMAT_TYPES); - memcpy (dynamic_format_types, format_types_orig, - sizeof (format_types_orig)); - memcpy (&dynamic_format_types[n_format_types], TARGET_FORMAT_TYPES, - TARGET_N_FORMAT_TYPES * sizeof (dynamic_format_types[0])); - - format_types = dynamic_format_types; - n_format_types += TARGET_N_FORMAT_TYPES; - } -#endif - - if (!decode_format_attr (args, &info, 0)) - { - *no_add_attrs = true; - return NULL_TREE; - } - - argument = TYPE_ARG_TYPES (type); - if (argument) - { - if (!check_format_string (argument, info.format_num, flags, - no_add_attrs)) - return NULL_TREE; - - if (info.first_arg_num != 0) - { - unsigned HOST_WIDE_INT arg_num = 1; - - /* Verify that first_arg_num points to the last arg, - the ... */ - while (argument) - arg_num++, argument = TREE_CHAIN (argument); - - if (arg_num != info.first_arg_num) - { - if (!(flags & (int) ATTR_FLAG_BUILT_IN)) - error ("args to be formatted is not %<...%>"); - *no_add_attrs = true; - return NULL_TREE; - } - } - } - - /* Check if this is a strftime variant. Just for this variant - FMT_FLAG_ARG_CONVERT is not set. */ - if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0 - && info.first_arg_num != 0) - { - error ("strftime formats cannot format arguments"); - *no_add_attrs = true; - return NULL_TREE; - } - - /* If this is a custom GCC-internal format type, we have to - initialize certain bits at runtime. */ - if (info.format_type == asm_fprintf_format_type - || info.format_type == gcc_gfc_format_type - || info.format_type == gcc_diag_format_type - || info.format_type == gcc_tdiag_format_type - || info.format_type == gcc_cdiag_format_type - || info.format_type == gcc_cxxdiag_format_type) - { - /* Our first time through, we have to make sure that our - format_type data is allocated dynamically and is modifiable. */ - if (!dynamic_format_types) - format_types = dynamic_format_types = (format_kind_info *) - xmemdup (format_types_orig, sizeof (format_types_orig), - sizeof (format_types_orig)); - - /* If this is format __asm_fprintf__, we have to initialize - GCC's notion of HOST_WIDE_INT for checking %wd. */ - if (info.format_type == asm_fprintf_format_type) - init_dynamic_asm_fprintf_info (); - /* If this is format __gcc_gfc__, we have to initialize GCC's - notion of 'locus' at runtime for %L. */ - else if (info.format_type == gcc_gfc_format_type) - init_dynamic_gfc_info (); - /* If this is one of the diagnostic attributes, then we have to - initialize 'location_t' and 'tree' at runtime. */ - else if (info.format_type == gcc_diag_format_type - || info.format_type == gcc_tdiag_format_type - || info.format_type == gcc_cdiag_format_type - || info.format_type == gcc_cxxdiag_format_type) - init_dynamic_diag_info (); - else - gcc_unreachable (); - } - - return NULL_TREE; -} diff --git a/gcc/c-format.h b/gcc/c-format.h deleted file mode 100644 index 9d01f0a..0000000 --- a/gcc/c-format.h +++ /dev/null @@ -1,326 +0,0 @@ -/* Check calls to formatted I/O functions (-Wformat). - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2007, 2008 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 -. */ - -#ifndef GCC_C_FORMAT_H -#define GCC_C_FORMAT_H - -/* The meaningfully distinct length modifiers for format checking recognized - by GCC. */ -enum format_lengths -{ - FMT_LEN_none, - FMT_LEN_hh, - FMT_LEN_h, - FMT_LEN_l, - FMT_LEN_ll, - FMT_LEN_L, - FMT_LEN_z, - FMT_LEN_t, - FMT_LEN_j, - FMT_LEN_H, - FMT_LEN_D, - FMT_LEN_DD, - FMT_LEN_MAX -}; - - -/* The standard versions in which various format features appeared. */ -enum format_std_version -{ - STD_C89, - STD_C94, - STD_C9L, /* C99, but treat as C89 if -Wno-long-long. */ - STD_C99, - STD_EXT -}; - -/* Flags that may apply to a particular kind of format checked by GCC. */ -enum -{ - /* This format converts arguments of types determined by the - format string. */ - FMT_FLAG_ARG_CONVERT = 1, - /* The scanf allocation 'a' kludge applies to this format kind. */ - FMT_FLAG_SCANF_A_KLUDGE = 2, - /* A % during parsing a specifier is allowed to be a modified % rather - that indicating the format is broken and we are out-of-sync. */ - FMT_FLAG_FANCY_PERCENT_OK = 4, - /* With $ operand numbers, it is OK to reference the same argument more - than once. */ - FMT_FLAG_DOLLAR_MULTIPLE = 8, - /* This format type uses $ operand numbers (strfmon doesn't). */ - FMT_FLAG_USE_DOLLAR = 16, - /* Zero width is bad in this type of format (scanf). */ - FMT_FLAG_ZERO_WIDTH_BAD = 32, - /* Empty precision specification is OK in this type of format (printf). */ - FMT_FLAG_EMPTY_PREC_OK = 64, - /* Gaps are allowed in the arguments with $ operand numbers if all - arguments are pointers (scanf). */ - FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128 - /* Not included here: details of whether width or precision may occur - (controlled by width_char and precision_char); details of whether - '*' can be used for these (width_type and precision_type); details - of whether length modifiers can occur (length_char_specs). */ -}; - -/* Structure describing a length modifier supported in format checking, and - possibly a doubled version such as "hh". */ -typedef struct -{ - /* Name of the single-character length modifier. If prefixed by - a zero character, it describes a multi character length - modifier, like I64, I32, etc. */ - const char *name; - /* Index into a format_char_info.types array. */ - enum format_lengths index; - /* Standard version this length appears in. */ - enum format_std_version std; - /* Same, if the modifier can be repeated, or NULL if it can't. */ - const char *double_name; - enum format_lengths double_index; - enum format_std_version double_std; - - /* If this flag is set, just scalar width identity is checked, and - not the type identity itself. */ - int scalar_identity_flag; -} format_length_info; - - -/* Structure describing the combination of a conversion specifier - (or a set of specifiers which act identically) and a length modifier. */ -typedef struct -{ - /* The standard version this combination of length and type appeared in. - This is only relevant if greater than those for length and type - individually; otherwise it is ignored. */ - enum format_std_version std; - /* The name to use for the type, if different from that generated internally - (e.g., "signed size_t"). */ - const char *name; - /* The type itself. */ - tree *type; -} format_type_detail; - - -/* Macros to fill out tables of these. */ -#define NOARGUMENTS { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } -#define BADLEN { STD_C89, NULL, NULL } -#define NOLENGTHS { BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } - - -/* Structure describing a format conversion specifier (or a set of specifiers - which act identically), and the length modifiers used with it. */ -typedef struct format_char_info -{ - const char *format_chars; - int pointer_count; - enum format_std_version std; - /* Types accepted for each length modifier. */ - format_type_detail types[FMT_LEN_MAX]; - /* List of other modifier characters allowed with these specifiers. - This lists flags, and additionally "w" for width, "p" for precision - (right precision, for strfmon), "#" for left precision (strfmon), - "a" for scanf "a" allocation extension (not applicable in C99 mode), - "*" for scanf suppression, and "E" and "O" for those strftime - modifiers. */ - const char *flag_chars; - /* List of additional flags describing these conversion specifiers. - "c" for generic character pointers being allowed, "2" for strftime - two digit year formats, "3" for strftime formats giving two digit - years in some locales, "4" for "2" which becomes "3" with an "E" modifier, - "o" if use of strftime "O" is a GNU extension beyond C99, - "W" if the argument is a pointer which is dereferenced and written into, - "R" if the argument is a pointer which is dereferenced and read from, - "i" for printf integer formats where the '0' flag is ignored with - precision, and "[" for the starting character of a scanf scanset. */ - const char *flags2; - /* If this format conversion character consumes more than one argument, - CHAIN points to information about the next argument. For later - arguments, only POINTER_COUNT, TYPES, and the "c", "R", and "W" flags - in FLAGS2 are used. */ - const struct format_char_info *chain; -} format_char_info; - - -/* Structure describing a flag accepted by some kind of format. */ -typedef struct -{ - /* The flag character in question (0 for end of array). */ - int flag_char; - /* Zero if this entry describes the flag character in general, or a - nonzero character that may be found in flags2 if it describes the - flag when used with certain formats only. If the latter, only - the first such entry found that applies to the current conversion - specifier is used; the values of 'name' and 'long_name' it supplies - will be used, if non-NULL and the standard version is higher than - the unpredicated one, for any pedantic warning. For example, 'o' - for strftime formats (meaning 'O' is an extension over C99). */ - int predicate; - /* Nonzero if the next character after this flag in the format should - be skipped ('=' in strfmon), zero otherwise. */ - int skip_next_char; - /* The name to use for this flag in diagnostic messages. For example, - N_("'0' flag"), N_("field width"). */ - const char *name; - /* Long name for this flag in diagnostic messages; currently only used for - "ISO C does not support ...". For example, N_("the 'I' printf flag"). */ - const char *long_name; - /* The standard version in which it appeared. */ - enum format_std_version std; -} format_flag_spec; - - -/* Structure describing a combination of flags that is bad for some kind - of format. */ -typedef struct -{ - /* The first flag character in question (0 for end of array). */ - int flag_char1; - /* The second flag character. */ - int flag_char2; - /* Nonzero if the message should say that the first flag is ignored with - the second, zero if the combination should simply be objected to. */ - int ignored; - /* Zero if this entry applies whenever this flag combination occurs, - a nonzero character from flags2 if it only applies in some - circumstances (e.g. 'i' for printf formats ignoring 0 with precision). */ - int predicate; -} format_flag_pair; - - -/* Structure describing a particular kind of format processed by GCC. */ -typedef struct -{ - /* The name of this kind of format, for use in diagnostics. Also - the name of the attribute (without preceding and following __). */ - const char *name; - /* Specifications of the length modifiers accepted; possibly NULL. */ - const format_length_info *length_char_specs; - /* Details of the conversion specification characters accepted. */ - const format_char_info *conversion_specs; - /* String listing the flag characters that are accepted. */ - const char *flag_chars; - /* String listing modifier characters (strftime) accepted. May be NULL. */ - const char *modifier_chars; - /* Details of the flag characters, including pseudo-flags. */ - const format_flag_spec *flag_specs; - /* Details of bad combinations of flags. */ - const format_flag_pair *bad_flag_pairs; - /* Flags applicable to this kind of format. */ - int flags; - /* Flag character to treat a width as, or 0 if width not used. */ - int width_char; - /* Flag character to treat a left precision (strfmon) as, - or 0 if left precision not used. */ - int left_precision_char; - /* Flag character to treat a precision (for strfmon, right precision) as, - or 0 if precision not used. */ - int precision_char; - /* If a flag character has the effect of suppressing the conversion of - an argument ('*' in scanf), that flag character, otherwise 0. */ - int suppression_char; - /* Flag character to treat a length modifier as (ignored if length - modifiers not used). Need not be placed in flag_chars for conversion - specifiers, but is used to check for bad combinations such as length - modifier with assignment suppression in scanf. */ - int length_code_char; - /* Assignment-allocation flag character ('m' in scanf), otherwise 0. */ - int alloc_char; - /* Pointer to type of argument expected if '*' is used for a width, - or NULL if '*' not used for widths. */ - tree *width_type; - /* Pointer to type of argument expected if '*' is used for a precision, - or NULL if '*' not used for precisions. */ - tree *precision_type; -} format_kind_info; - -#define T_I &integer_type_node -#define T89_I { STD_C89, NULL, T_I } -#define T_L &long_integer_type_node -#define T89_L { STD_C89, NULL, T_L } -#define T_LL &long_long_integer_type_node -#define T9L_LL { STD_C9L, NULL, T_LL } -#define TEX_LL { STD_EXT, NULL, T_LL } -#define T_S &short_integer_type_node -#define T89_S { STD_C89, NULL, T_S } -#define T_UI &unsigned_type_node -#define T89_UI { STD_C89, NULL, T_UI } -#define T_UL &long_unsigned_type_node -#define T89_UL { STD_C89, NULL, T_UL } -#define T_ULL &long_long_unsigned_type_node -#define T9L_ULL { STD_C9L, NULL, T_ULL } -#define TEX_ULL { STD_EXT, NULL, T_ULL } -#define T_US &short_unsigned_type_node -#define T89_US { STD_C89, NULL, T_US } -#define T_F &float_type_node -#define T89_F { STD_C89, NULL, T_F } -#define T99_F { STD_C99, NULL, T_F } -#define T_D &double_type_node -#define T89_D { STD_C89, NULL, T_D } -#define T99_D { STD_C99, NULL, T_D } -#define T_LD &long_double_type_node -#define T89_LD { STD_C89, NULL, T_LD } -#define T99_LD { STD_C99, NULL, T_LD } -#define T_C &char_type_node -#define T89_C { STD_C89, NULL, T_C } -#define T_SC &signed_char_type_node -#define T99_SC { STD_C99, NULL, T_SC } -#define T_UC &unsigned_char_type_node -#define T99_UC { STD_C99, NULL, T_UC } -#define T_V &void_type_node -#define T89_V { STD_C89, NULL, T_V } -#define T_W &wchar_type_node -#define T94_W { STD_C94, "wchar_t", T_W } -#define TEX_W { STD_EXT, "wchar_t", T_W } -#define T_WI &wint_type_node -#define T94_WI { STD_C94, "wint_t", T_WI } -#define TEX_WI { STD_EXT, "wint_t", T_WI } -#define T_ST &size_type_node -#define T99_ST { STD_C99, "size_t", T_ST } -#define T_SST &signed_size_type_node -#define T99_SST { STD_C99, "signed size_t", T_SST } -#define T_PD &ptrdiff_type_node -#define T99_PD { STD_C99, "ptrdiff_t", T_PD } -#define T_UPD &unsigned_ptrdiff_type_node -#define T99_UPD { STD_C99, "unsigned ptrdiff_t", T_UPD } -#define T_IM &intmax_type_node -#define T99_IM { STD_C99, "intmax_t", T_IM } -#define T_UIM &uintmax_type_node -#define T99_UIM { STD_C99, "uintmax_t", T_UIM } -#define T_D32 &dfloat32_type_node -#define TEX_D32 { STD_EXT, "_Decimal32", T_D32 } -#define T_D64 &dfloat64_type_node -#define TEX_D64 { STD_EXT, "_Decimal64", T_D64 } -#define T_D128 &dfloat128_type_node -#define TEX_D128 { STD_EXT, "_Decimal128", T_D128 } - -/* Structure describing how format attributes such as "printf" are - interpreted as "gnu_printf" or "ms_printf" on a particular system. - TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific - defaults. */ -typedef struct -{ - /* The name of the to be copied format attribute. */ - const char *named_attr_src; - /* The name of the to be overridden format attribute. */ - const char *named_attr_dst; -} target_ovr_attr; - -#endif /* GCC_C_FORMAT_H */ diff --git a/gcc/c-gimplify.c b/gcc/c-gimplify.c deleted file mode 100644 index 06963a0..0000000 --- a/gcc/c-gimplify.c +++ /dev/null @@ -1,190 +0,0 @@ -/* Tree lowering pass. This pass gimplifies the tree representation built - by the C-based front ends. The structure of gimplified, or - language-independent, trees is dictated by the grammar described in this - file. - Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. - Lowering of expressions contributed by Sebastian Pop - Re-written to support lowering of whole function trees, documentation - and miscellaneous cleanups by Diego Novillo - -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 "tree.h" -#include "c-common.h" -#include "gimple.h" -#include "basic-block.h" -#include "tree-flow.h" -#include "tree-inline.h" -#include "diagnostic-core.h" -#include "langhooks.h" -#include "langhooks-def.h" -#include "flags.h" -#include "toplev.h" -#include "tree-dump.h" -#include "c-pretty-print.h" -#include "cgraph.h" - - -/* The gimplification pass converts the language-dependent trees - (ld-trees) emitted by the parser into language-independent trees - (li-trees) that are the target of SSA analysis and transformations. - - Language-independent trees are based on the SIMPLE intermediate - representation used in the McCAT compiler framework: - - "Designing the McCAT Compiler Based on a Family of Structured - Intermediate Representations," - L. Hendren, C. Donawa, M. Emami, G. Gao, Justiani, and B. Sridharan, - Proceedings of the 5th International Workshop on Languages and - Compilers for Parallel Computing, no. 757 in Lecture Notes in - Computer Science, New Haven, Connecticut, pp. 406-420, - Springer-Verlag, August 3-5, 1992. - - http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html - - Basically, we walk down gimplifying the nodes that we encounter. As we - walk back up, we check that they fit our constraints, and copy them - into temporaries if not. */ - -/* Gimplification of statement trees. */ - -/* Convert the tree representation of FNDECL from C frontend trees to - GENERIC. */ - -void -c_genericize (tree fndecl) -{ - FILE *dump_orig; - int local_dump_flags; - struct cgraph_node *cgn; - - /* Dump the C-specific tree IR. */ - dump_orig = dump_begin (TDI_original, &local_dump_flags); - if (dump_orig) - { - fprintf (dump_orig, "\n;; Function %s", - lang_hooks.decl_printable_name (fndecl, 2)); - fprintf (dump_orig, " (%s)\n", - (!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null" - : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)))); - fprintf (dump_orig, ";; enabled by -%s\n", dump_flag_name (TDI_original)); - fprintf (dump_orig, "\n"); - - if (local_dump_flags & TDF_RAW) - dump_node (DECL_SAVED_TREE (fndecl), - TDF_SLIM | local_dump_flags, dump_orig); - else - print_c_tree (dump_orig, DECL_SAVED_TREE (fndecl)); - fprintf (dump_orig, "\n"); - - dump_end (TDI_original, dump_orig); - } - - /* Dump all nested functions now. */ - cgn = cgraph_node (fndecl); - for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) - c_genericize (cgn->decl); -} - -static void -add_block_to_enclosing (tree block) -{ - unsigned i; - tree enclosing; - gimple bind; - VEC(gimple, heap) *stack = gimple_bind_expr_stack (); - - for (i = 0; VEC_iterate (gimple, stack, i, bind); i++) - if (gimple_bind_block (bind)) - break; - - enclosing = gimple_bind_block (bind); - BLOCK_SUBBLOCKS (enclosing) = chainon (BLOCK_SUBBLOCKS (enclosing), block); -} - -/* Genericize a scope by creating a new BIND_EXPR. - BLOCK is either a BLOCK representing the scope or a chain of _DECLs. - In the latter case, we need to create a new BLOCK and add it to the - BLOCK_SUBBLOCKS of the enclosing block. - BODY is a chain of C _STMT nodes for the contents of the scope, to be - genericized. */ - -tree -c_build_bind_expr (location_t loc, tree block, tree body) -{ - tree decls, bind; - - if (block == NULL_TREE) - decls = NULL_TREE; - else if (TREE_CODE (block) == BLOCK) - decls = BLOCK_VARS (block); - else - { - decls = block; - if (DECL_ARTIFICIAL (decls)) - block = NULL_TREE; - else - { - block = make_node (BLOCK); - BLOCK_VARS (block) = decls; - add_block_to_enclosing (block); - } - } - - if (!body) - body = build_empty_stmt (loc); - if (decls || block) - { - bind = build3 (BIND_EXPR, void_type_node, decls, body, block); - TREE_SIDE_EFFECTS (bind) = 1; - SET_EXPR_LOCATION (bind, loc); - } - else - bind = body; - - return bind; -} - -/* Gimplification of expression trees. */ - -/* Do C-specific gimplification on *EXPR_P. PRE_P and POST_P are as in - gimplify_expr. */ - -int -c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED, - gimple_seq *post_p ATTRIBUTE_UNUSED) -{ - enum tree_code code = TREE_CODE (*expr_p); - - /* This is handled mostly by gimplify.c, but we have to deal with - not warning about int x = x; as it is a GCC extension to turn off - this warning but only if warn_init_self is zero. */ - if (code == DECL_EXPR - && TREE_CODE (DECL_EXPR_DECL (*expr_p)) == VAR_DECL - && !DECL_EXTERNAL (DECL_EXPR_DECL (*expr_p)) - && !TREE_STATIC (DECL_EXPR_DECL (*expr_p)) - && (DECL_INITIAL (DECL_EXPR_DECL (*expr_p)) == DECL_EXPR_DECL (*expr_p)) - && !warn_init_self) - TREE_NO_WARNING (DECL_EXPR_DECL (*expr_p)) = 1; - - return GS_UNHANDLED; -} diff --git a/gcc/c-lang.c b/gcc/c-lang.c index 14d4eac..45a764f 100644 --- a/gcc/c-lang.c +++ b/gcc/c-lang.c @@ -26,13 +26,13 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "tree.h" #include "c-tree.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "langhooks.h" #include "langhooks-def.h" #include "tree-inline.h" #include "diagnostic-core.h" #include "c-objc-common.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" enum c_language_kind c_language = clk_c; diff --git a/gcc/c-lang.h b/gcc/c-lang.h index beed507..c0bdc7c 100644 --- a/gcc/c-lang.h +++ b/gcc/c-lang.h @@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_C_LANG_H #define GCC_C_LANG_H -#include "c-common.h" +#include "c-family/c-common.h" #include "ggc.h" struct GTY(()) lang_type { diff --git a/gcc/c-lex.c b/gcc/c-lex.c deleted file mode 100644 index 5af574d..0000000 --- a/gcc/c-lex.c +++ /dev/null @@ -1,1058 +0,0 @@ -/* Mainly the interface between cpplib and the C front ends. - Copyright (C) 1987, 1988, 1989, 1992, 1994, 1995, 1996, 1997 - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 - 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 "tree.h" -#include "input.h" -#include "output.h" -#include "c-common.h" -#include "flags.h" -#include "timevar.h" -#include "cpplib.h" -#include "c-pragma.h" -#include "toplev.h" -#include "intl.h" -#include "splay-tree.h" -#include "debug.h" -#include "target.h" - -/* We may keep statistics about how long which files took to compile. */ -static int header_time, body_time; -static splay_tree file_info_tree; - -int pending_lang_change; /* If we need to switch languages - C++ only */ -int c_header_level; /* depth in C headers - C++ only */ - -static tree interpret_integer (const cpp_token *, unsigned int); -static tree interpret_float (const cpp_token *, unsigned int); -static tree interpret_fixed (const cpp_token *, unsigned int); -static enum integer_type_kind narrowest_unsigned_type - (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int); -static enum integer_type_kind narrowest_signed_type - (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int); -static enum cpp_ttype lex_string (const cpp_token *, tree *, bool, bool); -static tree lex_charconst (const cpp_token *); -static void update_header_times (const char *); -static int dump_one_header (splay_tree_node, void *); -static void cb_line_change (cpp_reader *, const cpp_token *, int); -static void cb_ident (cpp_reader *, unsigned int, const cpp_string *); -static void cb_def_pragma (cpp_reader *, unsigned int); -static void cb_define (cpp_reader *, unsigned int, cpp_hashnode *); -static void cb_undef (cpp_reader *, unsigned int, cpp_hashnode *); - -void -init_c_lex (void) -{ - struct cpp_callbacks *cb; - struct c_fileinfo *toplevel; - - /* The get_fileinfo data structure must be initialized before - cpp_read_main_file is called. */ - toplevel = get_fileinfo (""); - if (flag_detailed_statistics) - { - header_time = 0; - body_time = get_run_time (); - toplevel->time = body_time; - } - - cb = cpp_get_callbacks (parse_in); - - cb->line_change = cb_line_change; - cb->ident = cb_ident; - cb->def_pragma = cb_def_pragma; - cb->valid_pch = c_common_valid_pch; - cb->read_pch = c_common_read_pch; - - /* Set the debug callbacks if we can use them. */ - if (debug_info_level == DINFO_LEVEL_VERBOSE - && (write_symbols == DWARF2_DEBUG - || write_symbols == VMS_AND_DWARF2_DEBUG)) - { - cb->define = cb_define; - cb->undef = cb_undef; - } -} - -struct c_fileinfo * -get_fileinfo (const char *name) -{ - splay_tree_node n; - struct c_fileinfo *fi; - - if (!file_info_tree) - file_info_tree = splay_tree_new ((splay_tree_compare_fn) strcmp, - 0, - (splay_tree_delete_value_fn) free); - - n = splay_tree_lookup (file_info_tree, (splay_tree_key) name); - if (n) - return (struct c_fileinfo *) n->value; - - fi = XNEW (struct c_fileinfo); - fi->time = 0; - fi->interface_only = 0; - fi->interface_unknown = 1; - splay_tree_insert (file_info_tree, (splay_tree_key) name, - (splay_tree_value) fi); - return fi; -} - -static void -update_header_times (const char *name) -{ - /* Changing files again. This means currently collected time - is charged against header time, and body time starts back at 0. */ - if (flag_detailed_statistics) - { - int this_time = get_run_time (); - struct c_fileinfo *file = get_fileinfo (name); - header_time += this_time - body_time; - file->time += this_time - body_time; - body_time = this_time; - } -} - -static int -dump_one_header (splay_tree_node n, void * ARG_UNUSED (dummy)) -{ - print_time ((const char *) n->key, - ((struct c_fileinfo *) n->value)->time); - return 0; -} - -void -dump_time_statistics (void) -{ - struct c_fileinfo *file = get_fileinfo (input_filename); - int this_time = get_run_time (); - file->time += this_time - body_time; - - fprintf (stderr, "\n******\n"); - print_time ("header files (total)", header_time); - print_time ("main file (total)", this_time - body_time); - fprintf (stderr, "ratio = %g : 1\n", - (double) header_time / (double) (this_time - body_time)); - fprintf (stderr, "\n******\n"); - - splay_tree_foreach (file_info_tree, dump_one_header, 0); -} - -static void -cb_ident (cpp_reader * ARG_UNUSED (pfile), - unsigned int ARG_UNUSED (line), - const cpp_string * ARG_UNUSED (str)) -{ -#ifdef ASM_OUTPUT_IDENT - if (!flag_no_ident) - { - /* Convert escapes in the string. */ - cpp_string cstr = { 0, 0 }; - if (cpp_interpret_string (pfile, str, 1, &cstr, CPP_STRING)) - { - ASM_OUTPUT_IDENT (asm_out_file, (const char *) cstr.text); - free (CONST_CAST (unsigned char *, cstr.text)); - } - } -#endif -} - -/* Called at the start of every non-empty line. TOKEN is the first - lexed token on the line. Used for diagnostic line numbers. */ -static void -cb_line_change (cpp_reader * ARG_UNUSED (pfile), const cpp_token *token, - int parsing_args) -{ - if (token->type != CPP_EOF && !parsing_args) - input_location = token->src_loc; -} - -void -fe_file_change (const struct line_map *new_map) -{ - if (new_map == NULL) - return; - - if (new_map->reason == LC_ENTER) - { - /* Don't stack the main buffer on the input stack; - we already did in compile_file. */ - if (!MAIN_FILE_P (new_map)) - { - unsigned int included_at = LAST_SOURCE_LINE_LOCATION (new_map - 1); - int line = 0; - if (included_at > BUILTINS_LOCATION) - line = SOURCE_LINE (new_map - 1, included_at); - - input_location = new_map->start_location; - (*debug_hooks->start_source_file) (line, new_map->to_file); -#ifndef NO_IMPLICIT_EXTERN_C - if (c_header_level) - ++c_header_level; - else if (new_map->sysp == 2) - { - c_header_level = 1; - ++pending_lang_change; - } -#endif - } - } - else if (new_map->reason == LC_LEAVE) - { -#ifndef NO_IMPLICIT_EXTERN_C - if (c_header_level && --c_header_level == 0) - { - if (new_map->sysp == 2) - warning (0, "badly nested C headers from preprocessor"); - --pending_lang_change; - } -#endif - input_location = new_map->start_location; - - (*debug_hooks->end_source_file) (new_map->to_line); - } - - update_header_times (new_map->to_file); - input_location = new_map->start_location; -} - -static void -cb_def_pragma (cpp_reader *pfile, source_location loc) -{ - /* Issue a warning message if we have been asked to do so. Ignore - unknown pragmas in system headers unless an explicit - -Wunknown-pragmas has been given. */ - if (warn_unknown_pragmas > in_system_header) - { - const unsigned char *space, *name; - const cpp_token *s; - location_t fe_loc = loc; - - space = name = (const unsigned char *) ""; - s = cpp_get_token (pfile); - if (s->type != CPP_EOF) - { - space = cpp_token_as_text (pfile, s); - s = cpp_get_token (pfile); - if (s->type == CPP_NAME) - name = cpp_token_as_text (pfile, s); - } - - warning_at (fe_loc, OPT_Wunknown_pragmas, "ignoring #pragma %s %s", - space, name); - } -} - -/* #define callback for DWARF and DWARF2 debug info. */ -static void -cb_define (cpp_reader *pfile, source_location loc, cpp_hashnode *node) -{ - const struct line_map *map = linemap_lookup (line_table, loc); - (*debug_hooks->define) (SOURCE_LINE (map, loc), - (const char *) cpp_macro_definition (pfile, node)); -} - -/* #undef callback for DWARF and DWARF2 debug info. */ -static void -cb_undef (cpp_reader * ARG_UNUSED (pfile), source_location loc, - cpp_hashnode *node) -{ - const struct line_map *map = linemap_lookup (line_table, loc); - (*debug_hooks->undef) (SOURCE_LINE (map, loc), - (const char *) NODE_NAME (node)); -} - -/* Read a token and return its type. Fill *VALUE with its value, if - applicable. Fill *CPP_FLAGS with the token's flags, if it is - non-NULL. */ - -enum cpp_ttype -c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, - int lex_flags) -{ - static bool no_more_pch; - const cpp_token *tok; - enum cpp_ttype type; - unsigned char add_flags = 0; - - timevar_push (TV_CPP); - retry: - tok = cpp_get_token_with_location (parse_in, loc); - type = tok->type; - - retry_after_at: - switch (type) - { - case CPP_PADDING: - goto retry; - - case CPP_NAME: - *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node)); - break; - - case CPP_NUMBER: - { - unsigned int flags = cpp_classify_number (parse_in, tok); - - switch (flags & CPP_N_CATEGORY) - { - case CPP_N_INVALID: - /* cpplib has issued an error. */ - *value = error_mark_node; - break; - - case CPP_N_INTEGER: - /* C++ uses '0' to mark virtual functions as pure. - Set PURE_ZERO to pass this information to the C++ parser. */ - if (tok->val.str.len == 1 && *tok->val.str.text == '0') - add_flags = PURE_ZERO; - *value = interpret_integer (tok, flags); - break; - - case CPP_N_FLOATING: - *value = interpret_float (tok, flags); - break; - - default: - gcc_unreachable (); - } - } - break; - - case CPP_ATSIGN: - /* An @ may give the next token special significance in Objective-C. */ - if (c_dialect_objc ()) - { - location_t atloc = *loc; - location_t newloc; - - retry_at: - tok = cpp_get_token_with_location (parse_in, &newloc); - type = tok->type; - switch (type) - { - case CPP_PADDING: - goto retry_at; - - case CPP_STRING: - case CPP_WSTRING: - case CPP_STRING16: - case CPP_STRING32: - case CPP_UTF8STRING: - type = lex_string (tok, value, true, true); - break; - - case CPP_NAME: - *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node)); - if (objc_is_reserved_word (*value)) - { - type = CPP_AT_NAME; - break; - } - /* FALLTHROUGH */ - - default: - /* ... or not. */ - error_at (atloc, "stray %<@%> in program"); - *loc = newloc; - goto retry_after_at; - } - break; - } - - /* FALLTHROUGH */ - case CPP_HASH: - case CPP_PASTE: - { - unsigned char name[8]; - - *cpp_spell_token (parse_in, tok, name, true) = 0; - - error ("stray %qs in program", name); - } - - goto retry; - - case CPP_OTHER: - { - cppchar_t c = tok->val.str.text[0]; - - if (c == '"' || c == '\'') - error ("missing terminating %c character", (int) c); - else if (ISGRAPH (c)) - error ("stray %qc in program", (int) c); - else - error ("stray %<\\%o%> in program", (int) c); - } - goto retry; - - case CPP_CHAR: - case CPP_WCHAR: - case CPP_CHAR16: - case CPP_CHAR32: - *value = lex_charconst (tok); - break; - - case CPP_STRING: - case CPP_WSTRING: - case CPP_STRING16: - case CPP_STRING32: - case CPP_UTF8STRING: - if ((lex_flags & C_LEX_STRING_NO_JOIN) == 0) - { - type = lex_string (tok, value, false, - (lex_flags & C_LEX_STRING_NO_TRANSLATE) == 0); - break; - } - *value = build_string (tok->val.str.len, (const char *) tok->val.str.text); - break; - - case CPP_PRAGMA: - *value = build_int_cst (NULL, tok->val.pragma); - break; - - /* These tokens should not be visible outside cpplib. */ - case CPP_HEADER_NAME: - case CPP_MACRO_ARG: - gcc_unreachable (); - - /* CPP_COMMENT will appear when compiling with -C and should be - ignored. */ - case CPP_COMMENT: - goto retry; - - default: - *value = NULL_TREE; - break; - } - - if (cpp_flags) - *cpp_flags = tok->flags | add_flags; - - if (!no_more_pch) - { - no_more_pch = true; - c_common_no_more_pch (); - } - - timevar_pop (TV_CPP); - - return type; -} - -/* Returns the narrowest C-visible unsigned type, starting with the - minimum specified by FLAGS, that can fit HIGH:LOW, or itk_none if - there isn't one. */ - -static enum integer_type_kind -narrowest_unsigned_type (unsigned HOST_WIDE_INT low, - unsigned HOST_WIDE_INT high, - unsigned int flags) -{ - int itk; - - if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) - itk = itk_unsigned_int; - else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) - itk = itk_unsigned_long; - else - itk = itk_unsigned_long_long; - - for (; itk < itk_none; itk += 2 /* skip unsigned types */) - { - tree upper; - - if (integer_types[itk] == NULL_TREE) - continue; - upper = TYPE_MAX_VALUE (integer_types[itk]); - - if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) > high - || ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) == high - && TREE_INT_CST_LOW (upper) >= low)) - return (enum integer_type_kind) itk; - } - - return itk_none; -} - -/* Ditto, but narrowest signed type. */ -static enum integer_type_kind -narrowest_signed_type (unsigned HOST_WIDE_INT low, - unsigned HOST_WIDE_INT high, unsigned int flags) -{ - int itk; - - if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) - itk = itk_int; - else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) - itk = itk_long; - else - itk = itk_long_long; - - - for (; itk < itk_none; itk += 2 /* skip signed types */) - { - tree upper; - - if (integer_types[itk] == NULL_TREE) - continue; - upper = TYPE_MAX_VALUE (integer_types[itk]); - - if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) > high - || ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) == high - && TREE_INT_CST_LOW (upper) >= low)) - return (enum integer_type_kind) itk; - } - - return itk_none; -} - -/* Interpret TOKEN, an integer with FLAGS as classified by cpplib. */ -static tree -interpret_integer (const cpp_token *token, unsigned int flags) -{ - tree value, type; - enum integer_type_kind itk; - cpp_num integer; - cpp_options *options = cpp_get_options (parse_in); - - integer = cpp_interpret_integer (parse_in, token, flags); - integer = cpp_num_sign_extend (integer, options->precision); - - /* The type of a constant with a U suffix is straightforward. */ - if (flags & CPP_N_UNSIGNED) - itk = narrowest_unsigned_type (integer.low, integer.high, flags); - else - { - /* The type of a potentially-signed integer constant varies - depending on the base it's in, the standard in use, and the - length suffixes. */ - enum integer_type_kind itk_u - = narrowest_unsigned_type (integer.low, integer.high, flags); - enum integer_type_kind itk_s - = narrowest_signed_type (integer.low, integer.high, flags); - - /* In both C89 and C99, octal and hex constants may be signed or - unsigned, whichever fits tighter. We do not warn about this - choice differing from the traditional choice, as the constant - is probably a bit pattern and either way will work. */ - if ((flags & CPP_N_RADIX) != CPP_N_DECIMAL) - itk = MIN (itk_u, itk_s); - else - { - /* In C99, decimal constants are always signed. - In C89, decimal constants that don't fit in long have - undefined behavior; we try to make them unsigned long. - In GCC's extended C89, that last is true of decimal - constants that don't fit in long long, too. */ - - itk = itk_s; - if (itk_s > itk_u && itk_s > itk_long) - { - if (!flag_isoc99) - { - if (itk_u < itk_unsigned_long) - itk_u = itk_unsigned_long; - itk = itk_u; - warning (0, "this decimal constant is unsigned only in ISO C90"); - } - else - warning (OPT_Wtraditional, - "this decimal constant would be unsigned in ISO C90"); - } - } - } - - if (itk == itk_none) - /* cpplib has already issued a warning for overflow. */ - type = ((flags & CPP_N_UNSIGNED) - ? widest_unsigned_literal_type_node - : widest_integer_literal_type_node); - else - { - type = integer_types[itk]; - if (itk > itk_unsigned_long - && (flags & CPP_N_WIDTH) != CPP_N_LARGE) - emit_diagnostic - ((c_dialect_cxx () ? cxx_dialect == cxx98 : !flag_isoc99) - ? DK_PEDWARN : DK_WARNING, - input_location, OPT_Wlong_long, - (flags & CPP_N_UNSIGNED) - ? "integer constant is too large for % type" - : "integer constant is too large for % type"); - } - - value = build_int_cst_wide (type, integer.low, integer.high); - - /* Convert imaginary to a complex type. */ - if (flags & CPP_N_IMAGINARY) - value = build_complex (NULL_TREE, build_int_cst (type, 0), value); - - return value; -} - -/* Interpret TOKEN, a floating point number with FLAGS as classified - by cpplib. */ -static tree -interpret_float (const cpp_token *token, unsigned int flags) -{ - tree type; - tree const_type; - tree value; - REAL_VALUE_TYPE real; - REAL_VALUE_TYPE real_trunc; - char *copy; - size_t copylen; - - /* Default (no suffix) depends on whether the FLOAT_CONST_DECIMAL64 - pragma has been used and is either double or _Decimal64. Types - that are not allowed with decimal float default to double. */ - if (flags & CPP_N_DEFAULT) - { - flags ^= CPP_N_DEFAULT; - flags |= CPP_N_MEDIUM; - - if (((flags & CPP_N_HEX) == 0) && ((flags & CPP_N_IMAGINARY) == 0)) - { - warning (OPT_Wunsuffixed_float_constants, - "unsuffixed float constant"); - if (float_const_decimal64_p ()) - flags |= CPP_N_DFLOAT; - } - } - - /* Decode _Fract and _Accum. */ - if (flags & CPP_N_FRACT || flags & CPP_N_ACCUM) - return interpret_fixed (token, flags); - - /* Decode type based on width and properties. */ - if (flags & CPP_N_DFLOAT) - if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) - type = dfloat128_type_node; - else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) - type = dfloat32_type_node; - else - type = dfloat64_type_node; - else - if (flags & CPP_N_WIDTH_MD) - { - char suffix; - enum machine_mode mode; - - if ((flags & CPP_N_WIDTH_MD) == CPP_N_MD_W) - suffix = 'w'; - else - suffix = 'q'; - - mode = targetm.c.mode_for_suffix (suffix); - if (mode == VOIDmode) - { - error ("unsupported non-standard suffix on floating constant"); - - return error_mark_node; - } - else - pedwarn (input_location, OPT_pedantic, "non-standard suffix on floating constant"); - - type = c_common_type_for_mode (mode, 0); - gcc_assert (type); - } - else if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) - type = long_double_type_node; - else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL - || flag_single_precision_constant) - type = float_type_node; - else - type = double_type_node; - - const_type = excess_precision_type (type); - if (!const_type) - const_type = type; - - /* Copy the constant to a nul-terminated buffer. If the constant - has any suffixes, cut them off; REAL_VALUE_ATOF/ REAL_VALUE_HTOF - can't handle them. */ - copylen = token->val.str.len; - if (flags & CPP_N_DFLOAT) - copylen -= 2; - else - { - if ((flags & CPP_N_WIDTH) != CPP_N_MEDIUM) - /* Must be an F or L or machine defined suffix. */ - copylen--; - if (flags & CPP_N_IMAGINARY) - /* I or J suffix. */ - copylen--; - } - - copy = (char *) alloca (copylen + 1); - memcpy (copy, token->val.str.text, copylen); - copy[copylen] = '\0'; - - real_from_string3 (&real, copy, TYPE_MODE (const_type)); - if (const_type != type) - /* Diagnosing if the result of converting the value with excess - precision to the semantic type would overflow (with associated - double rounding) is more appropriate than diagnosing if the - result of converting the string directly to the semantic type - would overflow. */ - real_convert (&real_trunc, TYPE_MODE (type), &real); - - /* Both C and C++ require a diagnostic for a floating constant - outside the range of representable values of its type. Since we - have __builtin_inf* to produce an infinity, this is now a - mandatory pedwarn if the target does not support infinities. */ - if (REAL_VALUE_ISINF (real) - || (const_type != type && REAL_VALUE_ISINF (real_trunc))) - { - if (!MODE_HAS_INFINITIES (TYPE_MODE (type))) - pedwarn (input_location, 0, "floating constant exceeds range of %qT", type); - else - warning (OPT_Woverflow, "floating constant exceeds range of %qT", type); - } - /* We also give a warning if the value underflows. */ - else if (REAL_VALUES_EQUAL (real, dconst0) - || (const_type != type && REAL_VALUES_EQUAL (real_trunc, dconst0))) - { - REAL_VALUE_TYPE realvoidmode; - int overflow = real_from_string (&realvoidmode, copy); - if (overflow < 0 || !REAL_VALUES_EQUAL (realvoidmode, dconst0)) - warning (OPT_Woverflow, "floating constant truncated to zero"); - } - - /* Create a node with determined type and value. */ - value = build_real (const_type, real); - if (flags & CPP_N_IMAGINARY) - value = build_complex (NULL_TREE, convert (const_type, integer_zero_node), - value); - - if (type != const_type) - value = build1 (EXCESS_PRECISION_EXPR, type, value); - - return value; -} - -/* Interpret TOKEN, a fixed-point number with FLAGS as classified - by cpplib. */ - -static tree -interpret_fixed (const cpp_token *token, unsigned int flags) -{ - tree type; - tree value; - FIXED_VALUE_TYPE fixed; - char *copy; - size_t copylen; - - copylen = token->val.str.len; - - if (flags & CPP_N_FRACT) /* _Fract. */ - { - if (flags & CPP_N_UNSIGNED) /* Unsigned _Fract. */ - { - if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) - { - type = unsigned_long_long_fract_type_node; - copylen -= 4; - } - else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) - { - type = unsigned_long_fract_type_node; - copylen -= 3; - } - else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) - { - type = unsigned_short_fract_type_node; - copylen -= 3; - } - else - { - type = unsigned_fract_type_node; - copylen -= 2; - } - } - else /* Signed _Fract. */ - { - if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) - { - type = long_long_fract_type_node; - copylen -= 3; - } - else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) - { - type = long_fract_type_node; - copylen -= 2; - } - else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) - { - type = short_fract_type_node; - copylen -= 2; - } - else - { - type = fract_type_node; - copylen --; - } - } - } - else /* _Accum. */ - { - if (flags & CPP_N_UNSIGNED) /* Unsigned _Accum. */ - { - if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) - { - type = unsigned_long_long_accum_type_node; - copylen -= 4; - } - else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) - { - type = unsigned_long_accum_type_node; - copylen -= 3; - } - else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) - { - type = unsigned_short_accum_type_node; - copylen -= 3; - } - else - { - type = unsigned_accum_type_node; - copylen -= 2; - } - } - else /* Signed _Accum. */ - { - if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) - { - type = long_long_accum_type_node; - copylen -= 3; - } - else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) - { - type = long_accum_type_node; - copylen -= 2; - } - else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) - { - type = short_accum_type_node; - copylen -= 2; - } - else - { - type = accum_type_node; - copylen --; - } - } - } - - copy = (char *) alloca (copylen + 1); - memcpy (copy, token->val.str.text, copylen); - copy[copylen] = '\0'; - - fixed_from_string (&fixed, copy, TYPE_MODE (type)); - - /* Create a node with determined type and value. */ - value = build_fixed (type, fixed); - - return value; -} - -/* Convert a series of STRING, WSTRING, STRING16, STRING32 and/or - UTF8STRING tokens into a tree, performing string constant - concatenation. TOK is the first of these. VALP is the location - to write the string into. OBJC_STRING indicates whether an '@' token - preceded the incoming token. - Returns the CPP token type of the result (CPP_STRING, CPP_WSTRING, - CPP_STRING32, CPP_STRING16, CPP_UTF8STRING, or CPP_OBJC_STRING). - - This is unfortunately more work than it should be. If any of the - strings in the series has an L prefix, the result is a wide string - (6.4.5p4). Whether or not the result is a wide string affects the - meaning of octal and hexadecimal escapes (6.4.4.4p6,9). But escape - sequences do not continue across the boundary between two strings in - a series (6.4.5p7), so we must not lose the boundaries. Therefore - cpp_interpret_string takes a vector of cpp_string structures, which - we must arrange to provide. */ - -static enum cpp_ttype -lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate) -{ - tree value; - size_t concats = 0; - struct obstack str_ob; - cpp_string istr; - enum cpp_ttype type = tok->type; - - /* Try to avoid the overhead of creating and destroying an obstack - for the common case of just one string. */ - cpp_string str = tok->val.str; - cpp_string *strs = &str; - - retry: - tok = cpp_get_token (parse_in); - switch (tok->type) - { - case CPP_PADDING: - goto retry; - case CPP_ATSIGN: - if (c_dialect_objc ()) - { - objc_string = true; - goto retry; - } - /* FALLTHROUGH */ - - default: - break; - - case CPP_WSTRING: - case CPP_STRING16: - case CPP_STRING32: - case CPP_UTF8STRING: - if (type != tok->type) - { - if (type == CPP_STRING) - type = tok->type; - else - error ("unsupported non-standard concatenation of string literals"); - } - - case CPP_STRING: - if (!concats) - { - gcc_obstack_init (&str_ob); - obstack_grow (&str_ob, &str, sizeof (cpp_string)); - } - - concats++; - obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string)); - goto retry; - } - - /* We have read one more token than we want. */ - _cpp_backup_tokens (parse_in, 1); - if (concats) - strs = XOBFINISH (&str_ob, cpp_string *); - - if (concats && !objc_string && !in_system_header) - warning (OPT_Wtraditional, - "traditional C rejects string constant concatenation"); - - if ((translate - ? cpp_interpret_string : cpp_interpret_string_notranslate) - (parse_in, strs, concats + 1, &istr, type)) - { - value = build_string (istr.len, (const char *) istr.text); - free (CONST_CAST (unsigned char *, istr.text)); - } - else - { - /* Callers cannot generally handle error_mark_node in this context, - so return the empty string instead. cpp_interpret_string has - issued an error. */ - 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; - } - *valp = fix_string_type (value); - - if (concats) - obstack_free (&str_ob, 0); - - return objc_string ? CPP_OBJC_STRING : type; -} - -/* Converts a (possibly wide) character constant token into a tree. */ -static tree -lex_charconst (const cpp_token *token) -{ - cppchar_t result; - tree type, value; - unsigned int chars_seen; - int unsignedp = 0; - - result = cpp_interpret_charconst (parse_in, token, - &chars_seen, &unsignedp); - - if (token->type == CPP_WCHAR) - type = wchar_type_node; - else if (token->type == CPP_CHAR32) - type = char32_type_node; - else if (token->type == CPP_CHAR16) - type = char16_type_node; - /* In C, a character constant has type 'int'. - In C++ 'char', but multi-char charconsts have type 'int'. */ - else if (!c_dialect_cxx () || chars_seen > 1) - type = integer_type_node; - else - type = char_type_node; - - /* Cast to cppchar_signed_t to get correct sign-extension of RESULT - before possibly widening to HOST_WIDE_INT for build_int_cst. */ - if (unsignedp || (cppchar_signed_t) result >= 0) - value = build_int_cst_wide (type, result, 0); - else - value = build_int_cst_wide (type, (cppchar_signed_t) result, -1); - - return value; -} diff --git a/gcc/c-objc-common.c b/gcc/c-objc-common.c index 7694a38..0bb252f 100644 --- a/gcc/c-objc-common.c +++ b/gcc/c-objc-common.c @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "c-tree.h" #include "intl.h" -#include "c-pretty-print.h" +#include "c-family/c-pretty-print.h" #include "flags.h" #include "diagnostic.h" #include "tree-pretty-print.h" diff --git a/gcc/c-omp.c b/gcc/c-omp.c deleted file mode 100644 index 31970bd..0000000 --- a/gcc/c-omp.c +++ /dev/null @@ -1,531 +0,0 @@ -/* This file contains routines to construct GNU OpenMP constructs, - called from parsing in the C and C++ front ends. - - Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. - Contributed by Richard Henderson , - Diego Novillo . - -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 "tree.h" -#include "c-common.h" -#include "toplev.h" -#include "gimple.h" /* For create_tmp_var_raw. */ -#include "langhooks.h" - - -/* Complete a #pragma omp master construct. STMT is the structured-block - that follows the pragma. LOC is the l*/ - -tree -c_finish_omp_master (location_t loc, tree stmt) -{ - tree t = add_stmt (build1 (OMP_MASTER, void_type_node, stmt)); - SET_EXPR_LOCATION (t, loc); - return t; -} - -/* Complete a #pragma omp critical construct. STMT is the structured-block - that follows the pragma, NAME is the identifier in the pragma, or null - if it was omitted. LOC is the location of the #pragma. */ - -tree -c_finish_omp_critical (location_t loc, tree body, tree name) -{ - tree stmt = make_node (OMP_CRITICAL); - TREE_TYPE (stmt) = void_type_node; - OMP_CRITICAL_BODY (stmt) = body; - OMP_CRITICAL_NAME (stmt) = name; - SET_EXPR_LOCATION (stmt, loc); - return add_stmt (stmt); -} - -/* Complete a #pragma omp ordered construct. STMT is the structured-block - that follows the pragma. LOC is the location of the #pragma. */ - -tree -c_finish_omp_ordered (location_t loc, tree stmt) -{ - tree t = build1 (OMP_ORDERED, void_type_node, stmt); - SET_EXPR_LOCATION (t, loc); - return add_stmt (t); -} - - -/* Complete a #pragma omp barrier construct. LOC is the location of - the #pragma. */ - -void -c_finish_omp_barrier (location_t loc) -{ - tree x; - - x = built_in_decls[BUILT_IN_GOMP_BARRIER]; - x = build_call_expr_loc (loc, x, 0); - add_stmt (x); -} - - -/* Complete a #pragma omp taskwait construct. LOC is the location of the - pragma. */ - -void -c_finish_omp_taskwait (location_t loc) -{ - tree x; - - x = built_in_decls[BUILT_IN_GOMP_TASKWAIT]; - x = build_call_expr_loc (loc, x, 0); - add_stmt (x); -} - - -/* Complete a #pragma omp atomic construct. The expression to be - implemented atomically is LHS code= RHS. LOC is the location of - the atomic statement. The value returned is either error_mark_node - (if the construct was erroneous) or an OMP_ATOMIC node which should - be added to the current statement tree with add_stmt.*/ - -tree -c_finish_omp_atomic (location_t loc, enum tree_code code, tree lhs, tree rhs) -{ - tree x, type, addr; - - if (lhs == error_mark_node || rhs == error_mark_node) - return error_mark_node; - - /* ??? According to one reading of the OpenMP spec, complex type are - supported, but there are no atomic stores for any architecture. - But at least icc 9.0 doesn't support complex types here either. - And lets not even talk about vector types... */ - type = TREE_TYPE (lhs); - if (!INTEGRAL_TYPE_P (type) - && !POINTER_TYPE_P (type) - && !SCALAR_FLOAT_TYPE_P (type)) - { - error_at (loc, "invalid expression type for %<#pragma omp atomic%>"); - return error_mark_node; - } - - /* ??? Validate that rhs does not overlap lhs. */ - - /* Take and save the address of the lhs. From then on we'll reference it - via indirection. */ - addr = build_unary_op (loc, ADDR_EXPR, lhs, 0); - if (addr == error_mark_node) - return error_mark_node; - addr = save_expr (addr); - if (TREE_CODE (addr) != SAVE_EXPR - && (TREE_CODE (addr) != ADDR_EXPR - || TREE_CODE (TREE_OPERAND (addr, 0)) != VAR_DECL)) - { - /* Make sure LHS is simple enough so that goa_lhs_expr_p can recognize - it even after unsharing function body. */ - tree var = create_tmp_var_raw (TREE_TYPE (addr), NULL); - DECL_CONTEXT (var) = current_function_decl; - addr = build4 (TARGET_EXPR, TREE_TYPE (addr), var, addr, NULL, NULL); - } - lhs = build_indirect_ref (loc, addr, RO_NULL); - - /* There are lots of warnings, errors, and conversions that need to happen - in the course of interpreting a statement. Use the normal mechanisms - to do this, and then take it apart again. */ - x = build_modify_expr (input_location, lhs, NULL_TREE, code, - input_location, rhs, NULL_TREE); - if (x == error_mark_node) - return error_mark_node; - gcc_assert (TREE_CODE (x) == MODIFY_EXPR); - rhs = TREE_OPERAND (x, 1); - - /* Punt the actual generation of atomic operations to common code. */ - x = build2 (OMP_ATOMIC, void_type_node, addr, rhs); - SET_EXPR_LOCATION (x, loc); - return x; -} - - -/* Complete a #pragma omp flush construct. We don't do anything with - the variable list that the syntax allows. LOC is the location of - the #pragma. */ - -void -c_finish_omp_flush (location_t loc) -{ - tree x; - - x = built_in_decls[BUILT_IN_SYNCHRONIZE]; - x = build_call_expr_loc (loc, x, 0); - add_stmt (x); -} - - -/* Check and canonicalize #pragma omp for increment expression. - Helper function for c_finish_omp_for. */ - -static tree -check_omp_for_incr_expr (location_t loc, tree exp, tree decl) -{ - tree t; - - if (!INTEGRAL_TYPE_P (TREE_TYPE (exp)) - || TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (decl))) - return error_mark_node; - - if (exp == decl) - return build_int_cst (TREE_TYPE (exp), 0); - - switch (TREE_CODE (exp)) - { - CASE_CONVERT: - t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl); - if (t != error_mark_node) - return fold_convert_loc (loc, TREE_TYPE (exp), t); - break; - case MINUS_EXPR: - t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl); - if (t != error_mark_node) - return fold_build2_loc (loc, MINUS_EXPR, - TREE_TYPE (exp), t, TREE_OPERAND (exp, 1)); - break; - case PLUS_EXPR: - t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl); - if (t != error_mark_node) - return fold_build2_loc (loc, PLUS_EXPR, - TREE_TYPE (exp), t, TREE_OPERAND (exp, 1)); - t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 1), decl); - if (t != error_mark_node) - return fold_build2_loc (loc, PLUS_EXPR, - TREE_TYPE (exp), TREE_OPERAND (exp, 0), t); - break; - default: - break; - } - - return error_mark_node; -} - -/* Validate and emit code for the OpenMP directive #pragma omp for. - DECLV is a vector of iteration variables, for each collapsed loop. - INITV, CONDV and INCRV are vectors containing initialization - expressions, controlling predicates and increment expressions. - BODY is the body of the loop and PRE_BODY statements that go before - the loop. */ - -tree -c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv, - tree incrv, tree body, tree pre_body) -{ - location_t elocus; - bool fail = false; - int i; - - gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv)); - gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv)); - gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (incrv)); - for (i = 0; i < TREE_VEC_LENGTH (declv); i++) - { - tree decl = TREE_VEC_ELT (declv, i); - tree init = TREE_VEC_ELT (initv, i); - tree cond = TREE_VEC_ELT (condv, i); - tree incr = TREE_VEC_ELT (incrv, i); - - elocus = locus; - if (EXPR_HAS_LOCATION (init)) - elocus = EXPR_LOCATION (init); - - /* Validate the iteration variable. */ - if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)) - && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE) - { - error_at (elocus, "invalid type for iteration variable %qE", decl); - fail = true; - } - - /* In the case of "for (int i = 0...)", init will be a decl. It should - have a DECL_INITIAL that we can turn into an assignment. */ - if (init == decl) - { - elocus = DECL_SOURCE_LOCATION (decl); - - init = DECL_INITIAL (decl); - if (init == NULL) - { - error_at (elocus, "%qE is not initialized", decl); - init = integer_zero_node; - fail = true; - } - - init = build_modify_expr (elocus, decl, NULL_TREE, NOP_EXPR, - /* FIXME diagnostics: This should - be the location of the INIT. */ - elocus, - init, - NULL_TREE); - } - gcc_assert (TREE_CODE (init) == MODIFY_EXPR); - gcc_assert (TREE_OPERAND (init, 0) == decl); - - if (cond == NULL_TREE) - { - error_at (elocus, "missing controlling predicate"); - fail = true; - } - else - { - bool cond_ok = false; - - if (EXPR_HAS_LOCATION (cond)) - elocus = EXPR_LOCATION (cond); - - if (TREE_CODE (cond) == LT_EXPR - || TREE_CODE (cond) == LE_EXPR - || TREE_CODE (cond) == GT_EXPR - || TREE_CODE (cond) == GE_EXPR - || TREE_CODE (cond) == NE_EXPR - || TREE_CODE (cond) == EQ_EXPR) - { - tree op0 = TREE_OPERAND (cond, 0); - tree op1 = TREE_OPERAND (cond, 1); - - /* 2.5.1. The comparison in the condition is computed in - the type of DECL, otherwise the behavior is undefined. - - For example: - long n; int i; - i < n; - - according to ISO will be evaluated as: - (long)i < n; - - We want to force: - i < (int)n; */ - if (TREE_CODE (op0) == NOP_EXPR - && decl == TREE_OPERAND (op0, 0)) - { - TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0); - TREE_OPERAND (cond, 1) - = fold_build1_loc (elocus, NOP_EXPR, TREE_TYPE (decl), - TREE_OPERAND (cond, 1)); - } - else if (TREE_CODE (op1) == NOP_EXPR - && decl == TREE_OPERAND (op1, 0)) - { - TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0); - TREE_OPERAND (cond, 0) - = fold_build1_loc (elocus, NOP_EXPR, TREE_TYPE (decl), - TREE_OPERAND (cond, 0)); - } - - if (decl == TREE_OPERAND (cond, 0)) - cond_ok = true; - else if (decl == TREE_OPERAND (cond, 1)) - { - TREE_SET_CODE (cond, - swap_tree_comparison (TREE_CODE (cond))); - TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0); - TREE_OPERAND (cond, 0) = decl; - cond_ok = true; - } - - if (TREE_CODE (cond) == NE_EXPR - || TREE_CODE (cond) == EQ_EXPR) - { - if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))) - cond_ok = false; - else if (operand_equal_p (TREE_OPERAND (cond, 1), - TYPE_MIN_VALUE (TREE_TYPE (decl)), - 0)) - TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR - ? GT_EXPR : LE_EXPR); - else if (operand_equal_p (TREE_OPERAND (cond, 1), - TYPE_MAX_VALUE (TREE_TYPE (decl)), - 0)) - TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR - ? LT_EXPR : GE_EXPR); - else - cond_ok = false; - } - } - - if (!cond_ok) - { - error_at (elocus, "invalid controlling predicate"); - fail = true; - } - } - - if (incr == NULL_TREE) - { - error_at (elocus, "missing increment expression"); - fail = true; - } - else - { - bool incr_ok = false; - - if (EXPR_HAS_LOCATION (incr)) - elocus = EXPR_LOCATION (incr); - - /* Check all the valid increment expressions: v++, v--, ++v, --v, - v = v + incr, v = incr + v and v = v - incr. */ - switch (TREE_CODE (incr)) - { - case POSTINCREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case PREDECREMENT_EXPR: - if (TREE_OPERAND (incr, 0) != decl) - break; - - incr_ok = true; - if (POINTER_TYPE_P (TREE_TYPE (decl)) - && TREE_OPERAND (incr, 1)) - { - tree t = fold_convert_loc (elocus, - sizetype, TREE_OPERAND (incr, 1)); - - if (TREE_CODE (incr) == POSTDECREMENT_EXPR - || TREE_CODE (incr) == PREDECREMENT_EXPR) - t = fold_build1_loc (elocus, NEGATE_EXPR, sizetype, t); - t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (decl), decl, t); - incr = build2 (MODIFY_EXPR, void_type_node, decl, t); - } - break; - - case MODIFY_EXPR: - if (TREE_OPERAND (incr, 0) != decl) - break; - if (TREE_OPERAND (incr, 1) == decl) - break; - if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR - && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl - || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl)) - incr_ok = true; - else if ((TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR - || (TREE_CODE (TREE_OPERAND (incr, 1)) - == POINTER_PLUS_EXPR)) - && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl) - incr_ok = true; - else - { - tree t = check_omp_for_incr_expr (elocus, - TREE_OPERAND (incr, 1), - decl); - if (t != error_mark_node) - { - incr_ok = true; - t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t); - incr = build2 (MODIFY_EXPR, void_type_node, decl, t); - } - } - break; - - default: - break; - } - if (!incr_ok) - { - error_at (elocus, "invalid increment expression"); - fail = true; - } - } - - TREE_VEC_ELT (initv, i) = init; - TREE_VEC_ELT (incrv, i) = incr; - } - - if (fail) - return NULL; - else - { - tree t = make_node (OMP_FOR); - - TREE_TYPE (t) = void_type_node; - OMP_FOR_INIT (t) = initv; - OMP_FOR_COND (t) = condv; - OMP_FOR_INCR (t) = incrv; - OMP_FOR_BODY (t) = body; - OMP_FOR_PRE_BODY (t) = pre_body; - - SET_EXPR_LOCATION (t, locus); - return add_stmt (t); - } -} - - -/* Divide CLAUSES into two lists: those that apply to a parallel - construct, and those that apply to a work-sharing construct. Place - the results in *PAR_CLAUSES and *WS_CLAUSES respectively. In - addition, add a nowait clause to the work-sharing list. LOC is the - location of the OMP_PARALLEL*. */ - -void -c_split_parallel_clauses (location_t loc, tree clauses, - tree *par_clauses, tree *ws_clauses) -{ - tree next; - - *par_clauses = NULL; - *ws_clauses = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); - - for (; clauses ; clauses = next) - { - next = OMP_CLAUSE_CHAIN (clauses); - - switch (OMP_CLAUSE_CODE (clauses)) - { - case OMP_CLAUSE_PRIVATE: - case OMP_CLAUSE_SHARED: - case OMP_CLAUSE_FIRSTPRIVATE: - case OMP_CLAUSE_LASTPRIVATE: - case OMP_CLAUSE_REDUCTION: - case OMP_CLAUSE_COPYIN: - case OMP_CLAUSE_IF: - case OMP_CLAUSE_NUM_THREADS: - case OMP_CLAUSE_DEFAULT: - OMP_CLAUSE_CHAIN (clauses) = *par_clauses; - *par_clauses = clauses; - break; - - case OMP_CLAUSE_SCHEDULE: - case OMP_CLAUSE_ORDERED: - case OMP_CLAUSE_COLLAPSE: - OMP_CLAUSE_CHAIN (clauses) = *ws_clauses; - *ws_clauses = clauses; - break; - - default: - gcc_unreachable (); - } - } -} - -/* True if OpenMP sharing attribute of DECL is predetermined. */ - -enum omp_clause_default_kind -c_omp_predetermined_sharing (tree decl) -{ - /* Variables with const-qualified type having no mutable member - are predetermined shared. */ - if (TREE_READONLY (decl)) - return OMP_CLAUSE_DEFAULT_SHARED; - - return OMP_CLAUSE_DEFAULT_UNSPECIFIED; -} diff --git a/gcc/c-opts.c b/gcc/c-opts.c deleted file mode 100644 index 08592f5..0000000 --- a/gcc/c-opts.c +++ /dev/null @@ -1,1815 +0,0 @@ -/* C/ObjC/C++ command line option handling. - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. - Contributed by Neil Booth. - -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 "tree.h" -#include "c-common.h" -#include "c-pragma.h" -#include "flags.h" -#include "toplev.h" -#include "langhooks.h" -#include "diagnostic.h" -#include "intl.h" -#include "cppdefault.h" -#include "incpath.h" -#include "debug.h" /* For debug_hooks. */ -#include "opts.h" -#include "options.h" -#include "mkdeps.h" -#include "target.h" /* For gcc_targetcm. */ - -#ifndef DOLLARS_IN_IDENTIFIERS -# define DOLLARS_IN_IDENTIFIERS true -#endif - -#ifndef TARGET_SYSTEM_ROOT -# define TARGET_SYSTEM_ROOT NULL -#endif - -#ifndef TARGET_OPTF -#define TARGET_OPTF(ARG) -#endif - -/* CPP's options. */ -cpp_options *cpp_opts; - -/* Input filename. */ -static const char *this_input_filename; - -/* Filename and stream for preprocessed output. */ -static const char *out_fname; -static FILE *out_stream; - -/* Append dependencies to deps_file. */ -static bool deps_append; - -/* If dependency switches (-MF etc.) have been given. */ -static bool deps_seen; - -/* If -v seen. */ -static bool verbose; - -/* Dependency output file. */ -static const char *deps_file; - -/* The prefix given by -iprefix, if any. */ -static const char *iprefix; - -/* The multilib directory given by -imultilib, if any. */ -static const char *imultilib; - -/* The system root, if any. Overridden by -isysroot. */ -static const char *sysroot = TARGET_SYSTEM_ROOT; - -/* Zero disables all standard directories for headers. */ -static bool std_inc = true; - -/* Zero disables the C++-specific standard directories for headers. */ -static bool std_cxx_inc = true; - -/* If the quote chain has been split by -I-. */ -static bool quote_chain_split; - -/* If -Wunused-macros. */ -static bool warn_unused_macros; - -/* If -Wvariadic-macros. */ -static bool warn_variadic_macros = true; - -/* Number of deferred options. */ -static size_t deferred_count; - -/* Number of deferred options scanned for -include. */ -static size_t include_cursor; - -static void handle_OPT_d (const char *); -static void set_std_cxx98 (int); -static void set_std_cxx0x (int); -static void set_std_c89 (int, int); -static void set_std_c99 (int); -static void set_std_c1x (int); -static void check_deps_environment_vars (void); -static void handle_deferred_opts (void); -static void sanitize_cpp_opts (void); -static void add_prefixed_path (const char *, size_t); -static void push_command_line_include (void); -static void cb_file_change (cpp_reader *, const struct line_map *); -static void cb_dir_change (cpp_reader *, const char *); -static void finish_options (void); - -#ifndef STDC_0_IN_SYSTEM_HEADERS -#define STDC_0_IN_SYSTEM_HEADERS 0 -#endif - -/* Holds switches parsed by c_common_handle_option (), but whose - handling is deferred to c_common_post_options (). */ -static void defer_opt (enum opt_code, const char *); -static struct deferred_opt -{ - enum opt_code code; - const char *arg; -} *deferred_opts; - - -static const unsigned int -c_family_lang_mask = (CL_C | CL_CXX | CL_ObjC | CL_ObjCXX); - -/* Complain that switch CODE expects an argument but none was - provided. OPT was the command-line option. Return FALSE to get - the default message in opts.c, TRUE if we provide a specialized - one. */ -bool -c_common_missing_argument (const char *opt, size_t code) -{ - switch (code) - { - default: - /* Pick up the default message. */ - return false; - - case OPT_fconstant_string_class_: - error ("no class name specified with %qs", opt); - break; - - case OPT_A: - error ("assertion missing after %qs", opt); - break; - - case OPT_D: - case OPT_U: - error ("macro name missing after %qs", opt); - break; - - case OPT_F: - case OPT_I: - case OPT_idirafter: - case OPT_isysroot: - case OPT_isystem: - case OPT_iquote: - error ("missing path after %qs", opt); - break; - - case OPT_MF: - case OPT_MD: - case OPT_MMD: - case OPT_include: - case OPT_imacros: - case OPT_o: - error ("missing filename after %qs", opt); - break; - - case OPT_MQ: - case OPT_MT: - error ("missing makefile target after %qs", opt); - break; - } - - return true; -} - -/* Defer option CODE with argument ARG. */ -static void -defer_opt (enum opt_code code, const char *arg) -{ - deferred_opts[deferred_count].code = code; - deferred_opts[deferred_count].arg = arg; - deferred_count++; -} - -/* -Werror= may set a warning option to enable a warning that is emitted - by the preprocessor. Set any corresponding flag in cpp_opts. */ - -static void -warning_as_error_callback (int option_index) -{ - switch (option_index) - { - default: - /* Ignore options not associated with the preprocessor. */ - break; - - case OPT_Wdeprecated: - cpp_opts->warn_deprecated = 1; - break; - - case OPT_Wcomment: - case OPT_Wcomments: - cpp_opts->warn_comments = 1; - break; - - case OPT_Wtrigraphs: - cpp_opts->warn_trigraphs = 1; - break; - - case OPT_Wmultichar: - cpp_opts->warn_multichar = 1; - break; - - case OPT_Wtraditional: - cpp_opts->warn_traditional = 1; - break; - - case OPT_Wlong_long: - cpp_opts->warn_long_long = 1; - break; - - case OPT_Wendif_labels: - cpp_opts->warn_endif_labels = 1; - break; - - case OPT_Wvariadic_macros: - /* Set the local flag that is used later to update cpp_opts. */ - warn_variadic_macros = 1; - break; - - case OPT_Wbuiltin_macro_redefined: - cpp_opts->warn_builtin_macro_redefined = 1; - break; - - case OPT_Wundef: - cpp_opts->warn_undef = 1; - break; - - case OPT_Wunused_macros: - /* Set the local flag that is used later to update cpp_opts. */ - warn_unused_macros = 1; - break; - - case OPT_Wc___compat: - /* Add warnings in the same way as c_common_handle_option below. */ - if (warn_enum_compare == -1) - warn_enum_compare = 1; - if (warn_jump_misses_init == -1) - warn_jump_misses_init = 1; - cpp_opts->warn_cxx_operator_names = 1; - break; - - case OPT_Wnormalized_: - inform (input_location, "-Werror=normalized=: Set -Wnormalized=nfc"); - cpp_opts->warn_normalize = normalized_C; - break; - - case OPT_Winvalid_pch: - cpp_opts->warn_invalid_pch = 1; - break; - - case OPT_Wcpp: - /* Handled by standard diagnostics using the option's associated - boolean variable. */ - break; - } -} - -/* Common initialization before parsing options. */ -unsigned int -c_common_init_options (unsigned int argc, const char **argv) -{ - static const unsigned int lang_flags[] = {CL_C, CL_ObjC, CL_CXX, CL_ObjCXX}; - unsigned int i, result; - struct cpp_callbacks *cb; - - /* Register callback for warnings enabled by -Werror=. */ - register_warning_as_error_callback (warning_as_error_callback); - - /* This is conditionalized only because that is the way the front - ends used to do it. Maybe this should be unconditional? */ - if (c_dialect_cxx ()) - { - /* By default wrap lines at 80 characters. Is getenv - ("COLUMNS") preferable? */ - diagnostic_line_cutoff (global_dc) = 80; - /* By default, emit location information once for every - diagnostic message. */ - diagnostic_prefixing_rule (global_dc) = DIAGNOSTICS_SHOW_PREFIX_ONCE; - } - - global_dc->opt_permissive = OPT_fpermissive; - - parse_in = cpp_create_reader (c_dialect_cxx () ? CLK_GNUCXX: CLK_GNUC89, - ident_hash, line_table); - cb = cpp_get_callbacks (parse_in); - cb->error = c_cpp_error; - - cpp_opts = cpp_get_options (parse_in); - cpp_opts->dollars_in_ident = DOLLARS_IN_IDENTIFIERS; - cpp_opts->objc = c_dialect_objc (); - - /* Reset to avoid warnings on internal definitions. We set it just - before passing on command-line options to cpplib. */ - cpp_opts->warn_dollars = 0; - - flag_exceptions = c_dialect_cxx (); - warn_pointer_arith = c_dialect_cxx (); - warn_write_strings = c_dialect_cxx(); - flag_warn_unused_result = true; - - /* By default, C99-like requirements for complex multiply and divide. */ - flag_complex_method = 2; - - deferred_opts = XNEWVEC (struct deferred_opt, argc); - - result = lang_flags[c_language]; - - if (c_language == clk_c) - { - /* If preprocessing assembly language, accept any of the C-family - front end options since the driver may pass them through. */ - for (i = 1; i < argc; i++) - if (! strcmp (argv[i], "-lang-asm")) - { - result |= CL_C | CL_ObjC | CL_CXX | CL_ObjCXX; - break; - } - } - - return result; -} - -/* Handle switch SCODE with argument ARG. VALUE is true, unless no- - form of an -f or -W option was given. Returns 0 if the switch was - invalid, a negative number to prevent language-independent - processing in toplev.c (a hack necessary for the short-term). */ -int -c_common_handle_option (size_t scode, const char *arg, int value, - int kind) -{ - const struct cl_option *option = &cl_options[scode]; - enum opt_code code = (enum opt_code) scode; - int result = 1; - - /* Prevent resetting the language standard to a C dialect when the driver - has already determined that we're looking at assembler input. */ - bool preprocessing_asm_p = (cpp_get_options (parse_in)->lang == CLK_ASM); - - switch (code) - { - default: - if (cl_options[code].flags & c_family_lang_mask) - { - if ((option->flags & CL_TARGET) - && ! targetcm.handle_c_option (scode, arg, value)) - result = 0; - break; - } - result = 0; - break; - - case OPT__output_pch_: - pch_file = arg; - break; - - case OPT_A: - defer_opt (code, arg); - break; - - case OPT_C: - cpp_opts->discard_comments = 0; - break; - - case OPT_CC: - cpp_opts->discard_comments = 0; - cpp_opts->discard_comments_in_macro_exp = 0; - break; - - case OPT_D: - defer_opt (code, arg); - break; - - case OPT_E: - flag_preprocess_only = 1; - break; - - case OPT_H: - cpp_opts->print_include_names = 1; - break; - - case OPT_F: - TARGET_OPTF (xstrdup (arg)); - break; - - case OPT_I: - if (strcmp (arg, "-")) - add_path (xstrdup (arg), BRACKET, 0, true); - else - { - if (quote_chain_split) - error ("-I- specified twice"); - quote_chain_split = true; - split_quote_chain (); - inform (input_location, "obsolete option -I- used, please use -iquote instead"); - } - break; - - case OPT_M: - case OPT_MM: - /* When doing dependencies with -M or -MM, suppress normal - preprocessed output, but still do -dM etc. as software - depends on this. Preprocessed output does occur if -MD, -MMD - or environment var dependency generation is used. */ - cpp_opts->deps.style = (code == OPT_M ? DEPS_SYSTEM: DEPS_USER); - flag_no_output = 1; - break; - - case OPT_MD: - case OPT_MMD: - cpp_opts->deps.style = (code == OPT_MD ? DEPS_SYSTEM: DEPS_USER); - cpp_opts->deps.need_preprocessor_output = true; - deps_file = arg; - break; - - case OPT_MF: - deps_seen = true; - deps_file = arg; - break; - - case OPT_MG: - deps_seen = true; - cpp_opts->deps.missing_files = true; - break; - - case OPT_MP: - deps_seen = true; - cpp_opts->deps.phony_targets = true; - break; - - case OPT_MQ: - case OPT_MT: - deps_seen = true; - defer_opt (code, arg); - break; - - case OPT_P: - flag_no_line_commands = 1; - break; - - case OPT_fworking_directory: - flag_working_directory = value; - break; - - case OPT_U: - defer_opt (code, arg); - break; - - case OPT_Wall: - warn_unused = value; - set_Wformat (value); - handle_option (OPT_Wimplicit, value, NULL, c_family_lang_mask, kind); - warn_char_subscripts = value; - warn_missing_braces = value; - warn_parentheses = value; - warn_return_type = value; - warn_sequence_point = value; /* Was C only. */ - warn_switch = value; - if (warn_strict_aliasing == -1) - set_Wstrict_aliasing (value); - warn_address = value; - if (warn_strict_overflow == -1) - warn_strict_overflow = value; - warn_array_bounds = value; - warn_volatile_register_var = value; - - /* Only warn about unknown pragmas that are not in system - headers. */ - warn_unknown_pragmas = value; - - warn_uninitialized = value; - - if (!c_dialect_cxx ()) - { - /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding - can turn it off only if it's not explicit. */ - if (warn_main == -1) - warn_main = (value ? 2 : 0); - - /* In C, -Wall turns on -Wenum-compare, which we do here. - In C++ it is on by default, which is done in - c_common_post_options. */ - if (warn_enum_compare == -1) - warn_enum_compare = value; - } - else - { - /* C++-specific warnings. */ - warn_sign_compare = value; - warn_reorder = value; - warn_cxx0x_compat = value; - } - - cpp_opts->warn_trigraphs = value; - cpp_opts->warn_comments = value; - cpp_opts->warn_num_sign_change = value; - - if (warn_pointer_sign == -1) - warn_pointer_sign = value; - break; - - case OPT_Wbuiltin_macro_redefined: - cpp_opts->warn_builtin_macro_redefined = value; - break; - - case OPT_Wcomment: - case OPT_Wcomments: - cpp_opts->warn_comments = value; - break; - - case OPT_Wc___compat: - /* Because -Wenum-compare is the default in C++, -Wc++-compat - implies -Wenum-compare. */ - if (warn_enum_compare == -1 && value) - warn_enum_compare = value; - /* Because C++ always warns about a goto which misses an - initialization, -Wc++-compat turns on -Wjump-misses-init. */ - if (warn_jump_misses_init == -1 && value) - warn_jump_misses_init = value; - cpp_opts->warn_cxx_operator_names = value; - break; - - case OPT_Wdeprecated: - cpp_opts->warn_deprecated = value; - break; - - case OPT_Wendif_labels: - cpp_opts->warn_endif_labels = value; - break; - - case OPT_Werror: - global_dc->warning_as_error_requested = value; - break; - - case OPT_Werror_implicit_function_declaration: - /* For backward compatibility, this is the same as - -Werror=implicit-function-declaration. */ - enable_warning_as_error ("implicit-function-declaration", value, CL_C | CL_ObjC); - break; - - case OPT_Wformat: - set_Wformat (value); - break; - - case OPT_Wformat_: - set_Wformat (atoi (arg)); - break; - - case OPT_Wimplicit: - gcc_assert (value == 0 || value == 1); - if (warn_implicit_int == -1) - handle_option (OPT_Wimplicit_int, value, NULL, - c_family_lang_mask, kind); - if (warn_implicit_function_declaration == -1) - handle_option (OPT_Wimplicit_function_declaration, value, NULL, - c_family_lang_mask, kind); - break; - - case OPT_Wimport: - /* Silently ignore for now. */ - break; - - case OPT_Winvalid_pch: - cpp_opts->warn_invalid_pch = value; - break; - - case OPT_Wmissing_include_dirs: - cpp_opts->warn_missing_include_dirs = value; - break; - - case OPT_Wmultichar: - cpp_opts->warn_multichar = value; - break; - - case OPT_Wnormalized_: - if (!value || (arg && strcasecmp (arg, "none") == 0)) - cpp_opts->warn_normalize = normalized_none; - else if (!arg || strcasecmp (arg, "nfkc") == 0) - cpp_opts->warn_normalize = normalized_KC; - else if (strcasecmp (arg, "id") == 0) - cpp_opts->warn_normalize = normalized_identifier_C; - else if (strcasecmp (arg, "nfc") == 0) - cpp_opts->warn_normalize = normalized_C; - else - error ("argument %qs to %<-Wnormalized%> not recognized", arg); - break; - - case OPT_Wreturn_type: - warn_return_type = value; - break; - - case OPT_Wstrict_null_sentinel: - warn_strict_null_sentinel = value; - break; - - case OPT_Wtraditional: - cpp_opts->warn_traditional = value; - break; - - case OPT_Wtrigraphs: - cpp_opts->warn_trigraphs = value; - break; - - case OPT_Wundef: - cpp_opts->warn_undef = value; - break; - - case OPT_Wunknown_pragmas: - /* Set to greater than 1, so that even unknown pragmas in - system headers will be warned about. */ - warn_unknown_pragmas = value * 2; - break; - - case OPT_Wunused_macros: - warn_unused_macros = value; - break; - - case OPT_Wvariadic_macros: - warn_variadic_macros = value; - break; - - case OPT_Wwrite_strings: - warn_write_strings = value; - break; - - case OPT_Weffc__: - warn_ecpp = value; - if (value) - warn_nonvdtor = true; - break; - - case OPT_ansi: - if (!c_dialect_cxx ()) - set_std_c89 (false, true); - else - set_std_cxx98 (true); - break; - - case OPT_d: - handle_OPT_d (arg); - break; - - case OPT_fcond_mismatch: - if (!c_dialect_cxx ()) - { - flag_cond_mismatch = value; - break; - } - /* Fall through. */ - - case OPT_fall_virtual: - case OPT_falt_external_templates: - case OPT_fenum_int_equiv: - case OPT_fexternal_templates: - case OPT_fguiding_decls: - case OPT_fhonor_std: - case OPT_fhuge_objects: - case OPT_flabels_ok: - case OPT_fname_mangling_version_: - case OPT_fnew_abi: - case OPT_fnonnull_objects: - case OPT_fsquangle: - case OPT_fstrict_prototype: - case OPT_fthis_is_variable: - case OPT_fvtable_thunks: - case OPT_fxref: - case OPT_fvtable_gc: - warning (0, "switch %qs is no longer supported", option->opt_text); - break; - - case OPT_faccess_control: - flag_access_control = value; - break; - - case OPT_fasm: - flag_no_asm = !value; - break; - - case OPT_fbuiltin: - flag_no_builtin = !value; - break; - - case OPT_fbuiltin_: - if (value) - result = 0; - else - disable_builtin_function (arg); - break; - - case OPT_fdirectives_only: - cpp_opts->directives_only = value; - break; - - case OPT_fdollars_in_identifiers: - cpp_opts->dollars_in_ident = value; - break; - - case OPT_ffreestanding: - value = !value; - /* Fall through.... */ - case OPT_fhosted: - flag_hosted = value; - flag_no_builtin = !value; - break; - - case OPT_fshort_double: - flag_short_double = value; - break; - - case OPT_fshort_enums: - flag_short_enums = value; - break; - - case OPT_fshort_wchar: - flag_short_wchar = value; - break; - - case OPT_fsigned_bitfields: - flag_signed_bitfields = value; - break; - - case OPT_fsigned_char: - flag_signed_char = value; - break; - - case OPT_funsigned_bitfields: - flag_signed_bitfields = !value; - break; - - case OPT_funsigned_char: - flag_signed_char = !value; - break; - - case OPT_fcheck_new: - flag_check_new = value; - break; - - case OPT_fconserve_space: - flag_conserve_space = value; - break; - - case OPT_fconstant_string_class_: - constant_string_class_name = arg; - break; - - case OPT_fdefault_inline: - flag_default_inline = value; - break; - - case OPT_felide_constructors: - flag_elide_constructors = value; - break; - - case OPT_fenforce_eh_specs: - flag_enforce_eh_specs = value; - break; - - case OPT_fextended_identifiers: - cpp_opts->extended_identifiers = value; - break; - - case OPT_ffor_scope: - flag_new_for_scope = value; - break; - - case OPT_fgnu_keywords: - flag_no_gnu_keywords = !value; - break; - - case OPT_fgnu_runtime: - flag_next_runtime = !value; - break; - - case OPT_fhandle_exceptions: - warning (0, "-fhandle-exceptions has been renamed -fexceptions (and is now on by default)"); - flag_exceptions = value; - break; - - case OPT_fimplement_inlines: - flag_implement_inlines = value; - break; - - case OPT_fimplicit_inline_templates: - flag_implicit_inline_templates = value; - break; - - case OPT_fimplicit_templates: - flag_implicit_templates = value; - break; - - case OPT_flax_vector_conversions: - flag_lax_vector_conversions = value; - break; - - case OPT_fms_extensions: - flag_ms_extensions = value; - break; - - case OPT_fnext_runtime: - flag_next_runtime = value; - break; - - case OPT_fnil_receivers: - flag_nil_receivers = value; - break; - - case OPT_fnonansi_builtins: - flag_no_nonansi_builtin = !value; - break; - - case OPT_foperator_names: - cpp_opts->operator_names = value; - break; - - case OPT_foptional_diags: - flag_optional_diags = value; - break; - - case OPT_fpch_deps: - cpp_opts->restore_pch_deps = value; - break; - - case OPT_fpch_preprocess: - flag_pch_preprocess = value; - break; - - case OPT_fpermissive: - flag_permissive = value; - global_dc->permissive = value; - break; - - case OPT_fpreprocessed: - cpp_opts->preprocessed = value; - break; - - case OPT_freplace_objc_classes: - flag_replace_objc_classes = value; - break; - - case OPT_frepo: - flag_use_repository = value; - if (value) - flag_implicit_templates = 0; - break; - - case OPT_frtti: - flag_rtti = value; - break; - - case OPT_fshow_column: - cpp_opts->show_column = value; - break; - - case OPT_fstats: - flag_detailed_statistics = value; - break; - - case OPT_ftabstop_: - /* It is documented that we silently ignore silly values. */ - if (value >= 1 && value <= 100) - cpp_opts->tabstop = value; - break; - - case OPT_fexec_charset_: - cpp_opts->narrow_charset = arg; - break; - - case OPT_fwide_exec_charset_: - cpp_opts->wide_charset = arg; - break; - - case OPT_finput_charset_: - cpp_opts->input_charset = arg; - break; - - case OPT_ftemplate_depth_: - /* Kept for backwards compatibility. */ - case OPT_ftemplate_depth_eq: - max_tinst_depth = value; - break; - - case OPT_fuse_cxa_atexit: - flag_use_cxa_atexit = value; - break; - - case OPT_fuse_cxa_get_exception_ptr: - flag_use_cxa_get_exception_ptr = value; - break; - - case OPT_fvisibility_inlines_hidden: - visibility_options.inlines_hidden = value; - break; - - case OPT_fweak: - flag_weak = value; - break; - - case OPT_fthreadsafe_statics: - flag_threadsafe_statics = value; - break; - - case OPT_fpretty_templates: - flag_pretty_templates = value; - break; - - case OPT_fzero_link: - flag_zero_link = value; - break; - - case OPT_gen_decls: - flag_gen_declaration = 1; - break; - - case OPT_femit_struct_debug_baseonly: - set_struct_debug_option ("base"); - break; - - case OPT_femit_struct_debug_reduced: - set_struct_debug_option ("dir:ord:sys,dir:gen:any,ind:base"); - break; - - case OPT_femit_struct_debug_detailed_: - set_struct_debug_option (arg); - break; - - case OPT_idirafter: - add_path (xstrdup (arg), AFTER, 0, true); - break; - - case OPT_imacros: - case OPT_include: - defer_opt (code, arg); - break; - - case OPT_imultilib: - imultilib = arg; - break; - - case OPT_iprefix: - iprefix = arg; - break; - - case OPT_iquote: - add_path (xstrdup (arg), QUOTE, 0, true); - break; - - case OPT_isysroot: - sysroot = arg; - break; - - case OPT_isystem: - add_path (xstrdup (arg), SYSTEM, 0, true); - break; - - case OPT_iwithprefix: - add_prefixed_path (arg, SYSTEM); - break; - - case OPT_iwithprefixbefore: - add_prefixed_path (arg, BRACKET); - break; - - case OPT_lang_asm: - cpp_set_lang (parse_in, CLK_ASM); - cpp_opts->dollars_in_ident = false; - break; - - case OPT_lang_objc: - cpp_opts->objc = 1; - break; - - case OPT_nostdinc: - std_inc = false; - break; - - case OPT_nostdinc__: - std_cxx_inc = false; - break; - - case OPT_o: - if (!out_fname) - out_fname = arg; - else - error ("output filename specified twice"); - break; - - /* We need to handle the -pedantic switches here, rather than in - c_common_post_options, so that a subsequent -Wno-endif-labels - is not overridden. */ - case OPT_pedantic_errors: - case OPT_pedantic: - cpp_opts->pedantic = 1; - cpp_opts->warn_endif_labels = 1; - if (warn_pointer_sign == -1) - warn_pointer_sign = 1; - if (warn_overlength_strings == -1) - warn_overlength_strings = 1; - if (warn_main == -1) - warn_main = 2; - break; - - case OPT_print_objc_runtime_info: - print_struct_values = 1; - break; - - case OPT_print_pch_checksum: - c_common_print_pch_checksum (stdout); - exit_after_options = true; - break; - - case OPT_remap: - cpp_opts->remap = 1; - break; - - case OPT_std_c__98: - case OPT_std_gnu__98: - if (!preprocessing_asm_p) - set_std_cxx98 (code == OPT_std_c__98 /* ISO */); - break; - - case OPT_std_c__0x: - case OPT_std_gnu__0x: - if (!preprocessing_asm_p) - set_std_cxx0x (code == OPT_std_c__0x /* ISO */); - break; - - case OPT_std_c89: - case OPT_std_c90: - case OPT_std_iso9899_1990: - case OPT_std_iso9899_199409: - if (!preprocessing_asm_p) - set_std_c89 (code == OPT_std_iso9899_199409 /* c94 */, true /* ISO */); - break; - - case OPT_std_gnu89: - case OPT_std_gnu90: - if (!preprocessing_asm_p) - set_std_c89 (false /* c94 */, false /* ISO */); - break; - - case OPT_std_c99: - case OPT_std_c9x: - case OPT_std_iso9899_1999: - case OPT_std_iso9899_199x: - if (!preprocessing_asm_p) - set_std_c99 (true /* ISO */); - break; - - case OPT_std_gnu99: - case OPT_std_gnu9x: - if (!preprocessing_asm_p) - set_std_c99 (false /* ISO */); - break; - - case OPT_std_c1x: - if (!preprocessing_asm_p) - set_std_c1x (true /* ISO */); - break; - - case OPT_std_gnu1x: - if (!preprocessing_asm_p) - set_std_c1x (false /* ISO */); - break; - - case OPT_trigraphs: - cpp_opts->trigraphs = 1; - break; - - case OPT_traditional_cpp: - cpp_opts->traditional = 1; - break; - - case OPT_undef: - flag_undef = 1; - break; - - case OPT_v: - verbose = true; - break; - - case OPT_Wabi: - warn_psabi = value; - break; - } - - return result; -} - -/* Post-switch processing. */ -bool -c_common_post_options (const char **pfilename) -{ - struct cpp_callbacks *cb; - - /* Canonicalize the input and output filenames. */ - if (in_fnames == NULL) - { - in_fnames = XNEWVEC (const char *, 1); - in_fnames[0] = ""; - } - else if (strcmp (in_fnames[0], "-") == 0) - in_fnames[0] = ""; - - if (out_fname == NULL || !strcmp (out_fname, "-")) - out_fname = ""; - - if (cpp_opts->deps.style == DEPS_NONE) - check_deps_environment_vars (); - - handle_deferred_opts (); - - sanitize_cpp_opts (); - - register_include_chains (parse_in, sysroot, iprefix, imultilib, - std_inc, std_cxx_inc && c_dialect_cxx (), verbose); - -#ifdef C_COMMON_OVERRIDE_OPTIONS - /* Some machines may reject certain combinations of C - language-specific options. */ - C_COMMON_OVERRIDE_OPTIONS; -#endif - - /* Excess precision other than "fast" requires front-end - support. */ - if (c_dialect_cxx ()) - { - if (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD - && TARGET_FLT_EVAL_METHOD_NON_DEFAULT) - sorry ("-fexcess-precision=standard for C++"); - flag_excess_precision_cmdline = EXCESS_PRECISION_FAST; - } - else if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT) - flag_excess_precision_cmdline = (flag_iso - ? EXCESS_PRECISION_STANDARD - : EXCESS_PRECISION_FAST); - - /* By default we use C99 inline semantics in GNU99 or C99 mode. C99 - inline semantics are not supported in GNU89 or C89 mode. */ - if (flag_gnu89_inline == -1) - flag_gnu89_inline = !flag_isoc99; - else if (!flag_gnu89_inline && !flag_isoc99) - error ("-fno-gnu89-inline is only supported in GNU99 or C99 mode"); - - /* Default to ObjC sjlj exception handling if NeXT runtime. */ - if (flag_objc_sjlj_exceptions < 0) - flag_objc_sjlj_exceptions = flag_next_runtime; - if (flag_objc_exceptions && !flag_objc_sjlj_exceptions) - flag_exceptions = 1; - - /* -Wextra implies the following flags - unless explicitly overridden. */ - if (warn_type_limits == -1) - warn_type_limits = extra_warnings; - if (warn_clobbered == -1) - warn_clobbered = extra_warnings; - if (warn_empty_body == -1) - warn_empty_body = extra_warnings; - if (warn_sign_compare == -1) - warn_sign_compare = extra_warnings; - if (warn_missing_field_initializers == -1) - warn_missing_field_initializers = extra_warnings; - if (warn_missing_parameter_type == -1) - warn_missing_parameter_type = extra_warnings; - if (warn_old_style_declaration == -1) - warn_old_style_declaration = extra_warnings; - if (warn_override_init == -1) - warn_override_init = extra_warnings; - if (warn_ignored_qualifiers == -1) - warn_ignored_qualifiers = extra_warnings; - - /* -Wpointer-sign is disabled by default, but it is enabled if any - of -Wall or -pedantic are given. */ - if (warn_pointer_sign == -1) - warn_pointer_sign = 0; - - if (warn_strict_aliasing == -1) - warn_strict_aliasing = 0; - if (warn_strict_overflow == -1) - warn_strict_overflow = 0; - if (warn_jump_misses_init == -1) - warn_jump_misses_init = 0; - - /* -Woverlength-strings is off by default, but is enabled by -pedantic. - It is never enabled in C++, as the minimum limit is not normative - in that standard. */ - if (warn_overlength_strings == -1 || c_dialect_cxx ()) - warn_overlength_strings = 0; - - /* Wmain is enabled by default in C++ but not in C. */ - /* Wmain is disabled by default for -ffreestanding (!flag_hosted), - even if -Wall was given (warn_main will be 2 if set by -Wall, 1 - if set by -Wmain). */ - if (warn_main == -1) - warn_main = (c_dialect_cxx () && flag_hosted) ? 1 : 0; - else if (warn_main == 2) - warn_main = flag_hosted ? 1 : 0; - - /* In C, -Wconversion enables -Wsign-conversion (unless disabled - through -Wno-sign-conversion). While in C++, - -Wsign-conversion needs to be requested explicitly. */ - if (warn_sign_conversion == -1) - warn_sign_conversion = (c_dialect_cxx ()) ? 0 : warn_conversion; - - /* In C, -Wall and -Wc++-compat enable -Wenum-compare, which we do - in c_common_handle_option; if it has not yet been set, it is - disabled by default. In C++, it is enabled by default. */ - if (warn_enum_compare == -1) - warn_enum_compare = c_dialect_cxx () ? 1 : 0; - - /* -Wpacked-bitfield-compat is on by default for the C languages. The - warning is issued in stor-layout.c which is not part of the front-end so - we need to selectively turn it on here. */ - if (warn_packed_bitfield_compat == -1) - warn_packed_bitfield_compat = 1; - - /* Special format checking options don't work without -Wformat; warn if - they are used. */ - if (!warn_format) - { - warning (OPT_Wformat_y2k, - "-Wformat-y2k ignored without -Wformat"); - warning (OPT_Wformat_extra_args, - "-Wformat-extra-args ignored without -Wformat"); - warning (OPT_Wformat_zero_length, - "-Wformat-zero-length ignored without -Wformat"); - warning (OPT_Wformat_nonliteral, - "-Wformat-nonliteral ignored without -Wformat"); - warning (OPT_Wformat_contains_nul, - "-Wformat-contains-nul ignored without -Wformat"); - warning (OPT_Wformat_security, - "-Wformat-security ignored without -Wformat"); - } - - if (warn_implicit == -1) - warn_implicit = 0; - - if (warn_implicit_int == -1) - warn_implicit_int = 0; - - /* -Wimplicit-function-declaration is enabled by default for C99. */ - if (warn_implicit_function_declaration == -1) - warn_implicit_function_declaration = flag_isoc99; - - /* If we're allowing C++0x constructs, don't warn about C++0x - compatibility problems. */ - if (cxx_dialect == cxx0x) - warn_cxx0x_compat = 0; - - if (flag_preprocess_only) - { - /* Open the output now. We must do so even if flag_no_output is - on, because there may be other output than from the actual - preprocessing (e.g. from -dM). */ - if (out_fname[0] == '\0') - out_stream = stdout; - else - out_stream = fopen (out_fname, "w"); - - if (out_stream == NULL) - { - fatal_error ("opening output file %s: %m", out_fname); - return false; - } - - if (num_in_fnames > 1) - error ("too many filenames given. Type %s --help for usage", - progname); - - init_pp_output (out_stream); - } - else - { - init_c_lex (); - - /* Yuk. WTF is this? I do know ObjC relies on it somewhere. */ - input_location = UNKNOWN_LOCATION; - } - - cb = cpp_get_callbacks (parse_in); - cb->file_change = cb_file_change; - cb->dir_change = cb_dir_change; - cpp_post_options (parse_in); - - input_location = UNKNOWN_LOCATION; - - *pfilename = this_input_filename - = cpp_read_main_file (parse_in, in_fnames[0]); - /* Don't do any compilation or preprocessing if there is no input file. */ - if (this_input_filename == NULL) - { - errorcount++; - return false; - } - - if (flag_working_directory - && flag_preprocess_only && !flag_no_line_commands) - pp_dir_change (parse_in, get_src_pwd ()); - - return flag_preprocess_only; -} - -/* Front end initialization common to C, ObjC and C++. */ -bool -c_common_init (void) -{ - /* Set up preprocessor arithmetic. Must be done after call to - c_common_nodes_and_builtins for type nodes to be good. */ - cpp_opts->precision = TYPE_PRECISION (intmax_type_node); - cpp_opts->char_precision = TYPE_PRECISION (char_type_node); - cpp_opts->int_precision = TYPE_PRECISION (integer_type_node); - cpp_opts->wchar_precision = TYPE_PRECISION (wchar_type_node); - cpp_opts->unsigned_wchar = TYPE_UNSIGNED (wchar_type_node); - cpp_opts->bytes_big_endian = BYTES_BIG_ENDIAN; - - /* This can't happen until after wchar_precision and bytes_big_endian - are known. */ - cpp_init_iconv (parse_in); - - if (version_flag) - c_common_print_pch_checksum (stderr); - - /* Has to wait until now so that cpplib has its hash table. */ - init_pragma (); - - if (flag_preprocess_only) - { - finish_options (); - preprocess_file (parse_in); - return false; - } - - return true; -} - -/* Initialize the integrated preprocessor after debug output has been - initialized; loop over each input file. */ -void -c_common_parse_file (int set_yydebug) -{ - unsigned int i; - - if (set_yydebug) - switch (c_language) - { - case clk_c: - warning(0, "The C parser does not support -dy, option ignored"); - break; - case clk_objc: - warning(0, - "The Objective-C parser does not support -dy, option ignored"); - break; - case clk_cxx: - warning(0, "The C++ parser does not support -dy, option ignored"); - break; - case clk_objcxx: - warning(0, - "The Objective-C++ parser does not support -dy, option ignored"); - break; - default: - gcc_unreachable (); - } - - i = 0; - for (;;) - { - finish_options (); - pch_init (); - push_file_scope (); - c_parse_file (); - finish_file (); - pop_file_scope (); - /* And end the main input file, if the debug writer wants it */ - if (debug_hooks->start_end_main_source_file) - (*debug_hooks->end_source_file) (0); - if (++i >= num_in_fnames) - break; - cpp_undef_all (parse_in); - cpp_clear_file_cache (parse_in); - this_input_filename - = cpp_read_main_file (parse_in, in_fnames[i]); - /* If an input file is missing, abandon further compilation. - cpplib has issued a diagnostic. */ - if (!this_input_filename) - break; - } -} - -/* Common finish hook for the C, ObjC and C++ front ends. */ -void -c_common_finish (void) -{ - FILE *deps_stream = NULL; - - /* Don't write the deps file if there are errors. */ - if (cpp_opts->deps.style != DEPS_NONE && !seen_error ()) - { - /* If -M or -MM was seen without -MF, default output to the - output stream. */ - if (!deps_file) - deps_stream = out_stream; - else - { - deps_stream = fopen (deps_file, deps_append ? "a": "w"); - if (!deps_stream) - fatal_error ("opening dependency file %s: %m", deps_file); - } - } - - /* For performance, avoid tearing down cpplib's internal structures - with cpp_destroy (). */ - cpp_finish (parse_in, deps_stream); - - if (deps_stream && deps_stream != out_stream - && (ferror (deps_stream) || fclose (deps_stream))) - fatal_error ("closing dependency file %s: %m", deps_file); - - if (out_stream && (ferror (out_stream) || fclose (out_stream))) - fatal_error ("when writing output to %s: %m", out_fname); -} - -/* Either of two environment variables can specify output of - dependencies. Their value is either "OUTPUT_FILE" or "OUTPUT_FILE - DEPS_TARGET", where OUTPUT_FILE is the file to write deps info to - and DEPS_TARGET is the target to mention in the deps. They also - result in dependency information being appended to the output file - rather than overwriting it, and like Sun's compiler - SUNPRO_DEPENDENCIES suppresses the dependency on the main file. */ -static void -check_deps_environment_vars (void) -{ - char *spec; - - GET_ENVIRONMENT (spec, "DEPENDENCIES_OUTPUT"); - if (spec) - cpp_opts->deps.style = DEPS_USER; - else - { - GET_ENVIRONMENT (spec, "SUNPRO_DEPENDENCIES"); - if (spec) - { - cpp_opts->deps.style = DEPS_SYSTEM; - cpp_opts->deps.ignore_main_file = true; - } - } - - if (spec) - { - /* Find the space before the DEPS_TARGET, if there is one. */ - char *s = strchr (spec, ' '); - if (s) - { - /* Let the caller perform MAKE quoting. */ - defer_opt (OPT_MT, s + 1); - *s = '\0'; - } - - /* Command line -MF overrides environment variables and default. */ - if (!deps_file) - deps_file = spec; - - deps_append = 1; - deps_seen = true; - } -} - -/* Handle deferred command line switches. */ -static void -handle_deferred_opts (void) -{ - size_t i; - struct deps *deps; - - /* Avoid allocating the deps buffer if we don't need it. - (This flag may be true without there having been -MT or -MQ - options, but we'll still need the deps buffer.) */ - if (!deps_seen) - return; - - deps = cpp_get_deps (parse_in); - - for (i = 0; i < deferred_count; i++) - { - struct deferred_opt *opt = &deferred_opts[i]; - - if (opt->code == OPT_MT || opt->code == OPT_MQ) - deps_add_target (deps, opt->arg, opt->code == OPT_MQ); - } -} - -/* These settings are appropriate for GCC, but not necessarily so for - cpplib as a library. */ -static void -sanitize_cpp_opts (void) -{ - /* If we don't know what style of dependencies to output, complain - if any other dependency switches have been given. */ - if (deps_seen && cpp_opts->deps.style == DEPS_NONE) - error ("to generate dependencies you must specify either -M or -MM"); - - /* -dM and dependencies suppress normal output; do it here so that - the last -d[MDN] switch overrides earlier ones. */ - if (flag_dump_macros == 'M') - flag_no_output = 1; - - /* By default, -fdirectives-only implies -dD. This allows subsequent phases - to perform proper macro expansion. */ - if (cpp_opts->directives_only && !cpp_opts->preprocessed && !flag_dump_macros) - flag_dump_macros = 'D'; - - /* Disable -dD, -dN and -dI if normal output is suppressed. Allow - -dM since at least glibc relies on -M -dM to work. */ - /* Also, flag_no_output implies flag_no_line_commands, always. */ - if (flag_no_output) - { - if (flag_dump_macros != 'M') - flag_dump_macros = 0; - flag_dump_includes = 0; - flag_no_line_commands = 1; - } - else if (cpp_opts->deps.missing_files) - error ("-MG may only be used with -M or -MM"); - - cpp_opts->unsigned_char = !flag_signed_char; - cpp_opts->stdc_0_in_system_headers = STDC_0_IN_SYSTEM_HEADERS; - - /* Wlong-long is disabled by default. It is enabled by: - [-pedantic | -Wtraditional] -std=[gnu|c]++98 ; or - [-pedantic | -Wtraditional] -std=non-c99 . - - Either -Wlong-long or -Wno-long-long override any other settings. */ - if (warn_long_long == -1) - warn_long_long = ((pedantic || warn_traditional) - && (c_dialect_cxx () ? cxx_dialect == cxx98 : !flag_isoc99)); - cpp_opts->warn_long_long = warn_long_long; - - /* Similarly with -Wno-variadic-macros. No check for c99 here, since - this also turns off warnings about GCCs extension. */ - cpp_opts->warn_variadic_macros - = warn_variadic_macros && (pedantic || warn_traditional); - - /* If we're generating preprocessor output, emit current directory - if explicitly requested or if debugging information is enabled. - ??? Maybe we should only do it for debugging formats that - actually output the current directory? */ - if (flag_working_directory == -1) - flag_working_directory = (debug_info_level != DINFO_LEVEL_NONE); - - if (cpp_opts->directives_only) - { - if (warn_unused_macros) - error ("-fdirectives-only is incompatible with -Wunused_macros"); - if (cpp_opts->traditional) - error ("-fdirectives-only is incompatible with -traditional"); - } -} - -/* Add include path with a prefix at the front of its name. */ -static void -add_prefixed_path (const char *suffix, size_t chain) -{ - char *path; - const char *prefix; - size_t prefix_len, suffix_len; - - suffix_len = strlen (suffix); - prefix = iprefix ? iprefix : cpp_GCC_INCLUDE_DIR; - prefix_len = iprefix ? strlen (iprefix) : cpp_GCC_INCLUDE_DIR_len; - - path = (char *) xmalloc (prefix_len + suffix_len + 1); - memcpy (path, prefix, prefix_len); - memcpy (path + prefix_len, suffix, suffix_len); - path[prefix_len + suffix_len] = '\0'; - - add_path (path, chain, 0, false); -} - -/* Handle -D, -U, -A, -imacros, and the first -include. */ -static void -finish_options (void) -{ - if (!cpp_opts->preprocessed) - { - size_t i; - - cb_file_change (parse_in, - linemap_add (line_table, LC_RENAME, 0, - _(""), 0)); - - cpp_init_builtins (parse_in, flag_hosted); - c_cpp_builtins (parse_in); - - /* We're about to send user input to cpplib, so make it warn for - things that we previously (when we sent it internal definitions) - told it to not warn. - - C99 permits implementation-defined characters in identifiers. - The documented meaning of -std= is to turn off extensions that - conflict with the specified standard, and since a strictly - conforming program cannot contain a '$', we do not condition - their acceptance on the -std= setting. */ - cpp_opts->warn_dollars = (cpp_opts->pedantic && !cpp_opts->c99); - - cb_file_change (parse_in, - linemap_add (line_table, LC_RENAME, 0, - _(""), 0)); - - for (i = 0; i < deferred_count; i++) - { - struct deferred_opt *opt = &deferred_opts[i]; - - if (opt->code == OPT_D) - cpp_define (parse_in, opt->arg); - else if (opt->code == OPT_U) - cpp_undef (parse_in, opt->arg); - else if (opt->code == OPT_A) - { - if (opt->arg[0] == '-') - cpp_unassert (parse_in, opt->arg + 1); - else - cpp_assert (parse_in, opt->arg); - } - } - - /* Start the main input file, if the debug writer wants it. */ - if (debug_hooks->start_end_main_source_file - && !flag_preprocess_only) - (*debug_hooks->start_source_file) (0, this_input_filename); - - /* Handle -imacros after -D and -U. */ - for (i = 0; i < deferred_count; i++) - { - struct deferred_opt *opt = &deferred_opts[i]; - - if (opt->code == OPT_imacros - && cpp_push_include (parse_in, opt->arg)) - { - /* Disable push_command_line_include callback for now. */ - include_cursor = deferred_count + 1; - cpp_scan_nooutput (parse_in); - } - } - } - else - { - if (cpp_opts->directives_only) - cpp_init_special_builtins (parse_in); - - /* Start the main input file, if the debug writer wants it. */ - if (debug_hooks->start_end_main_source_file - && !flag_preprocess_only) - (*debug_hooks->start_source_file) (0, this_input_filename); - } - - include_cursor = 0; - push_command_line_include (); -} - -/* Give CPP the next file given by -include, if any. */ -static void -push_command_line_include (void) -{ - while (include_cursor < deferred_count) - { - struct deferred_opt *opt = &deferred_opts[include_cursor++]; - - if (!cpp_opts->preprocessed && opt->code == OPT_include - && cpp_push_include (parse_in, opt->arg)) - return; - } - - if (include_cursor == deferred_count) - { - include_cursor++; - /* -Wunused-macros should only warn about macros defined hereafter. */ - cpp_opts->warn_unused_macros = warn_unused_macros; - /* Restore the line map from . */ - if (!cpp_opts->preprocessed) - cpp_change_file (parse_in, LC_RENAME, this_input_filename); - - /* Set this here so the client can change the option if it wishes, - and after stacking the main file so we don't trace the main file. */ - line_table->trace_includes = cpp_opts->print_include_names; - } -} - -/* File change callback. Has to handle -include files. */ -static void -cb_file_change (cpp_reader * ARG_UNUSED (pfile), - const struct line_map *new_map) -{ - if (flag_preprocess_only) - pp_file_change (new_map); - else - fe_file_change (new_map); - - if (new_map == 0 || (new_map->reason == LC_LEAVE && MAIN_FILE_P (new_map))) - push_command_line_include (); -} - -void -cb_dir_change (cpp_reader * ARG_UNUSED (pfile), const char *dir) -{ - if (!set_src_pwd (dir)) - warning (0, "too late for # directive to set debug directory"); -} - -/* Set the C 89 standard (with 1994 amendments if C94, without GNU - extensions if ISO). There is no concept of gnu94. */ -static void -set_std_c89 (int c94, int iso) -{ - cpp_set_lang (parse_in, c94 ? CLK_STDC94: iso ? CLK_STDC89: CLK_GNUC89); - flag_iso = iso; - flag_no_asm = iso; - flag_no_gnu_keywords = iso; - flag_no_nonansi_builtin = iso; - flag_isoc94 = c94; - flag_isoc99 = 0; - flag_isoc1x = 0; -} - -/* Set the C 99 standard (without GNU extensions if ISO). */ -static void -set_std_c99 (int iso) -{ - cpp_set_lang (parse_in, iso ? CLK_STDC99: CLK_GNUC99); - flag_no_asm = iso; - flag_no_nonansi_builtin = iso; - flag_iso = iso; - flag_isoc1x = 0; - flag_isoc99 = 1; - flag_isoc94 = 1; -} - -/* Set the C 1X standard draft (without GNU extensions if ISO). */ -static void -set_std_c1x (int iso) -{ - cpp_set_lang (parse_in, iso ? CLK_STDC1X: CLK_GNUC1X); - flag_no_asm = iso; - flag_no_nonansi_builtin = iso; - flag_iso = iso; - flag_isoc1x = 1; - flag_isoc99 = 1; - flag_isoc94 = 1; -} - -/* Set the C++ 98 standard (without GNU extensions if ISO). */ -static void -set_std_cxx98 (int iso) -{ - cpp_set_lang (parse_in, iso ? CLK_CXX98: CLK_GNUCXX); - flag_no_gnu_keywords = iso; - flag_no_nonansi_builtin = iso; - flag_iso = iso; - cxx_dialect = cxx98; -} - -/* Set the C++ 0x working draft "standard" (without GNU extensions if ISO). */ -static void -set_std_cxx0x (int iso) -{ - cpp_set_lang (parse_in, iso ? CLK_CXX0X: CLK_GNUCXX0X); - flag_no_gnu_keywords = iso; - flag_no_nonansi_builtin = iso; - flag_iso = iso; - cxx_dialect = cxx0x; -} - -/* Args to -d specify what to dump. Silently ignore - unrecognized options; they may be aimed at toplev.c. */ -static void -handle_OPT_d (const char *arg) -{ - char c; - - while ((c = *arg++) != '\0') - switch (c) - { - case 'M': /* Dump macros only. */ - case 'N': /* Dump names. */ - case 'D': /* Dump definitions. */ - case 'U': /* Dump used macros. */ - flag_dump_macros = c; - break; - - case 'I': - flag_dump_includes = 1; - break; - } -} diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 21f5675..56d5d83 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -46,13 +46,13 @@ along with GCC; see the file COPYING3. If not see #include "input.h" #include "cpplib.h" #include "timevar.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" #include "c-tree.h" #include "flags.h" #include "output.h" #include "toplev.h" #include "ggc.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "vec.h" #include "target.h" #include "cgraph.h" diff --git a/gcc/c-pch.c b/gcc/c-pch.c deleted file mode 100644 index 951ab1f..0000000 --- a/gcc/c-pch.c +++ /dev/null @@ -1,517 +0,0 @@ -/* Precompiled header implementation for the C languages. - Copyright (C) 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 - 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 "version.h" -#include "cpplib.h" -#include "tree.h" -#include "flags.h" -#include "c-common.h" -#include "output.h" -#include "toplev.h" -#include "debug.h" -#include "c-pragma.h" -#include "ggc.h" -#include "langhooks.h" -#include "hosthooks.h" -#include "target.h" -#include "opts.h" -#include "timevar.h" - -/* This is a list of flag variables that must match exactly, and their - names for the error message. The possible values for *flag_var must - fit in a 'signed char'. */ - -static const struct c_pch_matching -{ - int *flag_var; - const char *flag_name; -} pch_matching[] = { - { &flag_exceptions, "-fexceptions" }, -}; - -enum { - MATCH_SIZE = ARRAY_SIZE (pch_matching) -}; - -/* The value of the checksum in the dummy compiler that is actually - checksummed. That compiler should never be run. */ -static const char no_checksum[16] = { 0 }; - -/* Information about flags and suchlike that affect PCH validity. - - Before this structure is read, both an initial 8-character identification - string, and a 16-byte checksum, have been read and validated. */ - -struct c_pch_validity -{ - unsigned char debug_info_type; - signed char match[MATCH_SIZE]; - void (*pch_init) (void); - size_t target_data_length; -}; - -struct c_pch_header -{ - unsigned long asm_size; -}; - -#define IDENT_LENGTH 8 - -/* The file we'll be writing the PCH to. */ -static FILE *pch_outfile; - -/* The position in the assembler output file when pch_init was called. */ -static long asm_file_startpos; - -static const char *get_ident (void); - -/* Compute an appropriate 8-byte magic number for the PCH file, so that - utilities like file(1) can identify it, and so that GCC can quickly - ignore non-PCH files and PCH files that are of a completely different - format. */ - -static const char * -get_ident (void) -{ - static char result[IDENT_LENGTH]; - static const char templ[] = "gpch.013"; - static const char c_language_chars[] = "Co+O"; - - memcpy (result, templ, IDENT_LENGTH); - result[4] = c_language_chars[c_language]; - - return result; -} - -/* Prepare to write a PCH file, if one is being written. This is - called at the start of compilation. - - Also, print out the executable checksum if -fverbose-asm is in effect. */ - -void -pch_init (void) -{ - FILE *f; - struct c_pch_validity v; - void *target_validity; - static const char partial_pch[] = "gpcWrite"; - -#ifdef ASM_COMMENT_START - if (flag_verbose_asm) - { - fprintf (asm_out_file, "%s ", ASM_COMMENT_START); - c_common_print_pch_checksum (asm_out_file); - fputc ('\n', asm_out_file); - } -#endif - - if (!pch_file) - return; - - f = fopen (pch_file, "w+b"); - if (f == NULL) - fatal_error ("can%'t create precompiled header %s: %m", pch_file); - pch_outfile = f; - - gcc_assert (memcmp (executable_checksum, no_checksum, 16) != 0); - - memset (&v, '\0', sizeof (v)); - v.debug_info_type = write_symbols; - { - size_t i; - for (i = 0; i < MATCH_SIZE; i++) - { - v.match[i] = *pch_matching[i].flag_var; - gcc_assert (v.match[i] == *pch_matching[i].flag_var); - } - } - v.pch_init = &pch_init; - target_validity = targetm.get_pch_validity (&v.target_data_length); - - if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1 - || fwrite (executable_checksum, 16, 1, f) != 1 - || fwrite (&v, sizeof (v), 1, f) != 1 - || fwrite (target_validity, v.target_data_length, 1, f) != 1) - fatal_error ("can%'t write to %s: %m", pch_file); - - /* We need to be able to re-read the output. */ - /* The driver always provides a valid -o option. */ - if (asm_file_name == NULL - || strcmp (asm_file_name, "-") == 0) - fatal_error ("%qs is not a valid output file", asm_file_name); - - asm_file_startpos = ftell (asm_out_file); - - /* Let the debugging format deal with the PCHness. */ - (*debug_hooks->handle_pch) (0); - - cpp_save_state (parse_in, f); -} - -/* Write the PCH file. This is called at the end of a compilation which - will produce a PCH file. */ - -void -c_common_write_pch (void) -{ - char *buf; - long asm_file_end; - long written; - struct c_pch_header h; - - timevar_push (TV_PCH_SAVE); - - (*debug_hooks->handle_pch) (1); - - cpp_write_pch_deps (parse_in, pch_outfile); - - asm_file_end = ftell (asm_out_file); - h.asm_size = asm_file_end - asm_file_startpos; - - if (fwrite (&h, sizeof (h), 1, pch_outfile) != 1) - fatal_error ("can%'t write %s: %m", pch_file); - - buf = XNEWVEC (char, 16384); - - if (fseek (asm_out_file, asm_file_startpos, SEEK_SET) != 0) - fatal_error ("can%'t seek in %s: %m", asm_file_name); - - for (written = asm_file_startpos; written < asm_file_end; ) - { - long size = asm_file_end - written; - if (size > 16384) - size = 16384; - if (fread (buf, size, 1, asm_out_file) != 1) - fatal_error ("can%'t read %s: %m", asm_file_name); - if (fwrite (buf, size, 1, pch_outfile) != 1) - fatal_error ("can%'t write %s: %m", pch_file); - written += size; - } - free (buf); - /* asm_out_file can be written afterwards, so fseek to clear - _IOREAD flag. */ - if (fseek (asm_out_file, 0, SEEK_END) != 0) - fatal_error ("can%'t seek in %s: %m", asm_file_name); - - gt_pch_save (pch_outfile); - - timevar_push (TV_PCH_CPP_SAVE); - cpp_write_pch_state (parse_in, pch_outfile); - timevar_pop (TV_PCH_CPP_SAVE); - - if (fseek (pch_outfile, 0, SEEK_SET) != 0 - || fwrite (get_ident (), IDENT_LENGTH, 1, pch_outfile) != 1) - fatal_error ("can%'t write %s: %m", pch_file); - - fclose (pch_outfile); - - timevar_pop (TV_PCH_SAVE); -} - -/* Check the PCH file called NAME, open on FD, to see if it can be - used in this compilation. Return 1 if valid, 0 if the file can't - be used now but might be if it's seen later in the compilation, and - 2 if this file could never be used in the compilation. */ - -int -c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) -{ - int sizeread; - int result; - char ident[IDENT_LENGTH + 16]; - const char *pch_ident; - struct c_pch_validity v; - - /* Perform a quick test of whether this is a valid - precompiled header for the current language. */ - - gcc_assert (memcmp (executable_checksum, no_checksum, 16) != 0); - - sizeread = read (fd, ident, IDENT_LENGTH + 16); - if (sizeread == -1) - fatal_error ("can%'t read %s: %m", name); - else if (sizeread != IDENT_LENGTH + 16) - { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, "%s: too short to be a PCH file", - name); - return 2; - } - - pch_ident = get_ident(); - if (memcmp (ident, pch_ident, IDENT_LENGTH) != 0) - { - if (cpp_get_options (pfile)->warn_invalid_pch) - { - if (memcmp (ident, pch_ident, 5) == 0) - /* It's a PCH, for the right language, but has the wrong version. - */ - cpp_error (pfile, CPP_DL_WARNING, - "%s: not compatible with this GCC version", name); - else if (memcmp (ident, pch_ident, 4) == 0) - /* It's a PCH for the wrong language. */ - cpp_error (pfile, CPP_DL_WARNING, "%s: not for %s", name, - lang_hooks.name); - else - /* Not any kind of PCH. */ - cpp_error (pfile, CPP_DL_WARNING, "%s: not a PCH file", name); - } - return 2; - } - if (memcmp (ident + IDENT_LENGTH, executable_checksum, 16) != 0) - { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, - "%s: created by a different GCC executable", name); - return 2; - } - - /* At this point, we know it's a PCH file created by this - executable, so it ought to be long enough that we can read a - c_pch_validity structure. */ - if (read (fd, &v, sizeof (v)) != sizeof (v)) - fatal_error ("can%'t read %s: %m", name); - - /* The allowable debug info combinations are that either the PCH file - was built with the same as is being used now, or the PCH file was - built for some kind of debug info but now none is in use. */ - if (v.debug_info_type != write_symbols - && write_symbols != NO_DEBUG) - { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, - "%s: created with -g%s, but used with -g%s", name, - debug_type_names[v.debug_info_type], - debug_type_names[write_symbols]); - return 2; - } - - /* Check flags that must match exactly. */ - { - size_t i; - for (i = 0; i < MATCH_SIZE; i++) - if (*pch_matching[i].flag_var != v.match[i]) - { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, - "%s: settings for %s do not match", name, - pch_matching[i].flag_name); - return 2; - } - } - - /* If the text segment was not loaded at the same address as it was - when the PCH file was created, function pointers loaded from the - PCH will not be valid. We could in theory remap all the function - pointers, but no support for that exists at present. - Since we have the same executable, it should only be necessary to - check one function. */ - if (v.pch_init != &pch_init) - { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, - "%s: had text segment at different address", name); - return 2; - } - - /* Check the target-specific validity data. */ - { - void *this_file_data = xmalloc (v.target_data_length); - const char *msg; - - if ((size_t) read (fd, this_file_data, v.target_data_length) - != v.target_data_length) - fatal_error ("can%'t read %s: %m", name); - msg = targetm.pch_valid_p (this_file_data, v.target_data_length); - free (this_file_data); - if (msg != NULL) - { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, "%s: %s", name, msg); - return 2; - } - } - - /* Check the preprocessor macros are the same as when the PCH was - generated. */ - - result = cpp_valid_state (pfile, name, fd); - if (result == -1) - return 2; - else - return result == 0; -} - -/* If non-NULL, this function is called after a precompile header file - is loaded. */ -void (*lang_post_pch_load) (void); - -/* Load in the PCH file NAME, open on FD. It was originally searched for - by ORIG_NAME. */ - -void -c_common_read_pch (cpp_reader *pfile, const char *name, - int fd, const char *orig_name ATTRIBUTE_UNUSED) -{ - FILE *f; - struct c_pch_header h; - struct save_macro_data *smd; - expanded_location saved_loc; - bool saved_trace_includes; - - timevar_push (TV_PCH_RESTORE); - - f = fdopen (fd, "rb"); - if (f == NULL) - { - cpp_errno (pfile, CPP_DL_ERROR, "calling fdopen"); - close (fd); - goto end; - } - - cpp_get_callbacks (parse_in)->valid_pch = NULL; - - if (fread (&h, sizeof (h), 1, f) != 1) - { - cpp_errno (pfile, CPP_DL_ERROR, "reading"); - fclose (f); - goto end; - } - - if (!flag_preprocess_only) - { - unsigned long written; - char * buf = XNEWVEC (char, 16384); - - for (written = 0; written < h.asm_size; ) - { - long size = h.asm_size - written; - if (size > 16384) - size = 16384; - if (fread (buf, size, 1, f) != 1 - || fwrite (buf, size, 1, asm_out_file) != 1) - cpp_errno (pfile, CPP_DL_ERROR, "reading"); - written += size; - } - free (buf); - } - else - { - /* If we're preprocessing, don't write to a NULL - asm_out_file. */ - if (fseek (f, h.asm_size, SEEK_CUR) != 0) - cpp_errno (pfile, CPP_DL_ERROR, "seeking"); - } - - /* Save the location and then restore it after reading the PCH. */ - saved_loc = expand_location (line_table->highest_line); - saved_trace_includes = line_table->trace_includes; - - timevar_push (TV_PCH_CPP_RESTORE); - cpp_prepare_state (pfile, &smd); - timevar_pop (TV_PCH_CPP_RESTORE); - - gt_pch_restore (f); - - timevar_push (TV_PCH_CPP_RESTORE); - if (cpp_read_state (pfile, name, f, smd) != 0) - { - fclose (f); - timevar_pop (TV_PCH_CPP_RESTORE); - goto end; - } - timevar_pop (TV_PCH_CPP_RESTORE); - - - fclose (f); - - line_table->trace_includes = saved_trace_includes; - cpp_set_line_map (pfile, line_table); - linemap_add (line_table, LC_RENAME, 0, saved_loc.file, saved_loc.line); - - /* Give the front end a chance to take action after a PCH file has - been loaded. */ - if (lang_post_pch_load) - (*lang_post_pch_load) (); - -end: - timevar_pop (TV_PCH_RESTORE); -} - -/* Indicate that no more PCH files should be read. */ - -void -c_common_no_more_pch (void) -{ - if (cpp_get_callbacks (parse_in)->valid_pch) - { - cpp_get_callbacks (parse_in)->valid_pch = NULL; - host_hooks.gt_pch_use_address (NULL, 0, -1, 0); - } -} - -/* Handle #pragma GCC pch_preprocess, to load in the PCH file. */ - -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -void -c_common_pch_pragma (cpp_reader *pfile, const char *name) -{ - int fd; - - if (!cpp_get_options (pfile)->preprocessed) - { - error ("pch_preprocess pragma should only be used with -fpreprocessed"); - inform (input_location, "use #include instead"); - return; - } - - fd = open (name, O_RDONLY | O_BINARY, 0666); - if (fd == -1) - fatal_error ("%s: couldn%'t open PCH file: %m", name); - - if (c_common_valid_pch (pfile, name, fd) != 1) - { - if (!cpp_get_options (pfile)->warn_invalid_pch) - inform (input_location, "use -Winvalid-pch for more information"); - fatal_error ("%s: PCH file was invalid", name); - } - - c_common_read_pch (pfile, name, fd, name); - - close (fd); -} - -/* Print out executable_checksum[]. */ - -void -c_common_print_pch_checksum (FILE *f) -{ - int i; - fputs ("Compiler executable checksum: ", f); - for (i = 0; i < 16; i++) - fprintf (f, "%02x", executable_checksum[i]); - putc ('\n', f); -} diff --git a/gcc/c-ppoutput.c b/gcc/c-ppoutput.c deleted file mode 100644 index 1700fae..0000000 --- a/gcc/c-ppoutput.c +++ /dev/null @@ -1,625 +0,0 @@ -/* Preprocess only, using cpplib. - Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007, - 2008, 2009 Free Software Foundation, Inc. - Written by Per Bothner, 1994-95. - - This program 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. - - This program 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 this program; see the file COPYING3. If not see - . */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "cpplib.h" -#include "../libcpp/internal.h" -#include "tree.h" -#include "c-common.h" /* For flags. */ -#include "c-pragma.h" /* For parse_in. */ - -/* Encapsulates state used to convert a stream of tokens into a text - file. */ -static struct -{ - FILE *outf; /* Stream to write to. */ - const cpp_token *prev; /* Previous token. */ - const cpp_token *source; /* Source token for spacing. */ - int src_line; /* Line number currently being written. */ - unsigned char printed; /* Nonzero if something output at line. */ - bool first_time; /* pp_file_change hasn't been called yet. */ -} print; - -/* Defined and undefined macros being queued for output with -dU at - the next newline. */ -typedef struct macro_queue -{ - struct macro_queue *next; /* Next macro in the list. */ - char *macro; /* The name of the macro if not - defined, the full definition if - defined. */ -} macro_queue; -static macro_queue *define_queue, *undef_queue; - -/* General output routines. */ -static void scan_translation_unit (cpp_reader *); -static void print_lines_directives_only (int, const void *, size_t); -static void scan_translation_unit_directives_only (cpp_reader *); -static void scan_translation_unit_trad (cpp_reader *); -static void account_for_newlines (const unsigned char *, size_t); -static int dump_macro (cpp_reader *, cpp_hashnode *, void *); -static void dump_queued_macros (cpp_reader *); - -static void print_line (source_location, const char *); -static void maybe_print_line (source_location); -static void do_line_change (cpp_reader *, const cpp_token *, - source_location, int); - -/* Callback routines for the parser. Most of these are active only - in specific modes. */ -static void cb_line_change (cpp_reader *, const cpp_token *, int); -static void cb_define (cpp_reader *, source_location, cpp_hashnode *); -static void cb_undef (cpp_reader *, source_location, cpp_hashnode *); -static void cb_used_define (cpp_reader *, source_location, cpp_hashnode *); -static void cb_used_undef (cpp_reader *, source_location, cpp_hashnode *); -static void cb_include (cpp_reader *, source_location, const unsigned char *, - const char *, int, const cpp_token **); -static void cb_ident (cpp_reader *, source_location, const cpp_string *); -static void cb_def_pragma (cpp_reader *, source_location); -static void cb_read_pch (cpp_reader *pfile, const char *name, - int fd, const char *orig_name); - -/* Preprocess and output. */ -void -preprocess_file (cpp_reader *pfile) -{ - /* A successful cpp_read_main_file guarantees that we can call - cpp_scan_nooutput or cpp_get_token next. */ - if (flag_no_output) - { - /* Scan -included buffers, then the main file. */ - while (pfile->buffer->prev) - cpp_scan_nooutput (pfile); - cpp_scan_nooutput (pfile); - } - else if (cpp_get_options (pfile)->traditional) - scan_translation_unit_trad (pfile); - else if (cpp_get_options (pfile)->directives_only - && !cpp_get_options (pfile)->preprocessed) - scan_translation_unit_directives_only (pfile); - else - scan_translation_unit (pfile); - - /* -dM command line option. Should this be elsewhere? */ - if (flag_dump_macros == 'M') - cpp_forall_identifiers (pfile, dump_macro, NULL); - - /* Flush any pending output. */ - if (print.printed) - putc ('\n', print.outf); -} - -/* Set up the callbacks as appropriate. */ -void -init_pp_output (FILE *out_stream) -{ - cpp_callbacks *cb = cpp_get_callbacks (parse_in); - - if (!flag_no_output) - { - cb->line_change = cb_line_change; - /* Don't emit #pragma or #ident directives if we are processing - assembly language; the assembler may choke on them. */ - if (cpp_get_options (parse_in)->lang != CLK_ASM) - { - cb->ident = cb_ident; - cb->def_pragma = cb_def_pragma; - } - } - - if (flag_dump_includes) - cb->include = cb_include; - - if (flag_pch_preprocess) - { - cb->valid_pch = c_common_valid_pch; - cb->read_pch = cb_read_pch; - } - - if (flag_dump_macros == 'N' || flag_dump_macros == 'D') - { - cb->define = cb_define; - cb->undef = cb_undef; - } - - if (flag_dump_macros == 'U') - { - cb->before_define = dump_queued_macros; - cb->used_define = cb_used_define; - cb->used_undef = cb_used_undef; - } - - /* Initialize the print structure. */ - print.src_line = 1; - print.printed = 0; - print.prev = 0; - print.outf = out_stream; - print.first_time = 1; -} - -/* Writes out the preprocessed file, handling spacing and paste - avoidance issues. */ -static void -scan_translation_unit (cpp_reader *pfile) -{ - bool avoid_paste = false; - bool do_line_adjustments - = cpp_get_options (parse_in)->lang != CLK_ASM - && !flag_no_line_commands; - bool in_pragma = false; - - print.source = NULL; - for (;;) - { - source_location loc; - const cpp_token *token = cpp_get_token_with_location (pfile, &loc); - - if (token->type == CPP_PADDING) - { - avoid_paste = true; - if (print.source == NULL - || (!(print.source->flags & PREV_WHITE) - && token->val.source == NULL)) - print.source = token->val.source; - continue; - } - - if (token->type == CPP_EOF) - break; - - /* Subtle logic to output a space if and only if necessary. */ - if (avoid_paste) - { - const struct line_map *map - = linemap_lookup (line_table, loc); - int src_line = SOURCE_LINE (map, loc); - - if (print.source == NULL) - print.source = token; - - if (src_line != print.src_line - && do_line_adjustments - && !in_pragma) - { - do_line_change (pfile, token, loc, false); - putc (' ', print.outf); - } - else if (print.source->flags & PREV_WHITE - || (print.prev - && cpp_avoid_paste (pfile, print.prev, token)) - || (print.prev == NULL && token->type == CPP_HASH)) - putc (' ', print.outf); - } - else if (token->flags & PREV_WHITE) - { - const struct line_map *map - = linemap_lookup (line_table, loc); - int src_line = SOURCE_LINE (map, loc); - - if (src_line != print.src_line - && do_line_adjustments - && !in_pragma) - do_line_change (pfile, token, loc, false); - putc (' ', print.outf); - } - - avoid_paste = false; - print.source = NULL; - print.prev = token; - if (token->type == CPP_PRAGMA) - { - const char *space; - const char *name; - - maybe_print_line (token->src_loc); - fputs ("#pragma ", print.outf); - c_pp_lookup_pragma (token->val.pragma, &space, &name); - if (space) - fprintf (print.outf, "%s %s", space, name); - else - fprintf (print.outf, "%s", name); - print.printed = 1; - in_pragma = true; - } - else if (token->type == CPP_PRAGMA_EOL) - { - maybe_print_line (token->src_loc); - in_pragma = false; - } - else - cpp_output_token (token, print.outf); - - if (token->type == CPP_COMMENT) - account_for_newlines (token->val.str.text, token->val.str.len); - } -} - -static void -print_lines_directives_only (int lines, const void *buf, size_t size) -{ - print.src_line += lines; - fwrite (buf, 1, size, print.outf); -} - -/* Writes out the preprocessed file, handling spacing and paste - avoidance issues. */ -static void -scan_translation_unit_directives_only (cpp_reader *pfile) -{ - struct _cpp_dir_only_callbacks cb; - - cb.print_lines = print_lines_directives_only; - cb.maybe_print_line = maybe_print_line; - - _cpp_preprocess_dir_only (pfile, &cb); -} - -/* Adjust print.src_line for newlines embedded in output. */ -static void -account_for_newlines (const unsigned char *str, size_t len) -{ - while (len--) - if (*str++ == '\n') - print.src_line++; -} - -/* Writes out a traditionally preprocessed file. */ -static void -scan_translation_unit_trad (cpp_reader *pfile) -{ - while (_cpp_read_logical_line_trad (pfile)) - { - size_t len = pfile->out.cur - pfile->out.base; - maybe_print_line (pfile->out.first_line); - fwrite (pfile->out.base, 1, len, print.outf); - print.printed = 1; - if (!CPP_OPTION (pfile, discard_comments)) - account_for_newlines (pfile->out.base, len); - } -} - -/* If the token read on logical line LINE needs to be output on a - different line to the current one, output the required newlines or - a line marker, and return 1. Otherwise return 0. */ -static void -maybe_print_line (source_location src_loc) -{ - const struct line_map *map = linemap_lookup (line_table, src_loc); - int src_line = SOURCE_LINE (map, src_loc); - /* End the previous line of text. */ - if (print.printed) - { - putc ('\n', print.outf); - print.src_line++; - print.printed = 0; - } - - if (src_line >= print.src_line && src_line < print.src_line + 8) - { - while (src_line > print.src_line) - { - putc ('\n', print.outf); - print.src_line++; - } - } - else - print_line (src_loc, ""); -} - -/* Output a line marker for logical line LINE. Special flags are "1" - or "2" indicating entering or leaving a file. */ -static void -print_line (source_location src_loc, const char *special_flags) -{ - /* End any previous line of text. */ - if (print.printed) - putc ('\n', print.outf); - print.printed = 0; - - if (!flag_no_line_commands) - { - const struct line_map *map = linemap_lookup (line_table, src_loc); - - size_t to_file_len = strlen (map->to_file); - unsigned char *to_file_quoted = - (unsigned char *) alloca (to_file_len * 4 + 1); - unsigned char *p; - - print.src_line = SOURCE_LINE (map, src_loc); - - /* cpp_quote_string does not nul-terminate, so we have to do it - ourselves. */ - p = cpp_quote_string (to_file_quoted, - (const unsigned char *) map->to_file, to_file_len); - *p = '\0'; - fprintf (print.outf, "# %u \"%s\"%s", - print.src_line == 0 ? 1 : print.src_line, - to_file_quoted, special_flags); - - if (map->sysp == 2) - fputs (" 3 4", print.outf); - else if (map->sysp == 1) - fputs (" 3", print.outf); - - putc ('\n', print.outf); - } -} - -/* Helper function for cb_line_change and scan_translation_unit. */ -static void -do_line_change (cpp_reader *pfile, const cpp_token *token, - source_location src_loc, int parsing_args) -{ - if (define_queue || undef_queue) - dump_queued_macros (pfile); - - if (token->type == CPP_EOF || parsing_args) - return; - - maybe_print_line (src_loc); - print.prev = 0; - print.source = 0; - - /* Supply enough spaces to put this token in its original column, - one space per column greater than 2, since scan_translation_unit - will provide a space if PREV_WHITE. Don't bother trying to - reconstruct tabs; we can't get it right in general, and nothing - ought to care. Some things do care; the fault lies with them. */ - if (!CPP_OPTION (pfile, traditional)) - { - const struct line_map *map = linemap_lookup (line_table, src_loc); - int spaces = SOURCE_COLUMN (map, src_loc) - 2; - print.printed = 1; - - while (-- spaces >= 0) - putc (' ', print.outf); - } -} - -/* Called when a line of output is started. TOKEN is the first token - of the line, and at end of file will be CPP_EOF. */ -static void -cb_line_change (cpp_reader *pfile, const cpp_token *token, - int parsing_args) -{ - do_line_change (pfile, token, token->src_loc, parsing_args); -} - -static void -cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line, - const cpp_string *str) -{ - maybe_print_line (line); - fprintf (print.outf, "#ident %s\n", str->text); - print.src_line++; -} - -static void -cb_define (cpp_reader *pfile, source_location line, cpp_hashnode *node) -{ - maybe_print_line (line); - fputs ("#define ", print.outf); - - /* 'D' is whole definition; 'N' is name only. */ - if (flag_dump_macros == 'D') - fputs ((const char *) cpp_macro_definition (pfile, node), - print.outf); - else - fputs ((const char *) NODE_NAME (node), print.outf); - - putc ('\n', print.outf); - if (linemap_lookup (line_table, line)->to_line != 0) - print.src_line++; -} - -static void -cb_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line, - cpp_hashnode *node) -{ - maybe_print_line (line); - fprintf (print.outf, "#undef %s\n", NODE_NAME (node)); - print.src_line++; -} - -static void -cb_used_define (cpp_reader *pfile, source_location line ATTRIBUTE_UNUSED, - cpp_hashnode *node) -{ - macro_queue *q; - if (node->flags & NODE_BUILTIN) - return; - q = XNEW (macro_queue); - q->macro = xstrdup ((const char *) cpp_macro_definition (pfile, node)); - q->next = define_queue; - define_queue = q; -} - -static void -cb_used_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, - source_location line ATTRIBUTE_UNUSED, - cpp_hashnode *node) -{ - macro_queue *q; - q = XNEW (macro_queue); - q->macro = xstrdup ((const char *) NODE_NAME (node)); - q->next = undef_queue; - undef_queue = q; -} - -static void -dump_queued_macros (cpp_reader *pfile ATTRIBUTE_UNUSED) -{ - macro_queue *q; - - /* End the previous line of text. */ - if (print.printed) - { - putc ('\n', print.outf); - print.src_line++; - print.printed = 0; - } - - for (q = define_queue; q;) - { - macro_queue *oq; - fputs ("#define ", print.outf); - fputs (q->macro, print.outf); - putc ('\n', print.outf); - print.src_line++; - oq = q; - q = q->next; - free (oq->macro); - free (oq); - } - define_queue = NULL; - for (q = undef_queue; q;) - { - macro_queue *oq; - fprintf (print.outf, "#undef %s\n", q->macro); - print.src_line++; - oq = q; - q = q->next; - free (oq->macro); - free (oq); - } - undef_queue = NULL; -} - -static void -cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line, - const unsigned char *dir, const char *header, int angle_brackets, - const cpp_token **comments) -{ - maybe_print_line (line); - if (angle_brackets) - fprintf (print.outf, "#%s <%s>", dir, header); - else - fprintf (print.outf, "#%s \"%s\"", dir, header); - - if (comments != NULL) - { - while (*comments != NULL) - { - if ((*comments)->flags & PREV_WHITE) - putc (' ', print.outf); - cpp_output_token (*comments, print.outf); - ++comments; - } - } - - putc ('\n', print.outf); - print.src_line++; -} - -/* Callback called when -fworking-director and -E to emit working - directory in cpp output file. */ - -void -pp_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir) -{ - size_t to_file_len = strlen (dir); - unsigned char *to_file_quoted = - (unsigned char *) alloca (to_file_len * 4 + 1); - unsigned char *p; - - /* cpp_quote_string does not nul-terminate, so we have to do it ourselves. */ - p = cpp_quote_string (to_file_quoted, (const unsigned char *) dir, to_file_len); - *p = '\0'; - fprintf (print.outf, "# 1 \"%s//\"\n", to_file_quoted); -} - -/* The file name, line number or system header flags have changed, as - described in MAP. */ - -void -pp_file_change (const struct line_map *map) -{ - const char *flags = ""; - - if (flag_no_line_commands) - return; - - if (map != NULL) - { - input_location = map->start_location; - if (print.first_time) - { - /* Avoid printing foo.i when the main file is foo.c. */ - if (!cpp_get_options (parse_in)->preprocessed) - print_line (map->start_location, flags); - print.first_time = 0; - } - else - { - /* Bring current file to correct line when entering a new file. */ - if (map->reason == LC_ENTER) - { - const struct line_map *from = INCLUDED_FROM (line_table, map); - maybe_print_line (LAST_SOURCE_LINE_LOCATION (from)); - } - if (map->reason == LC_ENTER) - flags = " 1"; - else if (map->reason == LC_LEAVE) - flags = " 2"; - print_line (map->start_location, flags); - } - } -} - -/* Copy a #pragma directive to the preprocessed output. */ -static void -cb_def_pragma (cpp_reader *pfile, source_location line) -{ - maybe_print_line (line); - fputs ("#pragma ", print.outf); - cpp_output_line (pfile, print.outf); - print.src_line++; -} - -/* Dump out the hash table. */ -static int -dump_macro (cpp_reader *pfile, cpp_hashnode *node, void *v ATTRIBUTE_UNUSED) -{ - if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)) - { - fputs ("#define ", print.outf); - fputs ((const char *) cpp_macro_definition (pfile, node), - print.outf); - putc ('\n', print.outf); - print.src_line++; - } - - return 1; -} - -/* Load in the PCH file NAME, open on FD. It was originally searched for - by ORIG_NAME. Also, print out a #include command so that the PCH - file can be loaded when the preprocessed output is compiled. */ - -static void -cb_read_pch (cpp_reader *pfile, const char *name, - int fd, const char *orig_name ATTRIBUTE_UNUSED) -{ - c_common_read_pch (pfile, name, fd, orig_name); - - fprintf (print.outf, "#pragma GCC pch_preprocess \"%s\"\n", name); - print.src_line++; -} diff --git a/gcc/c-pragma.c b/gcc/c-pragma.c deleted file mode 100644 index 526d5fd..0000000 --- a/gcc/c-pragma.c +++ /dev/null @@ -1,1336 +0,0 @@ -/* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack. - Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007, 2008 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 "tree.h" -#include "function.h" /* For cfun. FIXME: Does the parser know - when it is inside a function, so that - we don't have to look at cfun? */ -#include "cpplib.h" -#include "c-pragma.h" -#include "flags.h" -#include "toplev.h" -#include "c-common.h" -#include "output.h" -#include "tm_p.h" /* For REGISTER_TARGET_PRAGMAS (why is - this not a target hook?). */ -#include "vec.h" -#include "vecprim.h" -#include "target.h" -#include "diagnostic.h" -#include "opts.h" -#include "plugin.h" - -#define GCC_BAD(gmsgid) \ - do { warning (OPT_Wpragmas, gmsgid); return; } while (0) -#define GCC_BAD2(gmsgid, arg) \ - do { warning (OPT_Wpragmas, gmsgid, arg); return; } while (0) - -typedef struct GTY(()) align_stack { - int alignment; - tree id; - struct align_stack * prev; -} align_stack; - -static GTY(()) struct align_stack * alignment_stack; - -#ifdef HANDLE_PRAGMA_PACK -static void handle_pragma_pack (cpp_reader *); - -#ifdef HANDLE_PRAGMA_PACK_PUSH_POP -/* If we have a "global" #pragma pack() in effect when the first - #pragma pack(push,) is encountered, this stores the value of - maximum_field_alignment in effect. When the final pop_alignment() - happens, we restore the value to this, not to a value of 0 for - maximum_field_alignment. Value is in bits. */ -static int default_alignment; -#define SET_GLOBAL_ALIGNMENT(ALIGN) (maximum_field_alignment = *(alignment_stack == NULL \ - ? &default_alignment \ - : &alignment_stack->alignment) = (ALIGN)) - -static void push_alignment (int, tree); -static void pop_alignment (tree); - -/* Push an alignment value onto the stack. */ -static void -push_alignment (int alignment, tree id) -{ - align_stack * entry; - - entry = GGC_NEW (align_stack); - - entry->alignment = alignment; - entry->id = id; - entry->prev = alignment_stack; - - /* The current value of maximum_field_alignment is not necessarily - 0 since there may be a #pragma pack() in effect; remember it - so that we can restore it after the final #pragma pop(). */ - if (alignment_stack == NULL) - default_alignment = maximum_field_alignment; - - alignment_stack = entry; - - maximum_field_alignment = alignment; -} - -/* Undo a push of an alignment onto the stack. */ -static void -pop_alignment (tree id) -{ - align_stack * entry; - - if (alignment_stack == NULL) - GCC_BAD ("#pragma pack (pop) encountered without matching #pragma pack (push)"); - - /* If we got an identifier, strip away everything above the target - entry so that the next step will restore the state just below it. */ - if (id) - { - for (entry = alignment_stack; entry; entry = entry->prev) - if (entry->id == id) - { - alignment_stack = entry; - break; - } - if (entry == NULL) - warning (OPT_Wpragmas, "\ -#pragma pack(pop, %E) encountered without matching #pragma pack(push, %E)" - , id, id); - } - - entry = alignment_stack->prev; - - maximum_field_alignment = entry ? entry->alignment : default_alignment; - - alignment_stack = entry; -} -#else /* not HANDLE_PRAGMA_PACK_PUSH_POP */ -#define SET_GLOBAL_ALIGNMENT(ALIGN) (maximum_field_alignment = (ALIGN)) -#define push_alignment(ID, N) \ - GCC_BAD ("#pragma pack(push[, id], ) is not supported on this target") -#define pop_alignment(ID) \ - GCC_BAD ("#pragma pack(pop[, id], ) is not supported on this target") -#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ - -/* #pragma pack () - #pragma pack (N) - - #pragma pack (push) - #pragma pack (push, N) - #pragma pack (push, ID) - #pragma pack (push, ID, N) - #pragma pack (pop) - #pragma pack (pop, ID) */ -static void -handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy)) -{ - tree x, id = 0; - int align = -1; - enum cpp_ttype token; - enum { set, push, pop } action; - - if (pragma_lex (&x) != CPP_OPEN_PAREN) - GCC_BAD ("missing %<(%> after %<#pragma pack%> - ignored"); - - token = pragma_lex (&x); - if (token == CPP_CLOSE_PAREN) - { - action = set; - align = initial_max_fld_align; - } - else if (token == CPP_NUMBER) - { - if (TREE_CODE (x) != INTEGER_CST) - GCC_BAD ("invalid constant in %<#pragma pack%> - ignored"); - align = TREE_INT_CST_LOW (x); - action = set; - if (pragma_lex (&x) != CPP_CLOSE_PAREN) - GCC_BAD ("malformed %<#pragma pack%> - ignored"); - } - else if (token == CPP_NAME) - { -#define GCC_BAD_ACTION do { if (action != pop) \ - GCC_BAD ("malformed %<#pragma pack(push[, id][, ])%> - ignored"); \ - else \ - GCC_BAD ("malformed %<#pragma pack(pop[, id])%> - ignored"); \ - } while (0) - - const char *op = IDENTIFIER_POINTER (x); - if (!strcmp (op, "push")) - action = push; - else if (!strcmp (op, "pop")) - action = pop; - else - GCC_BAD2 ("unknown action %qE for %<#pragma pack%> - ignored", x); - - while ((token = pragma_lex (&x)) == CPP_COMMA) - { - token = pragma_lex (&x); - if (token == CPP_NAME && id == 0) - { - id = x; - } - else if (token == CPP_NUMBER && action == push && align == -1) - { - if (TREE_CODE (x) != INTEGER_CST) - GCC_BAD ("invalid constant in %<#pragma pack%> - ignored"); - align = TREE_INT_CST_LOW (x); - if (align == -1) - action = set; - } - else - GCC_BAD_ACTION; - } - - if (token != CPP_CLOSE_PAREN) - GCC_BAD_ACTION; -#undef GCC_BAD_ACTION - } - else - GCC_BAD ("malformed %<#pragma pack%> - ignored"); - - if (pragma_lex (&x) != CPP_EOF) - warning (OPT_Wpragmas, "junk at end of %<#pragma pack%>"); - - if (flag_pack_struct) - GCC_BAD ("#pragma pack has no effect with -fpack-struct - ignored"); - - if (action != pop) - switch (align) - { - case 0: - case 1: - case 2: - case 4: - case 8: - case 16: - align *= BITS_PER_UNIT; - break; - case -1: - if (action == push) - { - align = maximum_field_alignment; - break; - } - default: - GCC_BAD2 ("alignment must be a small power of two, not %d", align); - } - - switch (action) - { - case set: SET_GLOBAL_ALIGNMENT (align); break; - case push: push_alignment (align, id); break; - case pop: pop_alignment (id); break; - } -} -#endif /* HANDLE_PRAGMA_PACK */ - -typedef struct GTY(()) pending_weak_d -{ - tree name; - tree value; -} pending_weak; - -DEF_VEC_O(pending_weak); -DEF_VEC_ALLOC_O(pending_weak,gc); - -static GTY(()) VEC(pending_weak,gc) *pending_weaks; - -#ifdef HANDLE_PRAGMA_WEAK -static void apply_pragma_weak (tree, tree); -static void handle_pragma_weak (cpp_reader *); - -static void -apply_pragma_weak (tree decl, tree value) -{ - if (value) - { - value = build_string (IDENTIFIER_LENGTH (value), - IDENTIFIER_POINTER (value)); - decl_attributes (&decl, build_tree_list (get_identifier ("alias"), - build_tree_list (NULL, value)), - 0); - } - - if (SUPPORTS_WEAK && DECL_EXTERNAL (decl) && TREE_USED (decl) - && !DECL_WEAK (decl) /* Don't complain about a redundant #pragma. */ - && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) - warning (OPT_Wpragmas, "applying #pragma weak %q+D after first use " - "results in unspecified behavior", decl); - - declare_weak (decl); -} - -void -maybe_apply_pragma_weak (tree decl) -{ - tree id; - int i; - pending_weak *pe; - - /* Avoid asking for DECL_ASSEMBLER_NAME when it's not needed. */ - - /* No weak symbols pending, take the short-cut. */ - if (!pending_weaks) - return; - /* If it's not visible outside this file, it doesn't matter whether - it's weak. */ - if (!DECL_EXTERNAL (decl) && !TREE_PUBLIC (decl)) - return; - /* If it's not a function or a variable, it can't be weak. - FIXME: what kinds of things are visible outside this file but - aren't functions or variables? Should this be an assert instead? */ - if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL) - return; - - id = DECL_ASSEMBLER_NAME (decl); - - for (i = 0; VEC_iterate (pending_weak, pending_weaks, i, pe); i++) - if (id == pe->name) - { - apply_pragma_weak (decl, pe->value); - VEC_unordered_remove (pending_weak, pending_weaks, i); - break; - } -} - -/* Process all "#pragma weak A = B" directives where we have not seen - a decl for A. */ -void -maybe_apply_pending_pragma_weaks (void) -{ - tree alias_id, id, decl; - int i; - pending_weak *pe; - - for (i = 0; VEC_iterate (pending_weak, pending_weaks, i, pe); i++) - { - alias_id = pe->name; - id = pe->value; - - if (id == NULL) - continue; - - decl = build_decl (UNKNOWN_LOCATION, - FUNCTION_DECL, alias_id, default_function_type); - - DECL_ARTIFICIAL (decl) = 1; - TREE_PUBLIC (decl) = 1; - DECL_EXTERNAL (decl) = 1; - DECL_WEAK (decl) = 1; - - assemble_alias (decl, id); - } -} - -/* #pragma weak name [= value] */ -static void -handle_pragma_weak (cpp_reader * ARG_UNUSED (dummy)) -{ - tree name, value, x, decl; - enum cpp_ttype t; - - value = 0; - - if (pragma_lex (&name) != CPP_NAME) - GCC_BAD ("malformed #pragma weak, ignored"); - t = pragma_lex (&x); - if (t == CPP_EQ) - { - if (pragma_lex (&value) != CPP_NAME) - GCC_BAD ("malformed #pragma weak, ignored"); - t = pragma_lex (&x); - } - if (t != CPP_EOF) - warning (OPT_Wpragmas, "junk at end of %<#pragma weak%>"); - - decl = identifier_global_value (name); - if (decl && DECL_P (decl)) - { - apply_pragma_weak (decl, value); - if (value) - assemble_alias (decl, value); - } - else - { - pending_weak *pe; - pe = VEC_safe_push (pending_weak, gc, pending_weaks, NULL); - pe->name = name; - pe->value = value; - } -} -#else -void -maybe_apply_pragma_weak (tree ARG_UNUSED (decl)) -{ -} - -void -maybe_apply_pending_pragma_weaks (void) -{ -} -#endif /* HANDLE_PRAGMA_WEAK */ - -/* GCC supports two #pragma directives for renaming the external - symbol associated with a declaration (DECL_ASSEMBLER_NAME), for - compatibility with the Solaris and Tru64 system headers. GCC also - has its own notation for this, __asm__("name") annotations. - - Corner cases of these features and their interaction: - - 1) Both pragmas silently apply only to declarations with external - linkage (that is, TREE_PUBLIC || DECL_EXTERNAL). Asm labels - do not have this restriction. - - 2) In C++, both #pragmas silently apply only to extern "C" declarations. - Asm labels do not have this restriction. - - 3) If any of the three ways of changing DECL_ASSEMBLER_NAME is - applied to a decl whose DECL_ASSEMBLER_NAME is already set, and the - new name is different, a warning issues and the name does not change. - - 4) The "source name" for #pragma redefine_extname is the DECL_NAME, - *not* the DECL_ASSEMBLER_NAME. - - 5) If #pragma extern_prefix is in effect and a declaration occurs - with an __asm__ name, the #pragma extern_prefix is silently - ignored for that declaration. - - 6) If #pragma extern_prefix and #pragma redefine_extname apply to - the same declaration, whichever triggered first wins, and a warning - is issued. (We would like to have #pragma redefine_extname always - win, but it can appear either before or after the declaration, and - if it appears afterward, we have no way of knowing whether a modified - DECL_ASSEMBLER_NAME is due to #pragma extern_prefix.) */ - -static GTY(()) tree pending_redefine_extname; - -static void handle_pragma_redefine_extname (cpp_reader *); - -/* #pragma redefine_extname oldname newname */ -static void -handle_pragma_redefine_extname (cpp_reader * ARG_UNUSED (dummy)) -{ - tree oldname, newname, decl, x; - enum cpp_ttype t; - - if (pragma_lex (&oldname) != CPP_NAME) - GCC_BAD ("malformed #pragma redefine_extname, ignored"); - if (pragma_lex (&newname) != CPP_NAME) - GCC_BAD ("malformed #pragma redefine_extname, ignored"); - t = pragma_lex (&x); - if (t != CPP_EOF) - warning (OPT_Wpragmas, "junk at end of %<#pragma redefine_extname%>"); - - decl = identifier_global_value (oldname); - if (decl - && (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)) - && (TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == VAR_DECL) - && has_c_linkage (decl)) - { - if (DECL_ASSEMBLER_NAME_SET_P (decl)) - { - const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - name = targetm.strip_name_encoding (name); - - if (strcmp (name, IDENTIFIER_POINTER (newname))) - warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to " - "conflict with previous rename"); - } - else - change_decl_assembler_name (decl, newname); - } - else - /* We have to add this to the rename list even if there's already - a global value that doesn't meet the above criteria, because in - C++ "struct foo {...};" puts "foo" in the current namespace but - does *not* conflict with a subsequent declaration of a function - or variable foo. See g++.dg/other/pragma-re-2.C. */ - add_to_renaming_pragma_list (oldname, newname); -} - -/* This is called from here and from ia64.c. */ -void -add_to_renaming_pragma_list (tree oldname, tree newname) -{ - tree previous = purpose_member (oldname, pending_redefine_extname); - if (previous) - { - if (TREE_VALUE (previous) != newname) - warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to " - "conflict with previous #pragma redefine_extname"); - return; - } - - pending_redefine_extname - = tree_cons (oldname, newname, pending_redefine_extname); -} - -static GTY(()) tree pragma_extern_prefix; - -/* #pragma extern_prefix "prefix" */ -static void -handle_pragma_extern_prefix (cpp_reader * ARG_UNUSED (dummy)) -{ - tree prefix, x; - enum cpp_ttype t; - - if (pragma_lex (&prefix) != CPP_STRING) - GCC_BAD ("malformed #pragma extern_prefix, ignored"); - t = pragma_lex (&x); - if (t != CPP_EOF) - warning (OPT_Wpragmas, "junk at end of %<#pragma extern_prefix%>"); - - if (targetm.handle_pragma_extern_prefix) - /* Note that the length includes the null terminator. */ - pragma_extern_prefix = (TREE_STRING_LENGTH (prefix) > 1 ? prefix : NULL); - else if (warn_unknown_pragmas > in_system_header) - warning (OPT_Wunknown_pragmas, - "#pragma extern_prefix not supported on this target"); -} - -/* Hook from the front ends to apply the results of one of the preceding - pragmas that rename variables. */ - -tree -maybe_apply_renaming_pragma (tree decl, tree asmname) -{ - tree *p, t; - - /* The renaming pragmas are only applied to declarations with - external linkage. */ - if ((TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL) - || (!TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) - || !has_c_linkage (decl)) - return asmname; - - /* If the DECL_ASSEMBLER_NAME is already set, it does not change, - but we may warn about a rename that conflicts. */ - if (DECL_ASSEMBLER_NAME_SET_P (decl)) - { - const char *oldname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - oldname = targetm.strip_name_encoding (oldname); - - if (asmname && strcmp (TREE_STRING_POINTER (asmname), oldname)) - warning (OPT_Wpragmas, "asm declaration ignored due to " - "conflict with previous rename"); - - /* Take any pending redefine_extname off the list. */ - for (p = &pending_redefine_extname; (t = *p); p = &TREE_CHAIN (t)) - if (DECL_NAME (decl) == TREE_PURPOSE (t)) - { - /* Only warn if there is a conflict. */ - if (strcmp (IDENTIFIER_POINTER (TREE_VALUE (t)), oldname)) - warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to " - "conflict with previous rename"); - - *p = TREE_CHAIN (t); - break; - } - return 0; - } - - /* Find out if we have a pending #pragma redefine_extname. */ - for (p = &pending_redefine_extname; (t = *p); p = &TREE_CHAIN (t)) - if (DECL_NAME (decl) == TREE_PURPOSE (t)) - { - tree newname = TREE_VALUE (t); - *p = TREE_CHAIN (t); - - /* If we already have an asmname, #pragma redefine_extname is - ignored (with a warning if it conflicts). */ - if (asmname) - { - if (strcmp (TREE_STRING_POINTER (asmname), - IDENTIFIER_POINTER (newname)) != 0) - warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to " - "conflict with __asm__ declaration"); - return asmname; - } - - /* Otherwise we use what we've got; #pragma extern_prefix is - silently ignored. */ - return build_string (IDENTIFIER_LENGTH (newname), - IDENTIFIER_POINTER (newname)); - } - - /* If we've got an asmname, #pragma extern_prefix is silently ignored. */ - if (asmname) - return asmname; - - /* If #pragma extern_prefix is in effect, apply it. */ - if (pragma_extern_prefix) - { - const char *prefix = TREE_STRING_POINTER (pragma_extern_prefix); - size_t plen = TREE_STRING_LENGTH (pragma_extern_prefix) - 1; - - const char *id = IDENTIFIER_POINTER (DECL_NAME (decl)); - size_t ilen = IDENTIFIER_LENGTH (DECL_NAME (decl)); - - char *newname = (char *) alloca (plen + ilen + 1); - - memcpy (newname, prefix, plen); - memcpy (newname + plen, id, ilen + 1); - - return build_string (plen + ilen, newname); - } - - /* Nada. */ - return 0; -} - - -#ifdef HANDLE_PRAGMA_VISIBILITY -static void handle_pragma_visibility (cpp_reader *); - -static VEC (int, heap) *visstack; - -/* Push the visibility indicated by STR onto the top of the #pragma - visibility stack. KIND is 0 for #pragma GCC visibility, 1 for - C++ namespace with visibility attribute and 2 for C++ builtin - ABI namespace. push_visibility/pop_visibility calls must have - matching KIND, it is not allowed to push visibility using one - KIND and pop using a different one. */ - -void -push_visibility (const char *str, int kind) -{ - VEC_safe_push (int, heap, visstack, - ((int) default_visibility) | (kind << 8)); - if (!strcmp (str, "default")) - default_visibility = VISIBILITY_DEFAULT; - else if (!strcmp (str, "internal")) - default_visibility = VISIBILITY_INTERNAL; - else if (!strcmp (str, "hidden")) - default_visibility = VISIBILITY_HIDDEN; - else if (!strcmp (str, "protected")) - default_visibility = VISIBILITY_PROTECTED; - else - GCC_BAD ("#pragma GCC visibility push() must specify default, internal, hidden or protected"); - visibility_options.inpragma = 1; -} - -/* Pop a level of the #pragma visibility stack. Return true if - successful. */ - -bool -pop_visibility (int kind) -{ - if (!VEC_length (int, visstack)) - return false; - if ((VEC_last (int, visstack) >> 8) != kind) - return false; - default_visibility - = (enum symbol_visibility) (VEC_pop (int, visstack) & 0xff); - visibility_options.inpragma - = VEC_length (int, visstack) != 0; - return true; -} - -/* Sets the default visibility for symbols to something other than that - specified on the command line. */ - -static void -handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED) -{ - /* Form is #pragma GCC visibility push(hidden)|pop */ - tree x; - enum cpp_ttype token; - enum { bad, push, pop } action = bad; - - token = pragma_lex (&x); - if (token == CPP_NAME) - { - const char *op = IDENTIFIER_POINTER (x); - if (!strcmp (op, "push")) - action = push; - else if (!strcmp (op, "pop")) - action = pop; - } - if (bad == action) - GCC_BAD ("#pragma GCC visibility must be followed by push or pop"); - else - { - if (pop == action) - { - if (! pop_visibility (0)) - GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>"); - } - else - { - if (pragma_lex (&x) != CPP_OPEN_PAREN) - GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored"); - token = pragma_lex (&x); - if (token != CPP_NAME) - GCC_BAD ("malformed #pragma GCC visibility push"); - else - push_visibility (IDENTIFIER_POINTER (x), 0); - if (pragma_lex (&x) != CPP_CLOSE_PAREN) - GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored"); - } - } - if (pragma_lex (&x) != CPP_EOF) - warning (OPT_Wpragmas, "junk at end of %<#pragma GCC visibility%>"); -} - -#endif - -static void -handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy)) -{ - const char *kind_string, *option_string; - unsigned int option_index; - enum cpp_ttype token; - diagnostic_t kind; - tree x; - - if (cfun) - { - error ("#pragma GCC diagnostic not allowed inside functions"); - return; - } - - token = pragma_lex (&x); - if (token != CPP_NAME) - GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>"); - kind_string = IDENTIFIER_POINTER (x); - if (strcmp (kind_string, "error") == 0) - kind = DK_ERROR; - else if (strcmp (kind_string, "warning") == 0) - kind = DK_WARNING; - else if (strcmp (kind_string, "ignored") == 0) - kind = DK_IGNORED; - else - GCC_BAD ("expected [error|warning|ignored] after %<#pragma GCC diagnostic%>"); - - token = pragma_lex (&x); - if (token != CPP_STRING) - GCC_BAD ("missing option after %<#pragma GCC diagnostic%> kind"); - option_string = TREE_STRING_POINTER (x); - for (option_index = 0; option_index < cl_options_count; option_index++) - if (strcmp (cl_options[option_index].opt_text, option_string) == 0) - { - /* This overrides -Werror, for example. */ - diagnostic_classify_diagnostic (global_dc, option_index, kind); - /* This makes sure the option is enabled, like -Wfoo would do. */ - if (cl_options[option_index].var_type == CLVC_BOOLEAN - && cl_options[option_index].flag_var - && kind != DK_IGNORED) - *(int *) cl_options[option_index].flag_var = 1; - return; - } - GCC_BAD ("unknown option after %<#pragma GCC diagnostic%> kind"); -} - -/* Parse #pragma GCC target (xxx) to set target specific options. */ -static void -handle_pragma_target(cpp_reader *ARG_UNUSED(dummy)) -{ - enum cpp_ttype token; - tree x; - bool close_paren_needed_p = false; - - if (cfun) - { - error ("#pragma GCC option is not allowed inside functions"); - return; - } - - token = pragma_lex (&x); - if (token == CPP_OPEN_PAREN) - { - close_paren_needed_p = true; - token = pragma_lex (&x); - } - - if (token != CPP_STRING) - { - GCC_BAD ("%<#pragma GCC option%> is not a string"); - return; - } - - /* Strings are user options. */ - else - { - tree args = NULL_TREE; - - do - { - /* Build up the strings now as a tree linked list. Skip empty - strings. */ - if (TREE_STRING_LENGTH (x) > 0) - args = tree_cons (NULL_TREE, x, args); - - token = pragma_lex (&x); - while (token == CPP_COMMA) - token = pragma_lex (&x); - } - while (token == CPP_STRING); - - if (close_paren_needed_p) - { - if (token == CPP_CLOSE_PAREN) - token = pragma_lex (&x); - else - GCC_BAD ("%<#pragma GCC target (string [,string]...)%> does " - "not have a final %<)%>."); - } - - if (token != CPP_EOF) - { - error ("#pragma GCC target string... is badly formed"); - return; - } - - /* put arguments in the order the user typed them. */ - args = nreverse (args); - - if (targetm.target_option.pragma_parse (args, NULL_TREE)) - current_target_pragma = args; - } -} - -/* Handle #pragma GCC optimize to set optimization options. */ -static void -handle_pragma_optimize (cpp_reader *ARG_UNUSED(dummy)) -{ - enum cpp_ttype token; - tree x; - bool close_paren_needed_p = false; - tree optimization_previous_node = optimization_current_node; - - if (cfun) - { - error ("#pragma GCC optimize is not allowed inside functions"); - return; - } - - token = pragma_lex (&x); - if (token == CPP_OPEN_PAREN) - { - close_paren_needed_p = true; - token = pragma_lex (&x); - } - - if (token != CPP_STRING && token != CPP_NUMBER) - { - GCC_BAD ("%<#pragma GCC optimize%> is not a string or number"); - return; - } - - /* Strings/numbers are user options. */ - else - { - tree args = NULL_TREE; - - do - { - /* Build up the numbers/strings now as a list. */ - if (token != CPP_STRING || TREE_STRING_LENGTH (x) > 0) - args = tree_cons (NULL_TREE, x, args); - - token = pragma_lex (&x); - while (token == CPP_COMMA) - token = pragma_lex (&x); - } - while (token == CPP_STRING || token == CPP_NUMBER); - - if (close_paren_needed_p) - { - if (token == CPP_CLOSE_PAREN) - token = pragma_lex (&x); - else - GCC_BAD ("%<#pragma GCC optimize (string [,string]...)%> does " - "not have a final %<)%>."); - } - - if (token != CPP_EOF) - { - error ("#pragma GCC optimize string... is badly formed"); - return; - } - - /* put arguments in the order the user typed them. */ - args = nreverse (args); - - parse_optimize_options (args, false); - current_optimize_pragma = chainon (current_optimize_pragma, args); - optimization_current_node = build_optimization_node (); - c_cpp_builtins_optimize_pragma (parse_in, - optimization_previous_node, - optimization_current_node); - } -} - -/* Stack of the #pragma GCC options created with #pragma GCC push_option. Save - both the binary representation of the options and the TREE_LIST of - strings that will be added to the function's attribute list. */ -typedef struct GTY(()) opt_stack { - struct opt_stack *prev; - tree target_binary; - tree target_strings; - tree optimize_binary; - tree optimize_strings; -} opt_stack; - -static GTY(()) struct opt_stack * options_stack; - -/* Handle #pragma GCC push_options to save the current target and optimization - options. */ - -static void -handle_pragma_push_options (cpp_reader *ARG_UNUSED(dummy)) -{ - enum cpp_ttype token; - tree x = 0; - opt_stack *p; - - token = pragma_lex (&x); - if (token != CPP_EOF) - { - warning (OPT_Wpragmas, "junk at end of %<#pragma push_options%>"); - return; - } - - p = GGC_NEW (opt_stack); - p->prev = options_stack; - options_stack = p; - - /* Save optimization and target flags in binary format. */ - p->optimize_binary = build_optimization_node (); - p->target_binary = build_target_option_node (); - - /* Save optimization and target flags in string list format. */ - p->optimize_strings = copy_list (current_optimize_pragma); - p->target_strings = copy_list (current_target_pragma); -} - -/* Handle #pragma GCC pop_options to restore the current target and - optimization options from a previous push_options. */ - -static void -handle_pragma_pop_options (cpp_reader *ARG_UNUSED(dummy)) -{ - enum cpp_ttype token; - tree x = 0; - opt_stack *p; - - token = pragma_lex (&x); - if (token != CPP_EOF) - { - warning (OPT_Wpragmas, "junk at end of %<#pragma pop_options%>"); - return; - } - - if (! options_stack) - { - warning (OPT_Wpragmas, - "%<#pragma GCC pop_options%> without a corresponding " - "%<#pragma GCC push_options%>"); - return; - } - - p = options_stack; - options_stack = p->prev; - - if (p->target_binary != target_option_current_node) - { - (void) targetm.target_option.pragma_parse (NULL_TREE, p->target_binary); - target_option_current_node = p->target_binary; - } - - if (p->optimize_binary != optimization_current_node) - { - tree old_optimize = optimization_current_node; - cl_optimization_restore (TREE_OPTIMIZATION (p->optimize_binary)); - c_cpp_builtins_optimize_pragma (parse_in, old_optimize, - p->optimize_binary); - optimization_current_node = p->optimize_binary; - } - - current_target_pragma = p->target_strings; - current_optimize_pragma = p->optimize_strings; -} - -/* Handle #pragma GCC reset_options to restore the current target and - optimization options to the original options used on the command line. */ - -static void -handle_pragma_reset_options (cpp_reader *ARG_UNUSED(dummy)) -{ - enum cpp_ttype token; - tree x = 0; - tree new_optimize = optimization_default_node; - tree new_target = target_option_default_node; - - token = pragma_lex (&x); - if (token != CPP_EOF) - { - warning (OPT_Wpragmas, "junk at end of %<#pragma reset_options%>"); - return; - } - - if (new_target != target_option_current_node) - { - (void) targetm.target_option.pragma_parse (NULL_TREE, new_target); - target_option_current_node = new_target; - } - - if (new_optimize != optimization_current_node) - { - tree old_optimize = optimization_current_node; - cl_optimization_restore (TREE_OPTIMIZATION (new_optimize)); - c_cpp_builtins_optimize_pragma (parse_in, old_optimize, new_optimize); - optimization_current_node = new_optimize; - } - - current_target_pragma = NULL_TREE; - current_optimize_pragma = NULL_TREE; -} - -/* Print a plain user-specified message. */ - -static void -handle_pragma_message (cpp_reader *ARG_UNUSED(dummy)) -{ - enum cpp_ttype token; - tree x, message = 0; - - token = pragma_lex (&x); - if (token == CPP_OPEN_PAREN) - { - token = pragma_lex (&x); - if (token == CPP_STRING) - message = x; - else - GCC_BAD ("expected a string after %<#pragma message%>"); - if (pragma_lex (&x) != CPP_CLOSE_PAREN) - GCC_BAD ("malformed %<#pragma message%>, ignored"); - } - else if (token == CPP_STRING) - message = x; - else - GCC_BAD ("expected a string after %<#pragma message%>"); - - gcc_assert (message); - - if (pragma_lex (&x) != CPP_EOF) - warning (OPT_Wpragmas, "junk at end of %<#pragma message%>"); - - if (TREE_STRING_LENGTH (message) > 1) - inform (input_location, "#pragma message: %s", TREE_STRING_POINTER (message)); -} - -/* Mark whether the current location is valid for a STDC pragma. */ - -static bool valid_location_for_stdc_pragma; - -void -mark_valid_location_for_stdc_pragma (bool flag) -{ - valid_location_for_stdc_pragma = flag; -} - -/* Return true if the current location is valid for a STDC pragma. */ - -bool -valid_location_for_stdc_pragma_p (void) -{ - return valid_location_for_stdc_pragma; -} - -enum pragma_switch_t { PRAGMA_ON, PRAGMA_OFF, PRAGMA_DEFAULT, PRAGMA_BAD }; - -/* A STDC pragma must appear outside of external declarations or - preceding all explicit declarations and statements inside a compound - statement; its behavior is undefined if used in any other context. - It takes a switch of ON, OFF, or DEFAULT. */ - -static enum pragma_switch_t -handle_stdc_pragma (const char *pname) -{ - const char *arg; - tree t; - enum pragma_switch_t ret; - - if (!valid_location_for_stdc_pragma_p ()) - { - warning (OPT_Wpragmas, "invalid location for %, ignored", - pname); - return PRAGMA_BAD; - } - - if (pragma_lex (&t) != CPP_NAME) - { - warning (OPT_Wpragmas, "malformed %<#pragma %s%>, ignored", pname); - return PRAGMA_BAD; - } - - arg = IDENTIFIER_POINTER (t); - - if (!strcmp (arg, "ON")) - ret = PRAGMA_ON; - else if (!strcmp (arg, "OFF")) - ret = PRAGMA_OFF; - else if (!strcmp (arg, "DEFAULT")) - ret = PRAGMA_DEFAULT; - else - { - warning (OPT_Wpragmas, "malformed %<#pragma %s%>, ignored", pname); - return PRAGMA_BAD; - } - - if (pragma_lex (&t) != CPP_EOF) - { - warning (OPT_Wpragmas, "junk at end of %<#pragma %s%>", pname); - return PRAGMA_BAD; - } - - return ret; -} - -/* #pragma STDC FLOAT_CONST_DECIMAL64 ON - #pragma STDC FLOAT_CONST_DECIMAL64 OFF - #pragma STDC FLOAT_CONST_DECIMAL64 DEFAULT */ - -static void -handle_pragma_float_const_decimal64 (cpp_reader *ARG_UNUSED (dummy)) -{ - if (c_dialect_cxx ()) - { - if (warn_unknown_pragmas > in_system_header) - warning (OPT_Wunknown_pragmas, - "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported" - " for C++"); - return; - } - - if (!targetm.decimal_float_supported_p ()) - { - if (warn_unknown_pragmas > in_system_header) - warning (OPT_Wunknown_pragmas, - "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported" - " on this target"); - return; - } - - pedwarn (input_location, OPT_pedantic, - "ISO C does not support %<#pragma STDC FLOAT_CONST_DECIMAL64%>"); - - switch (handle_stdc_pragma ("STDC FLOAT_CONST_DECIMAL64")) - { - case PRAGMA_ON: - set_float_const_decimal64 (); - break; - case PRAGMA_OFF: - case PRAGMA_DEFAULT: - clear_float_const_decimal64 (); - break; - case PRAGMA_BAD: - break; - } -} - -/* A vector of registered pragma callbacks. */ - -DEF_VEC_O (pragma_handler); -DEF_VEC_ALLOC_O (pragma_handler, heap); - -static VEC(pragma_handler, heap) *registered_pragmas; - -typedef struct -{ - const char *space; - const char *name; -} pragma_ns_name; - -DEF_VEC_O (pragma_ns_name); -DEF_VEC_ALLOC_O (pragma_ns_name, heap); - -static VEC(pragma_ns_name, heap) *registered_pp_pragmas; - -struct omp_pragma_def { const char *name; unsigned int id; }; -static const struct omp_pragma_def omp_pragmas[] = { - { "atomic", PRAGMA_OMP_ATOMIC }, - { "barrier", PRAGMA_OMP_BARRIER }, - { "critical", PRAGMA_OMP_CRITICAL }, - { "flush", PRAGMA_OMP_FLUSH }, - { "for", PRAGMA_OMP_FOR }, - { "master", PRAGMA_OMP_MASTER }, - { "ordered", PRAGMA_OMP_ORDERED }, - { "parallel", PRAGMA_OMP_PARALLEL }, - { "section", PRAGMA_OMP_SECTION }, - { "sections", PRAGMA_OMP_SECTIONS }, - { "single", PRAGMA_OMP_SINGLE }, - { "task", PRAGMA_OMP_TASK }, - { "taskwait", PRAGMA_OMP_TASKWAIT }, - { "threadprivate", PRAGMA_OMP_THREADPRIVATE } -}; - -void -c_pp_lookup_pragma (unsigned int id, const char **space, const char **name) -{ - const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas); - int i; - - for (i = 0; i < n_omp_pragmas; ++i) - if (omp_pragmas[i].id == id) - { - *space = "omp"; - *name = omp_pragmas[i].name; - return; - } - - if (id >= PRAGMA_FIRST_EXTERNAL - && (id < PRAGMA_FIRST_EXTERNAL - + VEC_length (pragma_ns_name, registered_pp_pragmas))) - { - *space = VEC_index (pragma_ns_name, registered_pp_pragmas, - id - PRAGMA_FIRST_EXTERNAL)->space; - *name = VEC_index (pragma_ns_name, registered_pp_pragmas, - id - PRAGMA_FIRST_EXTERNAL)->name; - return; - } - - gcc_unreachable (); -} - -/* Front-end wrappers for pragma registration to avoid dragging - cpplib.h in almost everywhere. */ - -static void -c_register_pragma_1 (const char *space, const char *name, - pragma_handler handler, bool allow_expansion) -{ - unsigned id; - - if (flag_preprocess_only) - { - pragma_ns_name ns_name; - - if (!allow_expansion) - return; - - ns_name.space = space; - ns_name.name = name; - VEC_safe_push (pragma_ns_name, heap, registered_pp_pragmas, &ns_name); - id = VEC_length (pragma_ns_name, registered_pp_pragmas); - id += PRAGMA_FIRST_EXTERNAL - 1; - } - else - { - VEC_safe_push (pragma_handler, heap, registered_pragmas, &handler); - id = VEC_length (pragma_handler, registered_pragmas); - id += PRAGMA_FIRST_EXTERNAL - 1; - - /* The C++ front end allocates 6 bits in cp_token; the C front end - allocates 7 bits in c_token. At present this is sufficient. */ - gcc_assert (id < 64); - } - - cpp_register_deferred_pragma (parse_in, space, name, id, - allow_expansion, false); -} - -void -c_register_pragma (const char *space, const char *name, pragma_handler handler) -{ - c_register_pragma_1 (space, name, handler, false); -} - -void -c_register_pragma_with_expansion (const char *space, const char *name, - pragma_handler handler) -{ - c_register_pragma_1 (space, name, handler, true); -} - -void -c_invoke_pragma_handler (unsigned int id) -{ - pragma_handler handler; - - id -= PRAGMA_FIRST_EXTERNAL; - handler = *VEC_index (pragma_handler, registered_pragmas, id); - - handler (parse_in); -} - -/* Set up front-end pragmas. */ -void -init_pragma (void) -{ - if (flag_openmp) - { - const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas); - int i; - - for (i = 0; i < n_omp_pragmas; ++i) - cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas[i].name, - omp_pragmas[i].id, true, true); - } - - if (!flag_preprocess_only) - cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess", - PRAGMA_GCC_PCH_PREPROCESS, false, false); - -#ifdef HANDLE_PRAGMA_PACK -#ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION - c_register_pragma_with_expansion (0, "pack", handle_pragma_pack); -#else - c_register_pragma (0, "pack", handle_pragma_pack); -#endif -#endif -#ifdef HANDLE_PRAGMA_WEAK - c_register_pragma (0, "weak", handle_pragma_weak); -#endif -#ifdef HANDLE_PRAGMA_VISIBILITY - c_register_pragma ("GCC", "visibility", handle_pragma_visibility); -#endif - - c_register_pragma ("GCC", "diagnostic", handle_pragma_diagnostic); - c_register_pragma ("GCC", "target", handle_pragma_target); - c_register_pragma ("GCC", "optimize", handle_pragma_optimize); - c_register_pragma ("GCC", "push_options", handle_pragma_push_options); - c_register_pragma ("GCC", "pop_options", handle_pragma_pop_options); - c_register_pragma ("GCC", "reset_options", handle_pragma_reset_options); - - c_register_pragma ("STDC", "FLOAT_CONST_DECIMAL64", - handle_pragma_float_const_decimal64); - - c_register_pragma_with_expansion (0, "redefine_extname", handle_pragma_redefine_extname); - c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix); - - c_register_pragma_with_expansion (0, "message", handle_pragma_message); - -#ifdef REGISTER_TARGET_PRAGMAS - REGISTER_TARGET_PRAGMAS (); -#endif - - /* Allow plugins to register their own pragmas. */ - invoke_plugin_callbacks (PLUGIN_PRAGMAS, NULL); -} - -#include "gt-c-pragma.h" diff --git a/gcc/c-pragma.h b/gcc/c-pragma.h deleted file mode 100644 index eab23db..0000000 --- a/gcc/c-pragma.h +++ /dev/null @@ -1,133 +0,0 @@ -/* Pragma related interfaces. - Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2007, 2008 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 -. */ - -#ifndef GCC_C_PRAGMA_H -#define GCC_C_PRAGMA_H - -#include /* For enum cpp_ttype. */ - -/* Pragma identifiers built in to the front end parsers. Identifiers - for ancillary handlers will follow these. */ -typedef enum pragma_kind { - PRAGMA_NONE = 0, - - PRAGMA_OMP_ATOMIC, - PRAGMA_OMP_BARRIER, - PRAGMA_OMP_CRITICAL, - PRAGMA_OMP_FLUSH, - PRAGMA_OMP_FOR, - PRAGMA_OMP_MASTER, - PRAGMA_OMP_ORDERED, - PRAGMA_OMP_PARALLEL, - PRAGMA_OMP_PARALLEL_FOR, - PRAGMA_OMP_PARALLEL_SECTIONS, - PRAGMA_OMP_SECTION, - PRAGMA_OMP_SECTIONS, - PRAGMA_OMP_SINGLE, - PRAGMA_OMP_TASK, - PRAGMA_OMP_TASKWAIT, - PRAGMA_OMP_THREADPRIVATE, - - PRAGMA_GCC_PCH_PREPROCESS, - - PRAGMA_FIRST_EXTERNAL -} pragma_kind; - - -/* All clauses defined by OpenMP 2.5 and 3.0. - Used internally by both C and C++ parsers. */ -typedef enum pragma_omp_clause { - PRAGMA_OMP_CLAUSE_NONE = 0, - - PRAGMA_OMP_CLAUSE_COLLAPSE, - PRAGMA_OMP_CLAUSE_COPYIN, - PRAGMA_OMP_CLAUSE_COPYPRIVATE, - PRAGMA_OMP_CLAUSE_DEFAULT, - PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, - PRAGMA_OMP_CLAUSE_IF, - PRAGMA_OMP_CLAUSE_LASTPRIVATE, - PRAGMA_OMP_CLAUSE_NOWAIT, - PRAGMA_OMP_CLAUSE_NUM_THREADS, - PRAGMA_OMP_CLAUSE_ORDERED, - PRAGMA_OMP_CLAUSE_PRIVATE, - PRAGMA_OMP_CLAUSE_REDUCTION, - PRAGMA_OMP_CLAUSE_SCHEDULE, - PRAGMA_OMP_CLAUSE_SHARED, - PRAGMA_OMP_CLAUSE_UNTIED -} pragma_omp_clause; - -extern struct cpp_reader* parse_in; - -#define HANDLE_PRAGMA_WEAK SUPPORTS_WEAK - -#ifdef HANDLE_SYSV_PRAGMA -/* We always support #pragma pack for SYSV pragmas. */ -#ifndef HANDLE_PRAGMA_PACK -#define HANDLE_PRAGMA_PACK 1 -#endif -#endif /* HANDLE_SYSV_PRAGMA */ - - -#ifdef HANDLE_PRAGMA_PACK_PUSH_POP -/* If we are supporting #pragma pack(push... then we automatically - support #pragma pack() */ -#define HANDLE_PRAGMA_PACK 1 -#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ - -/* It's safe to always leave visibility pragma enabled as if - visibility is not supported on the host OS platform the - statements are ignored. */ -#define HANDLE_PRAGMA_VISIBILITY 1 -extern void push_visibility (const char *, int); -extern bool pop_visibility (int); - -extern void init_pragma (void); - -/* Front-end wrappers for pragma registration. */ -typedef void (*pragma_handler)(struct cpp_reader *); -extern void c_register_pragma (const char *, const char *, pragma_handler); -extern void c_register_pragma_with_expansion (const char *, const char *, - pragma_handler); -extern void c_invoke_pragma_handler (unsigned int); - -extern void maybe_apply_pragma_weak (tree); -extern void maybe_apply_pending_pragma_weaks (void); -extern tree maybe_apply_renaming_pragma (tree, tree); -extern void add_to_renaming_pragma_list (tree, tree); - -extern enum cpp_ttype pragma_lex (tree *); - -/* Flags for use with c_lex_with_flags. The values here were picked - so that 0 means to translate and join strings. */ -#define C_LEX_STRING_NO_TRANSLATE 1 /* Do not lex strings into - execution character set. */ -#define C_LEX_STRING_NO_JOIN 2 /* Do not concatenate strings - nor translate them into execution - character set. */ - -/* This is not actually available to pragma parsers. It's merely a - convenient location to declare this function for c-lex, after - having enum cpp_ttype declared. */ -extern enum cpp_ttype c_lex_with_flags (tree *, location_t *, unsigned char *, - int); - -extern void c_pp_lookup_pragma (unsigned int, const char **, const char **); - -#endif /* GCC_C_PRAGMA_H */ diff --git a/gcc/c-pretty-print.c b/gcc/c-pretty-print.c deleted file mode 100644 index 7f4b238..0000000 --- a/gcc/c-pretty-print.c +++ /dev/null @@ -1,2282 +0,0 @@ -/* Subroutines common to both C and C++ pretty-printers. - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - 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 "tree.h" -#include "intl.h" -#include "c-pretty-print.h" -#include "tree-pretty-print.h" -#include "tree-iterator.h" -#include "diagnostic.h" - -/* Translate if being used for diagnostics, but not for dump files or - __PRETTY_FUNCTION. */ -#define M_(msgid) (pp_translate_identifiers (pp) ? _(msgid) : (msgid)) - -/* The pretty-printer code is primarily designed to closely follow - (GNU) C and C++ grammars. That is to be contrasted with spaghetti - codes we used to have in the past. Following a structured - approach (preferably the official grammars) is believed to make it - much easier to add extensions and nifty pretty-printing effects that - takes expression or declaration contexts into account. */ - - -#define pp_c_maybe_whitespace(PP) \ - do { \ - if (pp_base (PP)->padding == pp_before) \ - pp_c_whitespace (PP); \ - } while (0) - -/* literal */ -static void pp_c_char (c_pretty_printer *, int); - -/* postfix-expression */ -static void pp_c_initializer_list (c_pretty_printer *, tree); -static void pp_c_brace_enclosed_initializer_list (c_pretty_printer *, tree); - -static void pp_c_multiplicative_expression (c_pretty_printer *, tree); -static void pp_c_additive_expression (c_pretty_printer *, tree); -static void pp_c_shift_expression (c_pretty_printer *, tree); -static void pp_c_relational_expression (c_pretty_printer *, tree); -static void pp_c_equality_expression (c_pretty_printer *, tree); -static void pp_c_and_expression (c_pretty_printer *, tree); -static void pp_c_exclusive_or_expression (c_pretty_printer *, tree); -static void pp_c_inclusive_or_expression (c_pretty_printer *, tree); -static void pp_c_logical_and_expression (c_pretty_printer *, tree); -static void pp_c_conditional_expression (c_pretty_printer *, tree); -static void pp_c_assignment_expression (c_pretty_printer *, tree); - -/* declarations. */ - - -/* Helper functions. */ - -void -pp_c_whitespace (c_pretty_printer *pp) -{ - pp_space (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_left_paren (c_pretty_printer *pp) -{ - pp_left_paren (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_right_paren (c_pretty_printer *pp) -{ - pp_right_paren (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_left_brace (c_pretty_printer *pp) -{ - pp_left_brace (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_right_brace (c_pretty_printer *pp) -{ - pp_right_brace (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_left_bracket (c_pretty_printer *pp) -{ - pp_left_bracket (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_right_bracket (c_pretty_printer *pp) -{ - pp_right_bracket (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_dot (c_pretty_printer *pp) -{ - pp_dot (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_ampersand (c_pretty_printer *pp) -{ - pp_ampersand (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_star (c_pretty_printer *pp) -{ - pp_star (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_arrow (c_pretty_printer *pp) -{ - pp_arrow (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_semicolon (c_pretty_printer *pp) -{ - pp_semicolon (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_complement (c_pretty_printer *pp) -{ - pp_complement (pp); - pp_base (pp)->padding = pp_none; -} - -void -pp_c_exclamation (c_pretty_printer *pp) -{ - pp_exclamation (pp); - pp_base (pp)->padding = pp_none; -} - -/* Print out the external representation of QUALIFIERS. */ - -void -pp_c_cv_qualifiers (c_pretty_printer *pp, int qualifiers, bool func_type) -{ - const char *p = pp_last_position_in_text (pp); - bool previous = false; - - if (!qualifiers) - return; - - /* The C programming language does not have references, but it is much - simpler to handle those here rather than going through the same - logic in the C++ pretty-printer. */ - if (p != NULL && (*p == '*' || *p == '&')) - pp_c_whitespace (pp); - - if (qualifiers & TYPE_QUAL_CONST) - { - pp_c_ws_string (pp, func_type ? "__attribute__((const))" : "const"); - previous = true; - } - - if (qualifiers & TYPE_QUAL_VOLATILE) - { - if (previous) - pp_c_whitespace (pp); - pp_c_ws_string (pp, func_type ? "__attribute__((noreturn))" : "volatile"); - previous = true; - } - - if (qualifiers & TYPE_QUAL_RESTRICT) - { - if (previous) - pp_c_whitespace (pp); - pp_c_ws_string (pp, flag_isoc99 ? "restrict" : "__restrict__"); - } -} - -/* Pretty-print T using the type-cast notation '( type-name )'. */ - -static void -pp_c_type_cast (c_pretty_printer *pp, tree t) -{ - pp_c_left_paren (pp); - pp_type_id (pp, t); - pp_c_right_paren (pp); -} - -/* We're about to pretty-print a pointer type as indicated by T. - Output a whitespace, if needed, preparing for subsequent output. */ - -void -pp_c_space_for_pointer_operator (c_pretty_printer *pp, tree t) -{ - if (POINTER_TYPE_P (t)) - { - tree pointee = strip_pointer_operator (TREE_TYPE (t)); - if (TREE_CODE (pointee) != ARRAY_TYPE - && TREE_CODE (pointee) != FUNCTION_TYPE) - pp_c_whitespace (pp); - } -} - - -/* Declarations. */ - -/* C++ cv-qualifiers are called type-qualifiers in C. Print out the - cv-qualifiers of T. If T is a declaration then it is the cv-qualifier - of its type. Take care of possible extensions. - - type-qualifier-list: - type-qualifier - type-qualifier-list type-qualifier - - type-qualifier: - const - restrict -- C99 - __restrict__ -- GNU C - address-space-qualifier -- GNU C - volatile - - address-space-qualifier: - identifier -- GNU C */ - -void -pp_c_type_qualifier_list (c_pretty_printer *pp, tree t) -{ - int qualifiers; - - if (!t || t == error_mark_node) - return; - - if (!TYPE_P (t)) - t = TREE_TYPE (t); - - qualifiers = TYPE_QUALS (t); - pp_c_cv_qualifiers (pp, qualifiers, - TREE_CODE (t) == FUNCTION_TYPE); - - if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t))) - { - const char *as = c_addr_space_name (TYPE_ADDR_SPACE (t)); - pp_c_identifier (pp, as); - } -} - -/* pointer: - * type-qualifier-list(opt) - * type-qualifier-list(opt) pointer */ - -static void -pp_c_pointer (c_pretty_printer *pp, tree t) -{ - if (!TYPE_P (t) && TREE_CODE (t) != TYPE_DECL) - t = TREE_TYPE (t); - switch (TREE_CODE (t)) - { - case POINTER_TYPE: - /* It is easier to handle C++ reference types here. */ - case REFERENCE_TYPE: - if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE) - pp_c_pointer (pp, TREE_TYPE (t)); - if (TREE_CODE (t) == POINTER_TYPE) - pp_c_star (pp); - else - pp_c_ampersand (pp); - pp_c_type_qualifier_list (pp, t); - break; - - /* ??? This node is now in GENERIC and so shouldn't be here. But - we'll fix that later. */ - case DECL_EXPR: - pp_declaration (pp, DECL_EXPR_DECL (t)); - pp_needs_newline (pp) = true; - break; - - default: - pp_unsupported_tree (pp, t); - } -} - -/* type-specifier: - void - char - short - int - long - float - double - signed - unsigned - _Bool -- C99 - _Complex -- C99 - _Imaginary -- C99 - struct-or-union-specifier - enum-specifier - typedef-name. - - GNU extensions. - simple-type-specifier: - __complex__ - __vector__ */ - -void -pp_c_type_specifier (c_pretty_printer *pp, tree t) -{ - const enum tree_code code = TREE_CODE (t); - switch (code) - { - case ERROR_MARK: - pp_c_ws_string (pp, M_("")); - break; - - case IDENTIFIER_NODE: - pp_c_tree_decl_identifier (pp, t); - break; - - case VOID_TYPE: - case BOOLEAN_TYPE: - case INTEGER_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - if (TYPE_NAME (t)) - { - t = TYPE_NAME (t); - pp_c_type_specifier (pp, t); - } - else - { - int prec = TYPE_PRECISION (t); - if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (t))) - t = c_common_type_for_mode (TYPE_MODE (t), TYPE_SATURATING (t)); - else - t = c_common_type_for_mode (TYPE_MODE (t), TYPE_UNSIGNED (t)); - if (TYPE_NAME (t)) - { - pp_c_type_specifier (pp, t); - if (TYPE_PRECISION (t) != prec) - { - pp_string (pp, ":"); - pp_decimal_int (pp, prec); - } - } - else - { - switch (code) - { - case INTEGER_TYPE: - pp_string (pp, (TYPE_UNSIGNED (t) - ? M_(""); - } - } - break; - - case TYPE_DECL: - if (DECL_NAME (t)) - pp_id_expression (pp, t); - else - pp_c_ws_string (pp, M_("")); - break; - - case UNION_TYPE: - case RECORD_TYPE: - case ENUMERAL_TYPE: - if (code == UNION_TYPE) - pp_c_ws_string (pp, "union"); - else if (code == RECORD_TYPE) - pp_c_ws_string (pp, "struct"); - else if (code == ENUMERAL_TYPE) - pp_c_ws_string (pp, "enum"); - else - pp_c_ws_string (pp, M_("")); - - if (TYPE_NAME (t)) - pp_id_expression (pp, TYPE_NAME (t)); - else - pp_c_ws_string (pp, M_("")); - break; - - default: - pp_unsupported_tree (pp, t); - break; - } -} - -/* specifier-qualifier-list: - type-specifier specifier-qualifier-list-opt - type-qualifier specifier-qualifier-list-opt - - - Implementation note: Because of the non-linearities in array or - function declarations, this routine prints not just the - specifier-qualifier-list of such entities or types of such entities, - but also the 'pointer' production part of their declarators. The - remaining part is done by pp_declarator or pp_c_abstract_declarator. */ - -void -pp_c_specifier_qualifier_list (c_pretty_printer *pp, tree t) -{ - const enum tree_code code = TREE_CODE (t); - - if (TREE_CODE (t) != POINTER_TYPE) - pp_c_type_qualifier_list (pp, t); - switch (code) - { - case REFERENCE_TYPE: - case POINTER_TYPE: - { - /* Get the types-specifier of this type. */ - tree pointee = strip_pointer_operator (TREE_TYPE (t)); - pp_c_specifier_qualifier_list (pp, pointee); - if (TREE_CODE (pointee) == ARRAY_TYPE - || TREE_CODE (pointee) == FUNCTION_TYPE) - { - pp_c_whitespace (pp); - pp_c_left_paren (pp); - } - else if (!c_dialect_cxx ()) - pp_c_whitespace (pp); - pp_ptr_operator (pp, t); - } - break; - - case FUNCTION_TYPE: - case ARRAY_TYPE: - pp_c_specifier_qualifier_list (pp, TREE_TYPE (t)); - break; - - case VECTOR_TYPE: - case COMPLEX_TYPE: - if (code == COMPLEX_TYPE) - pp_c_ws_string (pp, flag_isoc99 ? "_Complex" : "__complex__"); - else if (code == VECTOR_TYPE) - { - pp_c_ws_string (pp, "__vector"); - pp_c_left_paren (pp); - pp_wide_integer (pp, TYPE_VECTOR_SUBPARTS (t)); - pp_c_right_paren (pp); - pp_c_whitespace (pp); - } - pp_c_specifier_qualifier_list (pp, TREE_TYPE (t)); - break; - - default: - pp_simple_type_specifier (pp, t); - break; - } -} - -/* parameter-type-list: - parameter-list - parameter-list , ... - - parameter-list: - parameter-declaration - parameter-list , parameter-declaration - - parameter-declaration: - declaration-specifiers declarator - declaration-specifiers abstract-declarator(opt) */ - -void -pp_c_parameter_type_list (c_pretty_printer *pp, tree t) -{ - bool want_parm_decl = DECL_P (t) && !(pp->flags & pp_c_flag_abstract); - tree parms = want_parm_decl ? DECL_ARGUMENTS (t) : TYPE_ARG_TYPES (t); - pp_c_left_paren (pp); - if (parms == void_list_node) - pp_c_ws_string (pp, "void"); - else - { - bool first = true; - for ( ; parms && parms != void_list_node; parms = TREE_CHAIN (parms)) - { - if (!first) - pp_separate_with (pp, ','); - first = false; - pp_declaration_specifiers - (pp, want_parm_decl ? parms : TREE_VALUE (parms)); - if (want_parm_decl) - pp_declarator (pp, parms); - else - pp_abstract_declarator (pp, TREE_VALUE (parms)); - } - } - pp_c_right_paren (pp); -} - -/* abstract-declarator: - pointer - pointer(opt) direct-abstract-declarator */ - -static void -pp_c_abstract_declarator (c_pretty_printer *pp, tree t) -{ - if (TREE_CODE (t) == POINTER_TYPE) - { - if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE - || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) - pp_c_right_paren (pp); - t = TREE_TYPE (t); - } - - pp_direct_abstract_declarator (pp, t); -} - -/* direct-abstract-declarator: - ( abstract-declarator ) - direct-abstract-declarator(opt) [ assignment-expression(opt) ] - direct-abstract-declarator(opt) [ * ] - direct-abstract-declarator(opt) ( parameter-type-list(opt) ) */ - -void -pp_c_direct_abstract_declarator (c_pretty_printer *pp, tree t) -{ - switch (TREE_CODE (t)) - { - case POINTER_TYPE: - pp_abstract_declarator (pp, t); - break; - - case FUNCTION_TYPE: - pp_c_parameter_type_list (pp, t); - pp_direct_abstract_declarator (pp, TREE_TYPE (t)); - break; - - case ARRAY_TYPE: - pp_c_left_bracket (pp); - if (TYPE_DOMAIN (t) && TYPE_MAX_VALUE (TYPE_DOMAIN (t))) - { - tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (t)); - tree type = TREE_TYPE (maxval); - - if (host_integerp (maxval, 0)) - pp_wide_integer (pp, tree_low_cst (maxval, 0) + 1); - else - pp_expression (pp, fold_build2 (PLUS_EXPR, type, maxval, - build_int_cst (type, 1))); - } - pp_c_right_bracket (pp); - pp_direct_abstract_declarator (pp, TREE_TYPE (t)); - break; - - case IDENTIFIER_NODE: - case VOID_TYPE: - case BOOLEAN_TYPE: - case INTEGER_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - case ENUMERAL_TYPE: - case RECORD_TYPE: - case UNION_TYPE: - case VECTOR_TYPE: - case COMPLEX_TYPE: - case TYPE_DECL: - break; - - default: - pp_unsupported_tree (pp, t); - break; - } -} - -/* type-name: - specifier-qualifier-list abstract-declarator(opt) */ - -void -pp_c_type_id (c_pretty_printer *pp, tree t) -{ - pp_c_specifier_qualifier_list (pp, t); - pp_abstract_declarator (pp, t); -} - -/* storage-class-specifier: - typedef - extern - static - auto - register */ - -void -pp_c_storage_class_specifier (c_pretty_printer *pp, tree t) -{ - if (TREE_CODE (t) == TYPE_DECL) - pp_c_ws_string (pp, "typedef"); - else if (DECL_P (t)) - { - if (DECL_REGISTER (t)) - pp_c_ws_string (pp, "register"); - else if (TREE_STATIC (t) && TREE_CODE (t) == VAR_DECL) - pp_c_ws_string (pp, "static"); - } -} - -/* function-specifier: - inline */ - -void -pp_c_function_specifier (c_pretty_printer *pp, tree t) -{ - if (TREE_CODE (t) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (t)) - pp_c_ws_string (pp, "inline"); -} - -/* declaration-specifiers: - storage-class-specifier declaration-specifiers(opt) - type-specifier declaration-specifiers(opt) - type-qualifier declaration-specifiers(opt) - function-specifier declaration-specifiers(opt) */ - -void -pp_c_declaration_specifiers (c_pretty_printer *pp, tree t) -{ - pp_storage_class_specifier (pp, t); - pp_function_specifier (pp, t); - pp_c_specifier_qualifier_list (pp, DECL_P (t) ? TREE_TYPE (t) : t); -} - -/* direct-declarator - identifier - ( declarator ) - direct-declarator [ type-qualifier-list(opt) assignment-expression(opt) ] - direct-declarator [ static type-qualifier-list(opt) assignment-expression(opt)] - direct-declarator [ type-qualifier-list static assignment-expression ] - direct-declarator [ type-qualifier-list * ] - direct-declarator ( parameter-type-list ) - direct-declarator ( identifier-list(opt) ) */ - -void -pp_c_direct_declarator (c_pretty_printer *pp, tree t) -{ - switch (TREE_CODE (t)) - { - case VAR_DECL: - case PARM_DECL: - case TYPE_DECL: - case FIELD_DECL: - case LABEL_DECL: - pp_c_space_for_pointer_operator (pp, TREE_TYPE (t)); - pp_c_tree_decl_identifier (pp, t); - break; - - case ARRAY_TYPE: - case POINTER_TYPE: - pp_abstract_declarator (pp, TREE_TYPE (t)); - break; - - case FUNCTION_TYPE: - pp_parameter_list (pp, t); - pp_abstract_declarator (pp, TREE_TYPE (t)); - break; - - case FUNCTION_DECL: - pp_c_space_for_pointer_operator (pp, TREE_TYPE (TREE_TYPE (t))); - pp_c_tree_decl_identifier (pp, t); - if (pp_c_base (pp)->flags & pp_c_flag_abstract) - pp_abstract_declarator (pp, TREE_TYPE (t)); - else - { - pp_parameter_list (pp, t); - pp_abstract_declarator (pp, TREE_TYPE (TREE_TYPE (t))); - } - break; - - case INTEGER_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - case ENUMERAL_TYPE: - case UNION_TYPE: - case RECORD_TYPE: - break; - - default: - pp_unsupported_tree (pp, t); - break; - } -} - - -/* declarator: - pointer(opt) direct-declarator */ - -void -pp_c_declarator (c_pretty_printer *pp, tree t) -{ - switch (TREE_CODE (t)) - { - case INTEGER_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - case ENUMERAL_TYPE: - case UNION_TYPE: - case RECORD_TYPE: - break; - - case VAR_DECL: - case PARM_DECL: - case FIELD_DECL: - case ARRAY_TYPE: - case FUNCTION_TYPE: - case FUNCTION_DECL: - case TYPE_DECL: - pp_direct_declarator (pp, t); - break; - - - default: - pp_unsupported_tree (pp, t); - break; - } -} - -/* declaration: - declaration-specifiers init-declarator-list(opt) ; */ - -void -pp_c_declaration (c_pretty_printer *pp, tree t) -{ - pp_declaration_specifiers (pp, t); - pp_c_init_declarator (pp, t); -} - -/* Pretty-print ATTRIBUTES using GNU C extension syntax. */ - -void -pp_c_attributes (c_pretty_printer *pp, tree attributes) -{ - if (attributes == NULL_TREE) - return; - - pp_c_ws_string (pp, "__attribute__"); - pp_c_left_paren (pp); - pp_c_left_paren (pp); - for (; attributes != NULL_TREE; attributes = TREE_CHAIN (attributes)) - { - pp_tree_identifier (pp, TREE_PURPOSE (attributes)); - if (TREE_VALUE (attributes)) - pp_c_call_argument_list (pp, TREE_VALUE (attributes)); - - if (TREE_CHAIN (attributes)) - pp_separate_with (pp, ','); - } - pp_c_right_paren (pp); - pp_c_right_paren (pp); -} - -/* function-definition: - declaration-specifiers declarator compound-statement */ - -void -pp_c_function_definition (c_pretty_printer *pp, tree t) -{ - pp_declaration_specifiers (pp, t); - pp_declarator (pp, t); - pp_needs_newline (pp) = true; - pp_statement (pp, DECL_SAVED_TREE (t)); - pp_newline (pp); - pp_flush (pp); -} - - -/* Expressions. */ - -/* Print out a c-char. This is called solely for characters which are - in the *target* execution character set. We ought to convert them - back to the *host* execution character set before printing, but we - have no way to do this at present. A decent compromise is to print - all characters as if they were in the host execution character set, - and not attempt to recover any named escape characters, but render - all unprintables as octal escapes. If the host and target character - sets are the same, this produces relatively readable output. If they - are not the same, strings may appear as gibberish, but that's okay - (in fact, it may well be what the reader wants, e.g. if they are looking - to see if conversion to the target character set happened correctly). - - A special case: we need to prefix \, ", and ' with backslashes. It is - correct to do so for the *host*'s \, ", and ', because the rest of the - file appears in the host character set. */ - -static void -pp_c_char (c_pretty_printer *pp, int c) -{ - if (ISPRINT (c)) - { - switch (c) - { - case '\\': pp_string (pp, "\\\\"); break; - case '\'': pp_string (pp, "\\\'"); break; - case '\"': pp_string (pp, "\\\""); break; - default: pp_character (pp, c); - } - } - else - pp_scalar (pp, "\\%03o", (unsigned) c); -} - -/* Print out a STRING literal. */ - -void -pp_c_string_literal (c_pretty_printer *pp, tree s) -{ - const char *p = TREE_STRING_POINTER (s); - int n = TREE_STRING_LENGTH (s) - 1; - int i; - pp_doublequote (pp); - for (i = 0; i < n; ++i) - pp_c_char (pp, p[i]); - pp_doublequote (pp); -} - -/* Pretty-print an INTEGER literal. */ - -static void -pp_c_integer_constant (c_pretty_printer *pp, tree i) -{ - tree type = TREE_TYPE (i); - - if (TREE_INT_CST_HIGH (i) == 0) - pp_wide_integer (pp, TREE_INT_CST_LOW (i)); - else - { - unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (i); - HOST_WIDE_INT high = TREE_INT_CST_HIGH (i); - if (tree_int_cst_sgn (i) < 0) - { - pp_character (pp, '-'); - high = ~high + !low; - low = -low; - } - sprintf (pp_buffer (pp)->digit_buffer, HOST_WIDE_INT_PRINT_DOUBLE_HEX, - (unsigned HOST_WIDE_INT) high, (unsigned HOST_WIDE_INT) low); - pp_string (pp, pp_buffer (pp)->digit_buffer); - } - if (TYPE_UNSIGNED (type)) - pp_character (pp, 'u'); - if (type == long_integer_type_node || type == long_unsigned_type_node) - pp_character (pp, 'l'); - else if (type == long_long_integer_type_node - || type == long_long_unsigned_type_node) - pp_string (pp, "ll"); - else if (type == int128_integer_type_node - || type == int128_unsigned_type_node) - pp_string (pp, "I128"); -} - -/* Print out a CHARACTER literal. */ - -static void -pp_c_character_constant (c_pretty_printer *pp, tree c) -{ - tree type = TREE_TYPE (c); - if (type == wchar_type_node) - pp_character (pp, 'L'); - pp_quote (pp); - if (host_integerp (c, TYPE_UNSIGNED (type))) - pp_c_char (pp, tree_low_cst (c, TYPE_UNSIGNED (type))); - else - pp_scalar (pp, "\\x%x", (unsigned) TREE_INT_CST_LOW (c)); - pp_quote (pp); -} - -/* Print out a BOOLEAN literal. */ - -static void -pp_c_bool_constant (c_pretty_printer *pp, tree b) -{ - if (b == boolean_false_node) - { - if (c_dialect_cxx ()) - pp_c_ws_string (pp, "false"); - else if (flag_isoc99) - pp_c_ws_string (pp, "_False"); - else - pp_unsupported_tree (pp, b); - } - else if (b == boolean_true_node) - { - if (c_dialect_cxx ()) - pp_c_ws_string (pp, "true"); - else if (flag_isoc99) - pp_c_ws_string (pp, "_True"); - else - pp_unsupported_tree (pp, b); - } - else if (TREE_CODE (b) == INTEGER_CST) - pp_c_integer_constant (pp, b); - else - pp_unsupported_tree (pp, b); -} - -/* Attempt to print out an ENUMERATOR. Return true on success. Else return - false; that means the value was obtained by a cast, in which case - print out the type-id part of the cast-expression -- the casted value - is then printed by pp_c_integer_literal. */ - -static bool -pp_c_enumeration_constant (c_pretty_printer *pp, tree e) -{ - bool value_is_named = true; - tree type = TREE_TYPE (e); - tree value; - - /* Find the name of this constant. */ - for (value = TYPE_VALUES (type); - value != NULL_TREE && !tree_int_cst_equal (TREE_VALUE (value), e); - value = TREE_CHAIN (value)) - ; - - if (value != NULL_TREE) - pp_id_expression (pp, TREE_PURPOSE (value)); - else - { - /* Value must have been cast. */ - pp_c_type_cast (pp, type); - value_is_named = false; - } - - return value_is_named; -} - -/* Print out a REAL value as a decimal-floating-constant. */ - -static void -pp_c_floating_constant (c_pretty_printer *pp, tree r) -{ - real_to_decimal (pp_buffer (pp)->digit_buffer, &TREE_REAL_CST (r), - sizeof (pp_buffer (pp)->digit_buffer), 0, 1); - pp_string (pp, pp_buffer(pp)->digit_buffer); - if (TREE_TYPE (r) == float_type_node) - pp_character (pp, 'f'); - else if (TREE_TYPE (r) == long_double_type_node) - pp_character (pp, 'l'); - else if (TREE_TYPE (r) == dfloat128_type_node) - pp_string (pp, "dl"); - else if (TREE_TYPE (r) == dfloat64_type_node) - pp_string (pp, "dd"); - else if (TREE_TYPE (r) == dfloat32_type_node) - pp_string (pp, "df"); -} - -/* Print out a FIXED value as a decimal-floating-constant. */ - -static void -pp_c_fixed_constant (c_pretty_printer *pp, tree r) -{ - fixed_to_decimal (pp_buffer (pp)->digit_buffer, &TREE_FIXED_CST (r), - sizeof (pp_buffer (pp)->digit_buffer)); - pp_string (pp, pp_buffer(pp)->digit_buffer); -} - -/* Pretty-print a compound literal expression. GNU extensions include - vector constants. */ - -static void -pp_c_compound_literal (c_pretty_printer *pp, tree e) -{ - tree type = TREE_TYPE (e); - pp_c_type_cast (pp, type); - - switch (TREE_CODE (type)) - { - case RECORD_TYPE: - case UNION_TYPE: - case ARRAY_TYPE: - case VECTOR_TYPE: - case COMPLEX_TYPE: - pp_c_brace_enclosed_initializer_list (pp, e); - break; - - default: - pp_unsupported_tree (pp, e); - break; - } -} - -/* Pretty-print a COMPLEX_EXPR expression. */ - -static void -pp_c_complex_expr (c_pretty_printer *pp, tree e) -{ - /* Handle a few common special cases, otherwise fallback - to printing it as compound literal. */ - tree type = TREE_TYPE (e); - tree realexpr = TREE_OPERAND (e, 0); - tree imagexpr = TREE_OPERAND (e, 1); - - /* Cast of an COMPLEX_TYPE expression to a different COMPLEX_TYPE. */ - if (TREE_CODE (realexpr) == NOP_EXPR - && TREE_CODE (imagexpr) == NOP_EXPR - && TREE_TYPE (realexpr) == TREE_TYPE (type) - && TREE_TYPE (imagexpr) == TREE_TYPE (type) - && TREE_CODE (TREE_OPERAND (realexpr, 0)) == REALPART_EXPR - && TREE_CODE (TREE_OPERAND (imagexpr, 0)) == IMAGPART_EXPR - && TREE_OPERAND (TREE_OPERAND (realexpr, 0), 0) - == TREE_OPERAND (TREE_OPERAND (imagexpr, 0), 0)) - { - pp_c_type_cast (pp, type); - pp_expression (pp, TREE_OPERAND (TREE_OPERAND (realexpr, 0), 0)); - return; - } - - /* Cast of an scalar expression to COMPLEX_TYPE. */ - if ((integer_zerop (imagexpr) || real_zerop (imagexpr)) - && TREE_TYPE (realexpr) == TREE_TYPE (type)) - { - pp_c_type_cast (pp, type); - if (TREE_CODE (realexpr) == NOP_EXPR) - realexpr = TREE_OPERAND (realexpr, 0); - pp_expression (pp, realexpr); - return; - } - - pp_c_compound_literal (pp, e); -} - -/* constant: - integer-constant - floating-constant - fixed-point-constant - enumeration-constant - character-constant */ - -void -pp_c_constant (c_pretty_printer *pp, tree e) -{ - const enum tree_code code = TREE_CODE (e); - - switch (code) - { - case INTEGER_CST: - { - tree type = TREE_TYPE (e); - if (type == boolean_type_node) - pp_c_bool_constant (pp, e); - else if (type == char_type_node) - pp_c_character_constant (pp, e); - else if (TREE_CODE (type) == ENUMERAL_TYPE - && pp_c_enumeration_constant (pp, e)) - ; - else - pp_c_integer_constant (pp, e); - } - break; - - case REAL_CST: - pp_c_floating_constant (pp, e); - break; - - case FIXED_CST: - pp_c_fixed_constant (pp, e); - break; - - case STRING_CST: - pp_c_string_literal (pp, e); - break; - - case COMPLEX_CST: - /* Sometimes, we are confused and we think a complex literal - is a constant. Such thing is a compound literal which - grammatically belongs to postfix-expr production. */ - pp_c_compound_literal (pp, e); - break; - - default: - pp_unsupported_tree (pp, e); - break; - } -} - -/* Pretty-print a string such as an identifier, without changing its - encoding, preceded by whitespace is necessary. */ - -void -pp_c_ws_string (c_pretty_printer *pp, const char *str) -{ - pp_c_maybe_whitespace (pp); - pp_string (pp, str); - pp_base (pp)->padding = pp_before; -} - -/* Pretty-print an IDENTIFIER_NODE, which may contain UTF-8 sequences - that need converting to the locale encoding, preceded by whitespace - is necessary. */ - -void -pp_c_identifier (c_pretty_printer *pp, const char *id) -{ - pp_c_maybe_whitespace (pp); - pp_identifier (pp, id); - pp_base (pp)->padding = pp_before; -} - -/* Pretty-print a C primary-expression. - primary-expression: - identifier - constant - string-literal - ( expression ) */ - -void -pp_c_primary_expression (c_pretty_printer *pp, tree e) -{ - switch (TREE_CODE (e)) - { - case VAR_DECL: - case PARM_DECL: - case FIELD_DECL: - case CONST_DECL: - case FUNCTION_DECL: - case LABEL_DECL: - pp_c_tree_decl_identifier (pp, e); - break; - - case IDENTIFIER_NODE: - pp_c_tree_identifier (pp, e); - break; - - case ERROR_MARK: - pp_c_ws_string (pp, M_("")); - break; - - case RESULT_DECL: - pp_c_ws_string (pp, M_("")); - break; - - case INTEGER_CST: - case REAL_CST: - case FIXED_CST: - case STRING_CST: - pp_c_constant (pp, e); - break; - - case TARGET_EXPR: - pp_c_ws_string (pp, "__builtin_memcpy"); - pp_c_left_paren (pp); - pp_ampersand (pp); - pp_primary_expression (pp, TREE_OPERAND (e, 0)); - pp_separate_with (pp, ','); - pp_ampersand (pp); - pp_initializer (pp, TREE_OPERAND (e, 1)); - if (TREE_OPERAND (e, 2)) - { - pp_separate_with (pp, ','); - pp_c_expression (pp, TREE_OPERAND (e, 2)); - } - pp_c_right_paren (pp); - break; - - default: - /* FIXME: Make sure we won't get into an infinite loop. */ - pp_c_left_paren (pp); - pp_expression (pp, e); - pp_c_right_paren (pp); - break; - } -} - -/* Print out a C initializer -- also support C compound-literals. - initializer: - assignment-expression: - { initializer-list } - { initializer-list , } */ - -static void -pp_c_initializer (c_pretty_printer *pp, tree e) -{ - if (TREE_CODE (e) == CONSTRUCTOR) - pp_c_brace_enclosed_initializer_list (pp, e); - else - pp_expression (pp, e); -} - -/* init-declarator: - declarator: - declarator = initializer */ - -void -pp_c_init_declarator (c_pretty_printer *pp, tree t) -{ - pp_declarator (pp, t); - /* We don't want to output function definitions here. There are handled - elsewhere (and the syntactic form is bogus anyway). */ - if (TREE_CODE (t) != FUNCTION_DECL && DECL_INITIAL (t)) - { - tree init = DECL_INITIAL (t); - /* This C++ bit is handled here because it is easier to do so. - In templates, the C++ parser builds a TREE_LIST for a - direct-initialization; the TREE_PURPOSE is the variable to - initialize and the TREE_VALUE is the initializer. */ - if (TREE_CODE (init) == TREE_LIST) - { - pp_c_left_paren (pp); - pp_expression (pp, TREE_VALUE (init)); - pp_right_paren (pp); - } - else - { - pp_space (pp); - pp_equal (pp); - pp_space (pp); - pp_c_initializer (pp, init); - } - } -} - -/* initializer-list: - designation(opt) initializer - initializer-list , designation(opt) initializer - - designation: - designator-list = - - designator-list: - designator - designator-list designator - - designator: - [ constant-expression ] - identifier */ - -static void -pp_c_initializer_list (c_pretty_printer *pp, tree e) -{ - tree type = TREE_TYPE (e); - const enum tree_code code = TREE_CODE (type); - - if (TREE_CODE (e) == CONSTRUCTOR) - { - pp_c_constructor_elts (pp, CONSTRUCTOR_ELTS (e)); - return; - } - - switch (code) - { - case RECORD_TYPE: - case UNION_TYPE: - case ARRAY_TYPE: - { - tree init = TREE_OPERAND (e, 0); - for (; init != NULL_TREE; init = TREE_CHAIN (init)) - { - if (code == RECORD_TYPE || code == UNION_TYPE) - { - pp_c_dot (pp); - pp_c_primary_expression (pp, TREE_PURPOSE (init)); - } - else - { - pp_c_left_bracket (pp); - if (TREE_PURPOSE (init)) - pp_c_constant (pp, TREE_PURPOSE (init)); - pp_c_right_bracket (pp); - } - pp_c_whitespace (pp); - pp_equal (pp); - pp_c_whitespace (pp); - pp_initializer (pp, TREE_VALUE (init)); - if (TREE_CHAIN (init)) - pp_separate_with (pp, ','); - } - } - return; - - case VECTOR_TYPE: - if (TREE_CODE (e) == VECTOR_CST) - pp_c_expression_list (pp, TREE_VECTOR_CST_ELTS (e)); - else - break; - return; - - case COMPLEX_TYPE: - if (TREE_CODE (e) == COMPLEX_CST || TREE_CODE (e) == COMPLEX_EXPR) - { - const bool cst = TREE_CODE (e) == COMPLEX_CST; - pp_expression (pp, cst ? TREE_REALPART (e) : TREE_OPERAND (e, 0)); - pp_separate_with (pp, ','); - pp_expression (pp, cst ? TREE_IMAGPART (e) : TREE_OPERAND (e, 1)); - } - else - break; - return; - - default: - break; - } - - pp_unsupported_tree (pp, type); -} - -/* Pretty-print a brace-enclosed initializer-list. */ - -static void -pp_c_brace_enclosed_initializer_list (c_pretty_printer *pp, tree l) -{ - pp_c_left_brace (pp); - pp_c_initializer_list (pp, l); - pp_c_right_brace (pp); -} - - -/* This is a convenient function, used to bridge gap between C and C++ - grammars. - - id-expression: - identifier */ - -void -pp_c_id_expression (c_pretty_printer *pp, tree t) -{ - switch (TREE_CODE (t)) - { - case VAR_DECL: - case PARM_DECL: - case CONST_DECL: - case TYPE_DECL: - case FUNCTION_DECL: - case FIELD_DECL: - case LABEL_DECL: - pp_c_tree_decl_identifier (pp, t); - break; - - case IDENTIFIER_NODE: - pp_c_tree_identifier (pp, t); - break; - - default: - pp_unsupported_tree (pp, t); - break; - } -} - -/* 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 , } */ - -void -pp_c_postfix_expression (c_pretty_printer *pp, tree e) -{ - enum tree_code code = TREE_CODE (e); - switch (code) - { - case POSTINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - pp_postfix_expression (pp, TREE_OPERAND (e, 0)); - pp_string (pp, code == POSTINCREMENT_EXPR ? "++" : "--"); - break; - - case ARRAY_REF: - pp_postfix_expression (pp, TREE_OPERAND (e, 0)); - pp_c_left_bracket (pp); - pp_expression (pp, TREE_OPERAND (e, 1)); - pp_c_right_bracket (pp); - break; - - case CALL_EXPR: - { - call_expr_arg_iterator iter; - tree arg; - pp_postfix_expression (pp, CALL_EXPR_FN (e)); - pp_c_left_paren (pp); - FOR_EACH_CALL_EXPR_ARG (arg, iter, e) - { - pp_expression (pp, arg); - if (more_call_expr_args_p (&iter)) - pp_separate_with (pp, ','); - } - pp_c_right_paren (pp); - break; - } - - case UNORDERED_EXPR: - pp_c_ws_string (pp, flag_isoc99 - ? "isunordered" - : "__builtin_isunordered"); - goto two_args_fun; - - case ORDERED_EXPR: - pp_c_ws_string (pp, flag_isoc99 - ? "!isunordered" - : "!__builtin_isunordered"); - goto two_args_fun; - - case UNLT_EXPR: - pp_c_ws_string (pp, flag_isoc99 - ? "!isgreaterequal" - : "!__builtin_isgreaterequal"); - goto two_args_fun; - - case UNLE_EXPR: - pp_c_ws_string (pp, flag_isoc99 - ? "!isgreater" - : "!__builtin_isgreater"); - goto two_args_fun; - - case UNGT_EXPR: - pp_c_ws_string (pp, flag_isoc99 - ? "!islessequal" - : "!__builtin_islessequal"); - goto two_args_fun; - - case UNGE_EXPR: - pp_c_ws_string (pp, flag_isoc99 - ? "!isless" - : "!__builtin_isless"); - goto two_args_fun; - - case UNEQ_EXPR: - pp_c_ws_string (pp, flag_isoc99 - ? "!islessgreater" - : "!__builtin_islessgreater"); - goto two_args_fun; - - case LTGT_EXPR: - pp_c_ws_string (pp, flag_isoc99 - ? "islessgreater" - : "__builtin_islessgreater"); - goto two_args_fun; - - two_args_fun: - pp_c_left_paren (pp); - pp_expression (pp, TREE_OPERAND (e, 0)); - pp_separate_with (pp, ','); - pp_expression (pp, TREE_OPERAND (e, 1)); - pp_c_right_paren (pp); - break; - - case ABS_EXPR: - pp_c_ws_string (pp, "__builtin_abs"); - pp_c_left_paren (pp); - pp_expression (pp, TREE_OPERAND (e, 0)); - pp_c_right_paren (pp); - break; - - case COMPONENT_REF: - { - tree object = TREE_OPERAND (e, 0); - if (TREE_CODE (object) == INDIRECT_REF) - { - pp_postfix_expression (pp, TREE_OPERAND (object, 0)); - pp_c_arrow (pp); - } - else - { - pp_postfix_expression (pp, object); - pp_c_dot (pp); - } - pp_expression (pp, TREE_OPERAND (e, 1)); - } - break; - - case BIT_FIELD_REF: - { - tree type = TREE_TYPE (e); - - type = signed_or_unsigned_type_for (TYPE_UNSIGNED (type), type); - if (type - && tree_int_cst_equal (TYPE_SIZE (type), TREE_OPERAND (e, 1))) - { - HOST_WIDE_INT bitpos = tree_low_cst (TREE_OPERAND (e, 2), 0); - HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (type), 0); - if ((bitpos % size) == 0) - { - pp_c_left_paren (pp); - pp_c_left_paren (pp); - pp_type_id (pp, type); - pp_c_star (pp); - pp_c_right_paren (pp); - pp_c_ampersand (pp); - pp_expression (pp, TREE_OPERAND (e, 0)); - pp_c_right_paren (pp); - pp_c_left_bracket (pp); - pp_wide_integer (pp, bitpos / size); - pp_c_right_bracket (pp); - break; - } - } - pp_unsupported_tree (pp, e); - } - break; - - case COMPLEX_CST: - case VECTOR_CST: - pp_c_compound_literal (pp, e); - break; - - case COMPLEX_EXPR: - pp_c_complex_expr (pp, e); - break; - - case COMPOUND_LITERAL_EXPR: - e = DECL_INITIAL (COMPOUND_LITERAL_EXPR_DECL (e)); - /* Fall through. */ - case CONSTRUCTOR: - pp_initializer (pp, e); - break; - - case VA_ARG_EXPR: - pp_c_ws_string (pp, "__builtin_va_arg"); - pp_c_left_paren (pp); - pp_assignment_expression (pp, TREE_OPERAND (e, 0)); - pp_separate_with (pp, ','); - pp_type_id (pp, TREE_TYPE (e)); - pp_c_right_paren (pp); - break; - - case ADDR_EXPR: - if (TREE_CODE (TREE_OPERAND (e, 0)) == FUNCTION_DECL) - { - pp_c_id_expression (pp, TREE_OPERAND (e, 0)); - break; - } - /* else fall through. */ - - default: - pp_primary_expression (pp, e); - break; - } -} - -/* Print out an expression-list; E is expected to be a TREE_LIST. */ - -void -pp_c_expression_list (c_pretty_printer *pp, tree e) -{ - for (; e != NULL_TREE; e = TREE_CHAIN (e)) - { - pp_expression (pp, TREE_VALUE (e)); - if (TREE_CHAIN (e)) - pp_separate_with (pp, ','); - } -} - -/* Print out V, which contains the elements of a constructor. */ - -void -pp_c_constructor_elts (c_pretty_printer *pp, VEC(constructor_elt,gc) *v) -{ - unsigned HOST_WIDE_INT ix; - tree value; - - FOR_EACH_CONSTRUCTOR_VALUE (v, ix, value) - { - pp_expression (pp, value); - if (ix != VEC_length (constructor_elt, v) - 1) - pp_separate_with (pp, ','); - } -} - -/* Print out an expression-list in parens, as if it were the argument - list to a function. */ - -void -pp_c_call_argument_list (c_pretty_printer *pp, tree t) -{ - pp_c_left_paren (pp); - if (t && TREE_CODE (t) == TREE_LIST) - pp_c_expression_list (pp, t); - pp_c_right_paren (pp); -} - -/* unary-expression: - postfix-expression - ++ cast-expression - -- cast-expression - unary-operator cast-expression - sizeof unary-expression - sizeof ( type-id ) - - unary-operator: one of - * & + - ! ~ - - GNU extensions. - unary-expression: - __alignof__ unary-expression - __alignof__ ( type-id ) - __real__ unary-expression - __imag__ unary-expression */ - -void -pp_c_unary_expression (c_pretty_printer *pp, tree e) -{ - enum tree_code code = TREE_CODE (e); - switch (code) - { - case PREINCREMENT_EXPR: - case PREDECREMENT_EXPR: - pp_string (pp, code == PREINCREMENT_EXPR ? "++" : "--"); - pp_c_unary_expression (pp, TREE_OPERAND (e, 0)); - break; - - case ADDR_EXPR: - case INDIRECT_REF: - case NEGATE_EXPR: - case BIT_NOT_EXPR: - case TRUTH_NOT_EXPR: - case CONJ_EXPR: - /* String literal are used by address. */ - if (code == ADDR_EXPR && TREE_CODE (TREE_OPERAND (e, 0)) != STRING_CST) - pp_ampersand (pp); - else if (code == INDIRECT_REF) - pp_c_star (pp); - else if (code == NEGATE_EXPR) - pp_minus (pp); - else if (code == BIT_NOT_EXPR || code == CONJ_EXPR) - pp_complement (pp); - else if (code == TRUTH_NOT_EXPR) - pp_exclamation (pp); - pp_c_cast_expression (pp, TREE_OPERAND (e, 0)); - break; - - case REALPART_EXPR: - case IMAGPART_EXPR: - pp_c_ws_string (pp, code == REALPART_EXPR ? "__real__" : "__imag__"); - pp_c_whitespace (pp); - pp_unary_expression (pp, TREE_OPERAND (e, 0)); - break; - - default: - pp_postfix_expression (pp, e); - break; - } -} - -/* cast-expression: - unary-expression - ( type-name ) cast-expression */ - -void -pp_c_cast_expression (c_pretty_printer *pp, tree e) -{ - switch (TREE_CODE (e)) - { - case FLOAT_EXPR: - case FIX_TRUNC_EXPR: - CASE_CONVERT: - case VIEW_CONVERT_EXPR: - pp_c_type_cast (pp, TREE_TYPE (e)); - pp_c_cast_expression (pp, TREE_OPERAND (e, 0)); - break; - - default: - pp_unary_expression (pp, e); - } -} - -/* multiplicative-expression: - cast-expression - multiplicative-expression * cast-expression - multiplicative-expression / cast-expression - multiplicative-expression % cast-expression */ - -static void -pp_c_multiplicative_expression (c_pretty_printer *pp, tree e) -{ - enum tree_code code = TREE_CODE (e); - switch (code) - { - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case TRUNC_MOD_EXPR: - pp_multiplicative_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - if (code == MULT_EXPR) - pp_c_star (pp); - else if (code == TRUNC_DIV_EXPR) - pp_slash (pp); - else - pp_modulo (pp); - pp_c_whitespace (pp); - pp_c_cast_expression (pp, TREE_OPERAND (e, 1)); - break; - - default: - pp_c_cast_expression (pp, e); - break; - } -} - -/* additive-expression: - multiplicative-expression - additive-expression + multiplicative-expression - additive-expression - multiplicative-expression */ - -static void -pp_c_additive_expression (c_pretty_printer *pp, tree e) -{ - enum tree_code code = TREE_CODE (e); - switch (code) - { - case POINTER_PLUS_EXPR: - case PLUS_EXPR: - case MINUS_EXPR: - pp_c_additive_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) - pp_plus (pp); - else - pp_minus (pp); - pp_c_whitespace (pp); - pp_multiplicative_expression (pp, TREE_OPERAND (e, 1)); - break; - - default: - pp_multiplicative_expression (pp, e); - break; - } -} - -/* additive-expression: - additive-expression - shift-expression << additive-expression - shift-expression >> additive-expression */ - -static void -pp_c_shift_expression (c_pretty_printer *pp, tree e) -{ - enum tree_code code = TREE_CODE (e); - switch (code) - { - case LSHIFT_EXPR: - case RSHIFT_EXPR: - pp_c_shift_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - pp_string (pp, code == LSHIFT_EXPR ? "<<" : ">>"); - pp_c_whitespace (pp); - pp_c_additive_expression (pp, TREE_OPERAND (e, 1)); - break; - - default: - pp_c_additive_expression (pp, e); - } -} - -/* relational-expression: - shift-expression - relational-expression < shift-expression - relational-expression > shift-expression - relational-expression <= shift-expression - relational-expression >= shift-expression */ - -static void -pp_c_relational_expression (c_pretty_printer *pp, tree e) -{ - enum tree_code code = TREE_CODE (e); - switch (code) - { - case LT_EXPR: - case GT_EXPR: - case LE_EXPR: - case GE_EXPR: - pp_c_relational_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - if (code == LT_EXPR) - pp_less (pp); - else if (code == GT_EXPR) - pp_greater (pp); - else if (code == LE_EXPR) - pp_string (pp, "<="); - else if (code == GE_EXPR) - pp_string (pp, ">="); - pp_c_whitespace (pp); - pp_c_shift_expression (pp, TREE_OPERAND (e, 1)); - break; - - default: - pp_c_shift_expression (pp, e); - break; - } -} - -/* equality-expression: - relational-expression - equality-expression == relational-expression - equality-equality != relational-expression */ - -static void -pp_c_equality_expression (c_pretty_printer *pp, tree e) -{ - enum tree_code code = TREE_CODE (e); - switch (code) - { - case EQ_EXPR: - case NE_EXPR: - pp_c_equality_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - pp_string (pp, code == EQ_EXPR ? "==" : "!="); - pp_c_whitespace (pp); - pp_c_relational_expression (pp, TREE_OPERAND (e, 1)); - break; - - default: - pp_c_relational_expression (pp, e); - break; - } -} - -/* AND-expression: - equality-expression - AND-expression & equality-equality */ - -static void -pp_c_and_expression (c_pretty_printer *pp, tree e) -{ - if (TREE_CODE (e) == BIT_AND_EXPR) - { - pp_c_and_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - pp_ampersand (pp); - pp_c_whitespace (pp); - pp_c_equality_expression (pp, TREE_OPERAND (e, 1)); - } - else - pp_c_equality_expression (pp, e); -} - -/* exclusive-OR-expression: - AND-expression - exclusive-OR-expression ^ AND-expression */ - -static void -pp_c_exclusive_or_expression (c_pretty_printer *pp, tree e) -{ - if (TREE_CODE (e) == BIT_XOR_EXPR - || TREE_CODE (e) == TRUTH_XOR_EXPR) - { - pp_c_exclusive_or_expression (pp, TREE_OPERAND (e, 0)); - if (TREE_CODE (e) == BIT_XOR_EXPR) - pp_c_maybe_whitespace (pp); - else - pp_c_whitespace (pp); - pp_carret (pp); - pp_c_whitespace (pp); - pp_c_and_expression (pp, TREE_OPERAND (e, 1)); - } - else - pp_c_and_expression (pp, e); -} - -/* inclusive-OR-expression: - exclusive-OR-expression - inclusive-OR-expression | exclusive-OR-expression */ - -static void -pp_c_inclusive_or_expression (c_pretty_printer *pp, tree e) -{ - if (TREE_CODE (e) == BIT_IOR_EXPR) - { - pp_c_exclusive_or_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - pp_bar (pp); - pp_c_whitespace (pp); - pp_c_exclusive_or_expression (pp, TREE_OPERAND (e, 1)); - } - else - pp_c_exclusive_or_expression (pp, e); -} - -/* logical-AND-expression: - inclusive-OR-expression - logical-AND-expression && inclusive-OR-expression */ - -static void -pp_c_logical_and_expression (c_pretty_printer *pp, tree e) -{ - if (TREE_CODE (e) == TRUTH_ANDIF_EXPR - || TREE_CODE (e) == TRUTH_AND_EXPR) - { - pp_c_logical_and_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - pp_string (pp, "&&"); - pp_c_whitespace (pp); - pp_c_inclusive_or_expression (pp, TREE_OPERAND (e, 1)); - } - else - pp_c_inclusive_or_expression (pp, e); -} - -/* logical-OR-expression: - logical-AND-expression - logical-OR-expression || logical-AND-expression */ - -void -pp_c_logical_or_expression (c_pretty_printer *pp, tree e) -{ - if (TREE_CODE (e) == TRUTH_ORIF_EXPR - || TREE_CODE (e) == TRUTH_OR_EXPR) - { - pp_c_logical_or_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - pp_string (pp, "||"); - pp_c_whitespace (pp); - pp_c_logical_and_expression (pp, TREE_OPERAND (e, 1)); - } - else - pp_c_logical_and_expression (pp, e); -} - -/* conditional-expression: - logical-OR-expression - logical-OR-expression ? expression : conditional-expression */ - -static void -pp_c_conditional_expression (c_pretty_printer *pp, tree e) -{ - if (TREE_CODE (e) == COND_EXPR) - { - pp_c_logical_or_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - pp_question (pp); - pp_c_whitespace (pp); - pp_expression (pp, TREE_OPERAND (e, 1)); - pp_c_whitespace (pp); - pp_colon (pp); - pp_c_whitespace (pp); - pp_c_conditional_expression (pp, TREE_OPERAND (e, 2)); - } - else - pp_c_logical_or_expression (pp, e); -} - - -/* assignment-expression: - conditional-expression - unary-expression assignment-operator assignment-expression - - assignment-expression: one of - = *= /= %= += -= >>= <<= &= ^= |= */ - -static void -pp_c_assignment_expression (c_pretty_printer *pp, tree e) -{ - if (TREE_CODE (e) == MODIFY_EXPR - || TREE_CODE (e) == INIT_EXPR) - { - pp_c_unary_expression (pp, TREE_OPERAND (e, 0)); - pp_c_whitespace (pp); - pp_equal (pp); - pp_space (pp); - pp_c_expression (pp, TREE_OPERAND (e, 1)); - } - else - pp_c_conditional_expression (pp, e); -} - -/* expression: - assignment-expression - expression , assignment-expression - - Implementation note: instead of going through the usual recursion - chain, I take the liberty of dispatching nodes to the appropriate - functions. This makes some redundancy, but it worths it. That also - prevents a possible infinite recursion between pp_c_primary_expression () - and pp_c_expression (). */ - -void -pp_c_expression (c_pretty_printer *pp, tree e) -{ - switch (TREE_CODE (e)) - { - case INTEGER_CST: - pp_c_integer_constant (pp, e); - break; - - case REAL_CST: - pp_c_floating_constant (pp, e); - break; - - case FIXED_CST: - pp_c_fixed_constant (pp, e); - break; - - case STRING_CST: - pp_c_string_literal (pp, e); - break; - - case IDENTIFIER_NODE: - case FUNCTION_DECL: - case VAR_DECL: - case CONST_DECL: - case PARM_DECL: - case RESULT_DECL: - case FIELD_DECL: - case LABEL_DECL: - case ERROR_MARK: - pp_primary_expression (pp, e); - break; - - case POSTINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case ARRAY_REF: - case CALL_EXPR: - case COMPONENT_REF: - case BIT_FIELD_REF: - case COMPLEX_CST: - case COMPLEX_EXPR: - case VECTOR_CST: - case ORDERED_EXPR: - case UNORDERED_EXPR: - case LTGT_EXPR: - case UNEQ_EXPR: - case UNLE_EXPR: - case UNLT_EXPR: - case UNGE_EXPR: - case UNGT_EXPR: - case ABS_EXPR: - case CONSTRUCTOR: - case COMPOUND_LITERAL_EXPR: - case VA_ARG_EXPR: - pp_postfix_expression (pp, e); - break; - - case CONJ_EXPR: - case ADDR_EXPR: - case INDIRECT_REF: - case NEGATE_EXPR: - case BIT_NOT_EXPR: - case TRUTH_NOT_EXPR: - case PREINCREMENT_EXPR: - case PREDECREMENT_EXPR: - case REALPART_EXPR: - case IMAGPART_EXPR: - pp_c_unary_expression (pp, e); - break; - - case FLOAT_EXPR: - case FIX_TRUNC_EXPR: - CASE_CONVERT: - case VIEW_CONVERT_EXPR: - pp_c_cast_expression (pp, e); - break; - - case MULT_EXPR: - case TRUNC_MOD_EXPR: - case TRUNC_DIV_EXPR: - pp_multiplicative_expression (pp, e); - break; - - case LSHIFT_EXPR: - case RSHIFT_EXPR: - pp_c_shift_expression (pp, e); - break; - - case LT_EXPR: - case GT_EXPR: - case LE_EXPR: - case GE_EXPR: - pp_c_relational_expression (pp, e); - break; - - case BIT_AND_EXPR: - pp_c_and_expression (pp, e); - break; - - case BIT_XOR_EXPR: - case TRUTH_XOR_EXPR: - pp_c_exclusive_or_expression (pp, e); - break; - - case BIT_IOR_EXPR: - pp_c_inclusive_or_expression (pp, e); - break; - - case TRUTH_ANDIF_EXPR: - case TRUTH_AND_EXPR: - pp_c_logical_and_expression (pp, e); - break; - - case TRUTH_ORIF_EXPR: - case TRUTH_OR_EXPR: - pp_c_logical_or_expression (pp, e); - break; - - case EQ_EXPR: - case NE_EXPR: - pp_c_equality_expression (pp, e); - break; - - case COND_EXPR: - pp_conditional_expression (pp, e); - break; - - case POINTER_PLUS_EXPR: - case PLUS_EXPR: - case MINUS_EXPR: - pp_c_additive_expression (pp, e); - break; - - case MODIFY_EXPR: - case INIT_EXPR: - pp_assignment_expression (pp, e); - break; - - case COMPOUND_EXPR: - pp_c_left_paren (pp); - pp_expression (pp, TREE_OPERAND (e, 0)); - pp_separate_with (pp, ','); - pp_assignment_expression (pp, TREE_OPERAND (e, 1)); - pp_c_right_paren (pp); - break; - - case NON_LVALUE_EXPR: - case SAVE_EXPR: - pp_expression (pp, TREE_OPERAND (e, 0)); - break; - - case TARGET_EXPR: - pp_postfix_expression (pp, TREE_OPERAND (e, 1)); - break; - - case BIND_EXPR: - case GOTO_EXPR: - /* We don't yet have a way of dumping statements in a - human-readable format. */ - pp_string (pp, "({...})"); - break; - - default: - pp_unsupported_tree (pp, e); - break; - } -} - - - -/* Statements. */ - -void -pp_c_statement (c_pretty_printer *pp, tree stmt) -{ - if (stmt == NULL) - return; - - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - - dump_generic_node (pp_base (pp), stmt, pp_indentation (pp), 0, true); -} - - -/* Initialize the PRETTY-PRINTER for handling C codes. */ - -void -pp_c_pretty_printer_init (c_pretty_printer *pp) -{ - pp->offset_list = 0; - - pp->declaration = pp_c_declaration; - pp->declaration_specifiers = pp_c_declaration_specifiers; - pp->declarator = pp_c_declarator; - pp->direct_declarator = pp_c_direct_declarator; - pp->type_specifier_seq = pp_c_specifier_qualifier_list; - pp->abstract_declarator = pp_c_abstract_declarator; - pp->direct_abstract_declarator = pp_c_direct_abstract_declarator; - pp->ptr_operator = pp_c_pointer; - pp->parameter_list = pp_c_parameter_type_list; - pp->type_id = pp_c_type_id; - pp->simple_type_specifier = pp_c_type_specifier; - pp->function_specifier = pp_c_function_specifier; - pp->storage_class_specifier = pp_c_storage_class_specifier; - - pp->statement = pp_c_statement; - - pp->constant = pp_c_constant; - pp->id_expression = pp_c_id_expression; - pp->primary_expression = pp_c_primary_expression; - pp->postfix_expression = pp_c_postfix_expression; - pp->unary_expression = pp_c_unary_expression; - pp->initializer = pp_c_initializer; - pp->multiplicative_expression = pp_c_multiplicative_expression; - pp->conditional_expression = pp_c_conditional_expression; - pp->assignment_expression = pp_c_assignment_expression; - pp->expression = pp_c_expression; -} - - -/* Print the tree T in full, on file FILE. */ - -void -print_c_tree (FILE *file, tree t) -{ - static c_pretty_printer pp_rec; - static bool initialized = 0; - c_pretty_printer *pp = &pp_rec; - - if (!initialized) - { - initialized = 1; - pp_construct (pp_base (pp), NULL, 0); - pp_c_pretty_printer_init (pp); - pp_needs_newline (pp) = true; - } - pp_base (pp)->buffer->stream = file; - - pp_statement (pp, t); - - pp_newline (pp); - pp_flush (pp); -} - -/* Print the tree T in full, on stderr. */ - -DEBUG_FUNCTION void -debug_c_tree (tree t) -{ - print_c_tree (stderr, t); - fputc ('\n', stderr); -} - -/* Output the DECL_NAME of T. If T has no DECL_NAME, output a string made - up of T's memory address. */ - -void -pp_c_tree_decl_identifier (c_pretty_printer *pp, tree t) -{ - const char *name; - - gcc_assert (DECL_P (t)); - - if (DECL_NAME (t)) - name = IDENTIFIER_POINTER (DECL_NAME (t)); - else - { - static char xname[8]; - sprintf (xname, "", ((unsigned)((uintptr_t)(t) & 0xffff))); - name = xname; - } - - pp_c_identifier (pp, name); -} diff --git a/gcc/c-pretty-print.h b/gcc/c-pretty-print.h deleted file mode 100644 index 60ef0bc..0000000 --- a/gcc/c-pretty-print.h +++ /dev/null @@ -1,213 +0,0 @@ -/* Various declarations for the C and C++ pretty-printers. - Copyright (C) 2002, 2003, 2004, 2007, 2009 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 -. */ - -#ifndef GCC_C_PRETTY_PRINTER -#define GCC_C_PRETTY_PRINTER - -#include "tree.h" -#include "c-common.h" -#include "pretty-print.h" - - -typedef enum - { - pp_c_flag_abstract = 1 << 1, - pp_c_flag_last_bit = 2 - } pp_c_pretty_print_flags; - - -/* The data type used to bundle information necessary for pretty-printing - a C or C++ entity. */ -typedef struct c_pretty_print_info c_pretty_printer; - -/* The type of a C pretty-printer 'member' function. */ -typedef void (*c_pretty_print_fn) (c_pretty_printer *, tree); - -/* The datatype that contains information necessary for pretty-printing - a tree that represents a C construct. Any pretty-printer for a - language using C/c++ syntax can derive from this datatype and reuse - facilities provided here. It can do so by having a subobject of type - c_pretty_printer and override the macro pp_c_base to return a pointer - to that subobject. Such a pretty-printer has the responsibility to - initialize the pp_base() part, then call pp_c_pretty_printer_init - to set up the components that are specific to the C pretty-printer. - A derived pretty-printer can override any function listed in the - vtable below. See cp/cxx-pretty-print.h and cp/cxx-pretty-print.c - for an example of derivation. */ -struct c_pretty_print_info -{ - pretty_printer base; - /* Points to the first element of an array of offset-list. - Not used yet. */ - int *offset_list; - - pp_flags flags; - - /* These must be overridden by each of the C and C++ front-end to - reflect their understanding of syntactic productions when they differ. */ - c_pretty_print_fn declaration; - c_pretty_print_fn declaration_specifiers; - c_pretty_print_fn declarator; - c_pretty_print_fn abstract_declarator; - c_pretty_print_fn direct_abstract_declarator; - c_pretty_print_fn type_specifier_seq; - c_pretty_print_fn direct_declarator; - c_pretty_print_fn ptr_operator; - c_pretty_print_fn parameter_list; - c_pretty_print_fn type_id; - c_pretty_print_fn simple_type_specifier; - c_pretty_print_fn function_specifier; - c_pretty_print_fn storage_class_specifier; - c_pretty_print_fn initializer; - - c_pretty_print_fn statement; - - c_pretty_print_fn constant; - c_pretty_print_fn id_expression; - c_pretty_print_fn primary_expression; - c_pretty_print_fn postfix_expression; - c_pretty_print_fn unary_expression; - c_pretty_print_fn multiplicative_expression; - c_pretty_print_fn conditional_expression; - c_pretty_print_fn assignment_expression; - c_pretty_print_fn expression; -}; - -/* Override the pp_base macro. Derived pretty-printers should not - touch this macro. Instead they should override pp_c_base instead. */ -#undef pp_base -#define pp_base(PP) (&pp_c_base (PP)->base) - - -#define pp_c_tree_identifier(PPI, ID) \ - pp_c_identifier (PPI, IDENTIFIER_POINTER (ID)) - -#define pp_declaration(PPI, T) \ - pp_c_base (PPI)->declaration (pp_c_base (PPI), T) -#define pp_declaration_specifiers(PPI, D) \ - pp_c_base (PPI)->declaration_specifiers (pp_c_base (PPI), D) -#define pp_abstract_declarator(PP, D) \ - pp_c_base (PP)->abstract_declarator (pp_c_base (PP), D) -#define pp_type_specifier_seq(PPI, D) \ - pp_c_base (PPI)->type_specifier_seq (pp_c_base (PPI), D) -#define pp_declarator(PPI, D) \ - pp_c_base (PPI)->declarator (pp_c_base (PPI), D) -#define pp_direct_declarator(PPI, D) \ - pp_c_base (PPI)->direct_declarator (pp_c_base (PPI), D) -#define pp_direct_abstract_declarator(PP, D) \ - pp_c_base (PP)->direct_abstract_declarator (pp_c_base (PP), D) -#define pp_ptr_operator(PP, D) \ - pp_c_base (PP)->ptr_operator (pp_c_base (PP), D) -#define pp_parameter_list(PPI, T) \ - pp_c_base (PPI)->parameter_list (pp_c_base (PPI), T) -#define pp_type_id(PPI, D) \ - pp_c_base (PPI)->type_id (pp_c_base (PPI), D) -#define pp_simple_type_specifier(PP, T) \ - pp_c_base (PP)->simple_type_specifier (pp_c_base (PP), T) -#define pp_function_specifier(PP, D) \ - pp_c_base (PP)->function_specifier (pp_c_base (PP), D) -#define pp_storage_class_specifier(PP, D) \ - pp_c_base (PP)->storage_class_specifier (pp_c_base (PP), D); - -#define pp_statement(PPI, S) \ - pp_c_base (PPI)->statement (pp_c_base (PPI), S) - -#define pp_constant(PP, E) \ - pp_c_base (PP)->constant (pp_c_base (PP), E) -#define pp_id_expression(PP, E) \ - pp_c_base (PP)->id_expression (pp_c_base (PP), E) -#define pp_primary_expression(PPI, E) \ - pp_c_base (PPI)->primary_expression (pp_c_base (PPI), E) -#define pp_postfix_expression(PPI, E) \ - pp_c_base (PPI)->postfix_expression (pp_c_base (PPI), E) -#define pp_unary_expression(PPI, E) \ - pp_c_base (PPI)->unary_expression (pp_c_base (PPI), E) -#define pp_initializer(PPI, E) \ - pp_c_base (PPI)->initializer (pp_c_base (PPI), E) -#define pp_multiplicative_expression(PPI, E) \ - pp_c_base (PPI)->multiplicative_expression (pp_c_base (PPI), E) -#define pp_conditional_expression(PPI, E) \ - pp_c_base (PPI)->conditional_expression (pp_c_base (PPI), E) -#define pp_assignment_expression(PPI, E) \ - pp_c_base (PPI)->assignment_expression (pp_c_base (PPI), E) -#define pp_expression(PP, E) \ - pp_c_base (PP)->expression (pp_c_base (PP), E) - - -/* Returns the c_pretty_printer base object of PRETTY-PRINTER. This - macro must be overridden by any subclass of c_pretty_print_info. */ -#define pp_c_base(PP) (PP) - -extern void pp_c_pretty_printer_init (c_pretty_printer *); -void pp_c_whitespace (c_pretty_printer *); -void pp_c_left_paren (c_pretty_printer *); -void pp_c_right_paren (c_pretty_printer *); -void pp_c_left_brace (c_pretty_printer *); -void pp_c_right_brace (c_pretty_printer *); -void pp_c_left_bracket (c_pretty_printer *); -void pp_c_right_bracket (c_pretty_printer *); -void pp_c_dot (c_pretty_printer *); -void pp_c_ampersand (c_pretty_printer *); -void pp_c_star (c_pretty_printer *); -void pp_c_arrow (c_pretty_printer *); -void pp_c_semicolon (c_pretty_printer *); -void pp_c_complement (c_pretty_printer *); -void pp_c_exclamation (c_pretty_printer *); -void pp_c_space_for_pointer_operator (c_pretty_printer *, tree); - -/* Declarations. */ -void pp_c_tree_decl_identifier (c_pretty_printer *, tree); -void pp_c_function_definition (c_pretty_printer *, tree); -void pp_c_attributes (c_pretty_printer *, tree); -void pp_c_cv_qualifiers (c_pretty_printer *pp, int qualifiers, bool func_type); -void pp_c_type_qualifier_list (c_pretty_printer *, tree); -void pp_c_parameter_type_list (c_pretty_printer *, tree); -void pp_c_declaration (c_pretty_printer *, tree); -void pp_c_declaration_specifiers (c_pretty_printer *, tree); -void pp_c_declarator (c_pretty_printer *, tree); -void pp_c_direct_declarator (c_pretty_printer *, tree); -void pp_c_specifier_qualifier_list (c_pretty_printer *, tree); -void pp_c_function_specifier (c_pretty_printer *, tree); -void pp_c_type_id (c_pretty_printer *, tree); -void pp_c_direct_abstract_declarator (c_pretty_printer *, tree); -void pp_c_type_specifier (c_pretty_printer *, tree); -void pp_c_storage_class_specifier (c_pretty_printer *, tree); -/* Statements. */ -void pp_c_statement (c_pretty_printer *, tree); -/* Expressions. */ -void pp_c_expression (c_pretty_printer *, tree); -void pp_c_logical_or_expression (c_pretty_printer *, tree); -void pp_c_expression_list (c_pretty_printer *, tree); -void pp_c_constructor_elts (c_pretty_printer *, VEC(constructor_elt,gc) *); -void pp_c_call_argument_list (c_pretty_printer *, tree); -void pp_c_unary_expression (c_pretty_printer *, tree); -void pp_c_cast_expression (c_pretty_printer *, tree); -void pp_c_postfix_expression (c_pretty_printer *, tree); -void pp_c_primary_expression (c_pretty_printer *, tree); -void pp_c_init_declarator (c_pretty_printer *, tree); -void pp_c_constant (c_pretty_printer *, tree); -void pp_c_id_expression (c_pretty_printer *, tree); -void pp_c_ws_string (c_pretty_printer *, const char *); -void pp_c_identifier (c_pretty_printer *, const char *); -void pp_c_string_literal (c_pretty_printer *, tree); - -void print_c_tree (FILE *file, tree t); - -#endif /* GCC_C_PRETTY_PRINTER */ diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c deleted file mode 100644 index 683655f..0000000 --- a/gcc/c-semantics.c +++ /dev/null @@ -1,146 +0,0 @@ -/* This file contains subroutine used by the C front-end to construct GENERIC. - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 - Free Software Foundation, Inc. - Written by Benjamin Chelf (chelf@codesourcery.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 "tree.h" -#include "function.h" -#include "splay-tree.h" -#include "c-common.h" -/* In order for the format checking to accept the C frontend - diagnostic framework extensions, you must define this token before - including toplev.h. */ -#define GCC_DIAG_STYLE __gcc_cdiag__ -#include "toplev.h" -#include "flags.h" -#include "output.h" -#include "tree-iterator.h" - -/* Create an empty statement tree rooted at T. */ - -tree -push_stmt_list (void) -{ - tree t; - t = alloc_stmt_list (); - TREE_CHAIN (t) = cur_stmt_list; - cur_stmt_list = t; - return t; -} - -/* Finish the statement tree rooted at T. */ - -tree -pop_stmt_list (tree t) -{ - tree u = cur_stmt_list, chain; - - /* Pop statement lists until we reach the target level. The extra - nestings will be due to outstanding cleanups. */ - while (1) - { - chain = TREE_CHAIN (u); - TREE_CHAIN (u) = NULL_TREE; - if (chain) - STATEMENT_LIST_HAS_LABEL (chain) |= STATEMENT_LIST_HAS_LABEL (u); - if (t == u) - break; - u = chain; - } - cur_stmt_list = chain; - - /* If the statement list is completely empty, just return it. This is - just as good small as build_empty_stmt, with the advantage that - statement lists are merged when they appended to one another. So - using the STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P - statements. */ - if (TREE_SIDE_EFFECTS (t)) - { - tree_stmt_iterator i = tsi_start (t); - - /* If the statement list contained exactly one statement, then - extract it immediately. */ - if (tsi_one_before_end_p (i)) - { - u = tsi_stmt (i); - tsi_delink (&i); - free_stmt_list (t); - t = u; - } - } - - return t; -} - -/* Build a generic statement based on the given type of node and - arguments. Similar to `build_nt', except that we set - EXPR_LOCATION to LOC. */ -/* ??? This should be obsolete with the lineno_stmt productions - in the grammar. */ - -tree -build_stmt (location_t loc, enum tree_code code, ...) -{ - tree ret; - int length, i; - va_list p; - bool side_effects; - - /* This function cannot be used to construct variably-sized nodes. */ - gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp); - - va_start (p, code); - - ret = make_node (code); - TREE_TYPE (ret) = void_type_node; - length = TREE_CODE_LENGTH (code); - SET_EXPR_LOCATION (ret, loc); - - /* TREE_SIDE_EFFECTS will already be set for statements with - implicit side effects. Here we make sure it is set for other - expressions by checking whether the parameters have side - effects. */ - - side_effects = false; - for (i = 0; i < length; i++) - { - tree t = va_arg (p, tree); - if (t && !TYPE_P (t)) - side_effects |= TREE_SIDE_EFFECTS (t); - TREE_OPERAND (ret, i) = t; - } - - TREE_SIDE_EFFECTS (ret) |= side_effects; - - va_end (p); - return ret; -} - -/* Create a CASE_LABEL_EXPR tree node and return it. */ - -tree -build_case_label (location_t loc, - tree low_value, tree high_value, tree label_decl) -{ - return build_stmt (loc, CASE_LABEL_EXPR, low_value, high_value, label_decl); -} diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 1921e19..a607ecd 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_C_TREE_H #define GCC_C_TREE_H -#include "c-common.h" +#include "c-family/c-common.h" #include "toplev.h" #include "diagnostic.h" diff --git a/gcc/c.opt b/gcc/c.opt deleted file mode 100644 index 01d6428..0000000 --- a/gcc/c.opt +++ /dev/null @@ -1,1060 +0,0 @@ -; Options for the C, ObjC, C++ and ObjC++ front ends. -; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 -; 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 -; . - -; See the GCC internals manual for a description of this file's format. - -; Please try to keep this file in ASCII collating order. - -Language -C - -Language -ObjC - -Language -C++ - -Language -ObjC++ - --output-pch= -C ObjC C++ ObjC++ Joined Separate - -A -C ObjC C++ ObjC++ Joined Separate --A= Assert the to . Putting '-' before disables the to - -C -C ObjC C++ ObjC++ -Do not discard comments - -CC -C ObjC C++ ObjC++ -Do not discard comments in macro expansions - -D -C ObjC C++ ObjC++ Joined Separate --D[=] Define a with as its value. If just is given, is taken to be 1 - -E -C ObjC C++ ObjC++ Undocumented - -F -C ObjC C++ ObjC++ Joined Separate --F Add to the end of the main framework include path - -H -C ObjC C++ ObjC++ -Print the name of header files as they are used - -I -C ObjC C++ ObjC++ Joined Separate --I Add to the end of the main include path - -M -C ObjC C++ ObjC++ -Generate make dependencies - -MD -C ObjC C++ ObjC++ Separate -Generate make dependencies and compile - -MF -C ObjC C++ ObjC++ Joined Separate --MF Write dependency output to the given file - -MG -C ObjC C++ ObjC++ -Treat missing header files as generated files - -MM -C ObjC C++ ObjC++ -Like -M but ignore system header files - -MMD -C ObjC C++ ObjC++ Separate -Like -MD but ignore system header files - -MP -C ObjC C++ ObjC++ -Generate phony targets for all headers - -MQ -C ObjC C++ ObjC++ Joined Separate --MQ Add a MAKE-quoted target - -MT -C ObjC C++ ObjC++ Joined Separate --MT Add an unquoted target - -P -C ObjC C++ ObjC++ -Do not generate #line directives - -U -C ObjC C++ ObjC++ Joined Separate --U Undefine - -Wabi -C ObjC C++ ObjC++ LTO Var(warn_abi) Warning -Warn about things that will change when compiling with an ABI-compliant compiler - -Wpsabi -C ObjC C++ ObjC++ LTO Var(warn_psabi) Init(1) Undocumented - -Waddress -C ObjC C++ ObjC++ Var(warn_address) Warning -Warn about suspicious uses of memory addresses - -Wall -C ObjC C++ ObjC++ Warning -Enable most warning messages - -Wassign-intercept -ObjC ObjC++ Var(warn_assign_intercept) Warning -Warn whenever an Objective-C assignment is being intercepted by the garbage collector - -Wbad-function-cast -C ObjC Var(warn_bad_function_cast) Warning -Warn about casting functions to incompatible types - -Wbuiltin-macro-redefined -C ObjC C++ ObjC++ Warning -Warn when a built-in preprocessor macro is undefined or redefined - -Wc++-compat -C ObjC Var(warn_cxx_compat) Warning -Warn about C constructs that are not in the common subset of C and C++ - -Wc++0x-compat -C++ ObjC++ Var(warn_cxx0x_compat) Warning -Warn about C++ constructs whose meaning differs between ISO C++ 1998 and ISO C++ 200x - -Wcast-qual -C ObjC C++ ObjC++ Var(warn_cast_qual) Warning -Warn about casts which discard qualifiers - -Wchar-subscripts -C ObjC C++ ObjC++ Var(warn_char_subscripts) Warning -Warn about subscripts whose type is \"char\" - -Wclobbered -C ObjC C++ ObjC++ Var(warn_clobbered) Init(-1) Warning -Warn about variables that might be changed by \"longjmp\" or \"vfork\" - -Wcomment -C ObjC C++ ObjC++ Warning -Warn about possibly nested block comments, and C++ comments spanning more than one physical line - -Wcomments -C ObjC C++ ObjC++ Warning -Synonym for -Wcomment - -Wconversion -C ObjC C++ ObjC++ Var(warn_conversion) Warning -Warn for implicit type conversions that may change a value - -Wconversion-null -C++ ObjC++ Var(warn_conversion_null) Init(1) Warning -Warn for converting NULL from/to a non-pointer type - -Wsign-conversion -C ObjC C++ ObjC++ Var(warn_sign_conversion) Init(-1) -Warn for implicit type conversions between signed and unsigned integers - -Wctor-dtor-privacy -C++ ObjC++ Var(warn_ctor_dtor_privacy) Warning -Warn when all constructors and destructors are private - -Wdeclaration-after-statement -C ObjC Var(warn_declaration_after_statement) Warning -Warn when a declaration is found after a statement - -Wdeprecated -C C++ ObjC ObjC++ Var(warn_deprecated) Init(1) Warning -Warn if a deprecated compiler feature, class, method, or field is used - -Wdiv-by-zero -C ObjC C++ ObjC++ Var(warn_div_by_zero) Init(1) Warning -Warn about compile-time integer division by zero - -Weffc++ -C++ ObjC++ Var(warn_ecpp) Warning -Warn about violations of Effective C++ style rules - -Wempty-body -C ObjC C++ ObjC++ Var(warn_empty_body) Init(-1) Warning -Warn about an empty body in an if or else statement - -Wendif-labels -C ObjC C++ ObjC++ Warning -Warn about stray tokens after #elif and #endif - -Wenum-compare -C ObjC C++ ObjC++ Var(warn_enum_compare) Init(-1) Warning -Warn about comparison of different enum types - -Werror -C ObjC C++ ObjC++ -; Documented in common.opt - -Werror-implicit-function-declaration -C ObjC RejectNegative Warning -This switch is deprecated; use -Werror=implicit-function-declaration instead - -Wfloat-equal -C ObjC C++ ObjC++ Var(warn_float_equal) Warning -Warn if testing floating point numbers for equality - -Wformat -C ObjC C++ ObjC++ Warning -Warn about printf/scanf/strftime/strfmon format string anomalies - -Wformat-extra-args -C ObjC C++ ObjC++ Var(warn_format_extra_args) Warning -Warn if passing too many arguments to a function for its format string - -Wformat-nonliteral -C ObjC C++ ObjC++ Var(warn_format_nonliteral) Warning -Warn about format strings that are not literals - -Wformat-contains-nul -C ObjC C++ ObjC++ Var(warn_format_contains_nul) Warning -Warn about format strings that contain NUL bytes - -Wformat-security -C ObjC C++ ObjC++ Var(warn_format_security) Warning -Warn about possible security problems with format functions - -Wformat-y2k -C ObjC C++ ObjC++ Var(warn_format_y2k) Warning -Warn about strftime formats yielding 2-digit years - -Wformat-zero-length -C ObjC Var(warn_format_zero_length) Warning -Warn about zero-length formats - -Wformat= -C ObjC C++ ObjC++ Joined Warning - -Wignored-qualifiers -C C++ Var(warn_ignored_qualifiers) Init(-1) Warning -Warn whenever type qualifiers are ignored. - -Winit-self -C ObjC C++ ObjC++ Var(warn_init_self) Warning -Warn about variables which are initialized to themselves - -Wimplicit -C ObjC Var(warn_implicit) Init(-1) Warning -Warn about implicit declarations - -Wimplicit-function-declaration -C ObjC Var(warn_implicit_function_declaration) Init(-1) Warning -Warn about implicit function declarations - -Wimplicit-int -C ObjC Var(warn_implicit_int) Init(-1) Warning -Warn when a declaration does not specify a type - -Wimport -C ObjC C++ ObjC++ Undocumented - -Wint-to-pointer-cast -C ObjC C++ ObjC++ Var(warn_int_to_pointer_cast) Init(1) Warning -Warn when there is a cast to a pointer from an integer of a different size - -Winvalid-offsetof -C++ ObjC++ Var(warn_invalid_offsetof) Init(1) Warning -Warn about invalid uses of the \"offsetof\" macro - -Winvalid-pch -C ObjC C++ ObjC++ Warning -Warn about PCH files that are found but not used - -Wjump-misses-init -C ObjC Var(warn_jump_misses_init) Init(-1) Warning -Warn when a jump misses a variable initialization - -Wlogical-op -C ObjC C++ ObjC++ Var(warn_logical_op) Init(0) Warning -Warn when a logical operator is suspiciously always evaluating to true or false - -Wlong-long -C ObjC C++ ObjC++ Var(warn_long_long) Init(-1) Warning -Do not warn about using \"long long\" when -pedantic - -Wmain -C ObjC C++ ObjC++ Var(warn_main) Init(-1) Warning -Warn about suspicious declarations of \"main\" - -Wmissing-braces -C ObjC C++ ObjC++ Var(warn_missing_braces) Warning -Warn about possibly missing braces around initializers - -Wmissing-declarations -C ObjC C++ ObjC++ Var(warn_missing_declarations) Warning -Warn about global functions without previous declarations - -Wmissing-field-initializers -C ObjC C++ ObjC++ Var(warn_missing_field_initializers) Init(-1) Warning -Warn about missing fields in struct initializers - -Wmissing-format-attribute -C ObjC C++ ObjC++ Var(warn_missing_format_attribute) Warning -Warn about functions which might be candidates for format attributes - -Wmissing-include-dirs -C ObjC C++ ObjC++ Warning -Warn about user-specified include directories that do not exist - -Wmissing-parameter-type -C ObjC Var(warn_missing_parameter_type) Init(-1) Warning -Warn about function parameters declared without a type specifier in K&R-style functions - -Wmissing-prototypes -C ObjC Var(warn_missing_prototypes) Warning -Warn about global functions without prototypes - -Wmultichar -C ObjC C++ ObjC++ Warning -Warn about use of multi-character character constants - -Wnested-externs -C ObjC Var(warn_nested_externs) Warning -Warn about \"extern\" declarations not at file scope - -Wnon-template-friend -C++ ObjC++ Var(warn_nontemplate_friend) Init(1) Warning -Warn when non-templatized friend functions are declared within a template - -Wnon-virtual-dtor -C++ ObjC++ Var(warn_nonvdtor) Warning -Warn about non-virtual destructors - -Wnonnull -C ObjC Var(warn_nonnull) Warning -Warn about NULL being passed to argument slots marked as requiring non-NULL - -Wnormalized= -C ObjC C++ ObjC++ Joined Warning --Wnormalized= Warn about non-normalised Unicode strings - -Wold-style-cast -C++ ObjC++ Var(warn_old_style_cast) Warning -Warn if a C-style cast is used in a program - -Wold-style-declaration -C ObjC Var(warn_old_style_declaration) Init(-1) Warning -Warn for obsolescent usage in a declaration - -Wold-style-definition -C ObjC Var(warn_old_style_definition) Warning -Warn if an old-style parameter definition is used - -Woverlength-strings -C ObjC C++ ObjC++ Var(warn_overlength_strings) Init(-1) Warning -Warn if a string is longer than the maximum portable length specified by the standard - -Woverloaded-virtual -C++ ObjC++ Var(warn_overloaded_virtual) Warning -Warn about overloaded virtual function names - -Woverride-init -C ObjC Var(warn_override_init) Init(-1) Warning -Warn about overriding initializers without side effects - -Wpacked-bitfield-compat -C ObjC C++ ObjC++ Var(warn_packed_bitfield_compat) Init(-1) Warning -Warn about packed bit-fields whose offset changed in GCC 4.4 - -Wparentheses -C ObjC C++ ObjC++ Var(warn_parentheses) Warning -Warn about possibly missing parentheses - -Wpmf-conversions -C++ ObjC++ Var(warn_pmf2ptr) Init(1) Warning -Warn when converting the type of pointers to member functions - -Wpointer-arith -C ObjC C++ ObjC++ Var(warn_pointer_arith) Warning -Warn about function pointer arithmetic - -Wpointer-to-int-cast -C ObjC Var(warn_pointer_to_int_cast) Init(1) Warning -Warn when a pointer is cast to an integer of a different size - -Wpragmas -C ObjC C++ ObjC++ Var(warn_pragmas) Init(1) Warning -Warn about misuses of pragmas - -Wprotocol -ObjC ObjC++ Var(warn_protocol) Init(1) Warning -Warn if inherited methods are unimplemented - -Wredundant-decls -C ObjC C++ ObjC++ Var(warn_redundant_decls) Warning -Warn about multiple declarations of the same object - -Wreorder -C++ ObjC++ Var(warn_reorder) Warning -Warn when the compiler reorders code - -Wreturn-type -C ObjC C++ ObjC++ Var(warn_return_type) Warning -Warn whenever a function's return type defaults to \"int\" (C), or about inconsistent return types (C++) - -Wselector -ObjC ObjC++ Var(warn_selector) Warning -Warn if a selector has multiple methods - -Wsequence-point -C ObjC C++ ObjC++ Var(warn_sequence_point) Warning -Warn about possible violations of sequence point rules - -Wsign-compare -C ObjC C++ ObjC++ Var(warn_sign_compare) Init(-1) Warning -Warn about signed-unsigned comparisons - -Wsign-promo -C++ ObjC++ Var(warn_sign_promo) Warning -Warn when overload promotes from unsigned to signed - -Wstrict-null-sentinel -C++ ObjC++ Warning -Warn about uncasted NULL used as sentinel - -Wstrict-prototypes -C ObjC Var(warn_strict_prototypes) Warning -Warn about unprototyped function declarations - -Wstrict-selector-match -ObjC ObjC++ Var(warn_strict_selector_match) Warning -Warn if type signatures of candidate methods do not match exactly - -Wsync-nand -C C++ Var(warn_sync_nand) Init(1) Warning -Warn when __sync_fetch_and_nand and __sync_nand_and_fetch built-in functions are used - -Wsynth -C++ ObjC++ Var(warn_synth) Warning -Deprecated. This switch has no effect - -Wsystem-headers -C ObjC C++ ObjC++ Warning -; Documented in common.opt - -Wtraditional -C ObjC Var(warn_traditional) Warning -Warn about features not present in traditional C - -Wtraditional-conversion -C ObjC Var(warn_traditional_conversion) Warning -Warn of prototypes causing type conversions different from what would happen in the absence of prototype - -Wtrigraphs -C ObjC C++ ObjC++ Warning -Warn if trigraphs are encountered that might affect the meaning of the program - -Wundeclared-selector -ObjC ObjC++ Var(warn_undeclared_selector) Warning -Warn about @selector()s without previously declared methods - -Wundef -C ObjC C++ ObjC++ Warning -Warn if an undefined macro is used in an #if directive - -Wunknown-pragmas -C ObjC C++ ObjC++ Warning -Warn about unrecognized pragmas - -Wunsuffixed-float-constants -C ObjC Var(warn_unsuffixed_float_constants) Warning -Warn about unsuffixed float constants - -Wunused-macros -C ObjC C++ ObjC++ Warning -Warn about macros defined in the main file that are not used - -Wunused-result -C ObjC C++ ObjC++ Var(warn_unused_result) Init(1) Warning -Warn if a caller of a function, marked with attribute warn_unused_result, does not use its return value - -Wvariadic-macros -C ObjC C++ ObjC++ Warning -Do not warn about using variadic macros when -pedantic - -Wvla -C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning -Warn if a variable length array is used - -Wvolatile-register-var -C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning -Warn when a register variable is declared volatile - -Wwrite-strings -C ObjC C++ ObjC++ Var(warn_write_strings) Warning -In C++, nonzero means warn about deprecated conversion from string literals to `char *'. In C, similar warning, except that the conversion is of course not deprecated by the ISO C standard. - -Wpointer-sign -C ObjC Var(warn_pointer_sign) Init(-1) Warning -Warn when a pointer differs in signedness in an assignment - -ansi -C ObjC C++ ObjC++ -A synonym for -std=c89 (for C) or -std=c++98 (for C++) - -d -C ObjC C++ ObjC++ Joined -; Documented in common.opt. FIXME - what about -dI, -dD, -dN and -dD? - -faccess-control -C++ ObjC++ -Enforce class member access control semantics - -fall-virtual -C++ ObjC++ - -falt-external-templates -C++ ObjC++ -Change when template instances are emitted - -fasm -C ObjC C++ ObjC++ -Recognize the \"asm\" keyword - -fbuiltin -C ObjC C++ ObjC++ -Recognize built-in functions - -fbuiltin- -C ObjC C++ ObjC++ Joined - -fcheck-new -C++ ObjC++ -Check the return value of new - -fcond-mismatch -C ObjC C++ ObjC++ -Allow the arguments of the '?' operator to have different types - -fconserve-space -C++ ObjC++ -Reduce the size of object files - -fconstant-string-class= -ObjC ObjC++ Joined --fconst-string-class= Use class for constant strings - -fdeduce-init-list -C++ ObjC++ Var(flag_deduce_init_list) Init(1) --fno-deduce-init-list disable deduction of std::initializer_list for a template type parameter from a brace-enclosed initializer-list - -fdefault-inline -C++ ObjC++ -Inline member functions by default - -fdirectives-only -C ObjC C++ ObjC++ -Preprocess directives only. - -fdollars-in-identifiers -C ObjC C++ ObjC++ -Permit '$' as an identifier character - -felide-constructors -C++ ObjC++ - -fenforce-eh-specs -C++ ObjC++ -Generate code to check exception specifications - -fenum-int-equiv -C++ ObjC++ - -fexec-charset= -C ObjC C++ ObjC++ Joined RejectNegative --fexec-charset= Convert all strings and character constants to character set - -fextended-identifiers -C ObjC C++ ObjC++ -Permit universal character names (\\u and \\U) in identifiers - -finput-charset= -C ObjC C++ ObjC++ Joined RejectNegative --finput-charset= Specify the default character set for source files - - -fexternal-templates -C++ ObjC++ - -ffor-scope -C++ ObjC++ -Scope of for-init-statement variables is local to the loop - -ffreestanding -C ObjC C++ ObjC++ -Do not assume that standard C libraries and \"main\" exist - -fgnu-keywords -C++ ObjC++ -Recognize GNU-defined keywords - -fgnu-runtime -ObjC ObjC++ -Generate code for GNU runtime environment - -fgnu89-inline -C ObjC Var(flag_gnu89_inline) Init(-1) -Use traditional GNU semantics for inline functions - -fguiding-decls -C++ ObjC++ - -fhandle-exceptions -C++ ObjC++ Optimization - -fhonor-std -C++ ObjC++ - -fhosted -C ObjC -Assume normal C execution environment - -fhuge-objects -C++ ObjC++ -Enable support for huge objects - -fimplement-inlines -C++ ObjC++ -Export functions even if they can be inlined - -fimplicit-inline-templates -C++ ObjC++ -Emit implicit instantiations of inline templates - -fimplicit-templates -C++ ObjC++ -Emit implicit instantiations of templates - -ffriend-injection -C++ ObjC++ Var(flag_friend_injection) -Inject friend functions into enclosing namespace - -flabels-ok -C++ ObjC++ - -flax-vector-conversions -C ObjC C++ ObjC++ -Allow implicit conversions between vectors with differing numbers of subparts and/or differing element types. - -fms-extensions -C ObjC C++ ObjC++ -Don't warn about uses of Microsoft extensions - -fname-mangling-version- -C++ ObjC++ Joined - -fnew-abi -C++ ObjC++ - -fnext-runtime -ObjC ObjC++ -Generate code for NeXT (Apple Mac OS X) runtime environment - -fnil-receivers -ObjC ObjC++ -Assume that receivers of Objective-C messages may be nil - -fnonansi-builtins -C++ ObjC++ - -fnonnull-objects -C++ ObjC++ - -fnothrow-opt -C++ ObjC++ Optimization Var(flag_nothrow_opt) -Treat a throw() exception specification as noexcept to improve code size - -; Generate special '- .cxx_construct' and '- .cxx_destruct' methods -; to initialize any non-POD ivars in Objective-C++ classes. -fobjc-call-cxx-cdtors -ObjC++ Var(flag_objc_call_cxx_cdtors) -Generate special Objective-C methods to initialize/destroy non-POD C++ ivars, if needed - -fobjc-direct-dispatch -ObjC ObjC++ Var(flag_objc_direct_dispatch) -Allow fast jumps to the message dispatcher - -; Nonzero means that we will allow new ObjC exception syntax (@throw, -; @try, etc.) in source code. -fobjc-exceptions -ObjC ObjC++ Var(flag_objc_exceptions) -Enable Objective-C exception and synchronization syntax - -fobjc-gc -ObjC ObjC++ Var(flag_objc_gc) -Enable garbage collection (GC) in Objective-C/Objective-C++ programs - -; Nonzero means that we generate NeXT setjmp based exceptions. -fobjc-sjlj-exceptions -ObjC ObjC++ Var(flag_objc_sjlj_exceptions) Init(-1) -Enable Objective-C setjmp exception handling runtime - -fopenmp -C ObjC C++ ObjC++ Var(flag_openmp) -Enable OpenMP (implies -frecursive in Fortran) - -foperator-names -C++ ObjC++ -Recognize C++ keywords like \"compl\" and \"xor\" - -foptional-diags -C++ ObjC++ -Enable optional diagnostics - -fpch-deps -C ObjC C++ ObjC++ - -fpch-preprocess -C ObjC C++ ObjC++ -Look for and use PCH files even when preprocessing - -fpermissive -C++ ObjC++ -Downgrade conformance errors to warnings - -fpreprocessed -C ObjC C++ ObjC++ -Treat the input file as already preprocessed - -fpretty-templates -C++ ObjC++ --fno-pretty-templates Do not pretty-print template specializations as the template signature followed by the arguments - -freplace-objc-classes -ObjC ObjC++ -Used in Fix-and-Continue mode to indicate that object files may be swapped in at runtime - -frepo -C++ ObjC++ -Enable automatic template instantiation - -frtti -C++ ObjC++ Optimization -Generate run time type descriptor information - -fshort-double -C ObjC C++ ObjC++ Optimization -Use the same size for double as for float - -fshort-enums -C ObjC C++ ObjC++ Optimization -Use the narrowest integer type possible for enumeration types - -fshort-wchar -C ObjC C++ ObjC++ Optimization -Force the underlying type for \"wchar_t\" to be \"unsigned short\" - -fsigned-bitfields -C ObjC C++ ObjC++ -When \"signed\" or \"unsigned\" is not given make the bitfield signed - -fsigned-char -C ObjC C++ ObjC++ LTO -Make \"char\" signed by default - -fsquangle -C++ ObjC++ - -fstats -C++ ObjC++ -Display statistics accumulated during compilation - -fstrict-enums -C++ ObjC++ Optimization Var(flag_strict_enums) -Assume that values of enumeration type are always within the minimum range of that type - -fstrict-prototype -C++ ObjC++ - -ftabstop= -C ObjC C++ ObjC++ Joined RejectNegative UInteger --ftabstop= Distance between tab stops for column reporting - -ftemplate-depth- -C++ ObjC++ Joined RejectNegative UInteger Undocumented - -ftemplate-depth= -C++ ObjC++ Joined RejectNegative UInteger --ftemplate-depth= Specify maximum template instantiation depth - -fthis-is-variable -C++ ObjC++ - -fthreadsafe-statics -C++ ObjC++ Optimization --fno-threadsafe-statics Do not generate thread-safe code for initializing local statics - -funsigned-bitfields -C ObjC C++ ObjC++ -When \"signed\" or \"unsigned\" is not given make the bitfield unsigned - -funsigned-char -C ObjC C++ ObjC++ LTO -Make \"char\" unsigned by default - -fuse-cxa-atexit -C++ ObjC++ -Use __cxa_atexit to register destructors - -fuse-cxa-get-exception-ptr -C++ ObjC++ -Use __cxa_get_exception_ptr in exception handling - -fvisibility-inlines-hidden -C++ ObjC++ -Marks all inlined methods as having hidden visibility - -fvisibility-ms-compat -C++ ObjC++ Var(flag_visibility_ms_compat) -Changes visibility to match Microsoft Visual Studio by default - -fvtable-gc -C++ ObjC++ -Discard unused virtual functions - -fvtable-thunks -C++ ObjC++ -Implement vtables using thunks - -fweak -C++ ObjC++ -Emit common-like symbols as weak symbols - -fwide-exec-charset= -C ObjC C++ ObjC++ Joined RejectNegative --fwide-exec-charset= Convert all wide strings and character constants to character set - -fworking-directory -C ObjC C++ ObjC++ -Generate a #line directive pointing at the current working directory - -fxref -C++ ObjC++ -Emit cross referencing information - -fzero-link -ObjC ObjC++ -Generate lazy class lookup (via objc_getClass()) for use in Zero-Link mode - -gen-decls -ObjC ObjC++ -Dump declarations to a .decl file - -femit-struct-debug-baseonly -C ObjC C++ ObjC++ --femit-struct-debug-baseonly Aggressive reduced debug info for structs - -femit-struct-debug-reduced -C ObjC C++ ObjC++ --femit-struct-debug-reduced Conservative reduced debug info for structs - -femit-struct-debug-detailed= -C ObjC C++ ObjC++ Joined --femit-struct-debug-detailed= Detailed reduced debug info for structs - -idirafter -C ObjC C++ ObjC++ Joined Separate --idirafter Add to the end of the system include path - -imacros -C ObjC C++ ObjC++ Joined Separate --imacros Accept definition of macros in - -imultilib -C ObjC C++ ObjC++ Joined Separate --imultilib Set to be the multilib include subdirectory - -include -C ObjC C++ ObjC++ Joined Separate --include Include the contents of before other files - -iprefix -C ObjC C++ ObjC++ Joined Separate --iprefix Specify as a prefix for next two options - -isysroot -C ObjC C++ ObjC++ Joined Separate --isysroot Set to be the system root directory - -isystem -C ObjC C++ ObjC++ Joined Separate --isystem Add to the start of the system include path - -iquote -C ObjC C++ ObjC++ Joined Separate --iquote Add to the end of the quote include path - -iwithprefix -C ObjC C++ ObjC++ Joined Separate --iwithprefix Add to the end of the system include path - -iwithprefixbefore -C ObjC C++ ObjC++ Joined Separate --iwithprefixbefore Add to the end of the main include path - -lang-asm -C Undocumented - -lang-objc -C ObjC C++ ObjC++ Undocumented - -nostdinc -C ObjC C++ ObjC++ -Do not search standard system include directories (those specified with -isystem will still be used) - -nostdinc++ -C++ ObjC++ -Do not search standard system include directories for C++ - -o -C ObjC C++ ObjC++ Joined Separate -; Documented in common.opt - -pedantic -C ObjC C++ ObjC++ -; Documented in common.opt - -pedantic-errors -C ObjC C++ ObjC++ -; Documented in common.opt - -print-objc-runtime-info -ObjC ObjC++ -Generate C header of platform-specific features - -print-pch-checksum -C ObjC C++ ObjC++ -Print a checksum of the executable for PCH validity checking, and stop - -remap -C ObjC C++ ObjC++ -Remap file names when including files - -std=c++98 -C++ ObjC++ -Conform to the ISO 1998 C++ standard - -std=c++0x -C++ ObjC++ -Conform to the ISO 1998 C++ standard, with extensions that are likely to -become a part of the upcoming ISO C++ standard, dubbed C++0x. Note that the -extensions enabled by this mode are experimental and may be removed in -future releases of GCC. - -std=c1x -C ObjC -Conform to the ISO 201X C standard draft (experimental and incomplete support) - -std=c89 -C ObjC -Conform to the ISO 1990 C standard - -std=c90 -C ObjC -Conform to the ISO 1990 C standard - -std=c99 -C ObjC -Conform to the ISO 1999 C standard - -std=c9x -C ObjC -Deprecated in favor of -std=c99 - -std=gnu++98 -C++ ObjC++ -Conform to the ISO 1998 C++ standard with GNU extensions - -std=gnu++0x -C++ ObjC++ -Conform to the ISO 1998 C++ standard, with GNU extensions and -extensions that are likely to become a part of the upcoming ISO C++ -standard, dubbed C++0x. Note that the extensions enabled by this mode -are experimental and may be removed in future releases of GCC. - -std=gnu1x -C ObjC -Conform to the ISO 201X C standard draft with GNU extensions (experimental and incomplete support) - -std=gnu89 -C ObjC -Conform to the ISO 1990 C standard with GNU extensions - -std=gnu90 -C ObjC -Conform to the ISO 1990 C standard with GNU extensions - -std=gnu99 -C ObjC -Conform to the ISO 1999 C standard with GNU extensions - -std=gnu9x -C ObjC -Deprecated in favor of -std=gnu99 - -std=iso9899:1990 -C ObjC -Conform to the ISO 1990 C standard - -std=iso9899:199409 -C ObjC -Conform to the ISO 1990 C standard as amended in 1994 - -std=iso9899:1999 -C ObjC -Conform to the ISO 1999 C standard - -std=iso9899:199x -C ObjC -Deprecated in favor of -std=iso9899:1999 - -traditional-cpp -C ObjC C++ ObjC++ -Enable traditional preprocessing - -trigraphs -C ObjC C++ ObjC++ --trigraphs Support ISO C trigraphs - -undef -C ObjC C++ ObjC++ -Do not predefine system-specific and GCC-specific macros - -v -Common C ObjC C++ ObjC++ -Enable verbose output - -w -C ObjC C++ ObjC++ -; Documented in common.opt - -; This comment is to ensure we retain the blank line above. diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c index 4e2a9cb..786a7a3 100644 --- a/gcc/config/arm/arm-c.c +++ b/gcc/config/arm/arm-c.c @@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "tm_p.h" #include "tree.h" #include "output.h" -#include "c-common.h" +#include "c-family/c-common.h" /* Output C specific EABI object attributes. These can not be done in diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index b34086f..31c1354 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -45,7 +45,7 @@ #include "cgraph.h" #include "ggc.h" #include "except.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" /* ??? */ #include "integrate.h" #include "tm_p.h" #include "target.h" diff --git a/gcc/config/avr/avr-c.c b/gcc/config/avr/avr-c.c index c2c1dd5..22724c1 100644 --- a/gcc/config/avr/avr-c.c +++ b/gcc/config/avr/avr-c.c @@ -26,7 +26,7 @@ #include "tm_p.h" #include "cpplib.h" #include "tree.h" -#include "c-common.h" +#include "c-family/c-common.h" /* Not included in avr.c since this requires C front end. */ diff --git a/gcc/config/darwin-c.c b/gcc/config/darwin-c.c index 0e2f806..6221ab3b 100644 --- a/gcc/config/darwin-c.c +++ b/gcc/config/darwin-c.c @@ -25,9 +25,9 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "cpplib.h" #include "tree.h" -#include "c-pragma.h" #include "incpath.h" -#include "c-common.h" +#include "c-family/c-common.h" +#include "c-family/c-pragma.h" #include "toplev.h" #include "flags.h" #include "tm_p.h" diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index 4136eb0..5773fb1 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -39,7 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "function.h" #include "optabs.h" #include "toplev.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" /* ??? */ #include "tm_p.h" #include "ggc.h" #include "target.h" diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c index b33fc86..1b89a0b 100644 --- a/gcc/config/i386/i386-c.c +++ b/gcc/config/i386/i386-c.c @@ -25,12 +25,12 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "tm_p.h" #include "flags.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "ggc.h" #include "target.h" #include "target-def.h" #include "cpplib.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" static bool ix86_pragma_target_parse (tree, tree); static void ix86_target_macros_internal diff --git a/gcc/config/i386/msformat-c.c b/gcc/config/i386/msformat-c.c index af5c0f9..635c2ca 100644 --- a/gcc/config/i386/msformat-c.c +++ b/gcc/config/i386/msformat-c.c @@ -25,12 +25,12 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "tree.h" #include "flags.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "toplev.h" #include "intl.h" #include "diagnostic.h" #include "langhooks.h" -#include "c-format.h" +#include "c-family/c-format.h" #include "alloc-pool.h" /* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime. */ diff --git a/gcc/config/ia64/ia64-c.c b/gcc/config/ia64/ia64-c.c index c89a83c..7a0bdd7 100644 --- a/gcc/config/ia64/ia64-c.c +++ b/gcc/config/ia64/ia64-c.c @@ -24,8 +24,8 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "tree.h" #include "cpplib.h" -#include "c-common.h" -#include "c-pragma.h" +#include "c-family/c-common.h" +#include "c-family/c-pragma.h" #include "toplev.h" #include "tm_p.h" diff --git a/gcc/config/ia64/t-ia64 b/gcc/config/ia64/t-ia64 index db7a829..212bef7 100644 --- a/gcc/config/ia64/t-ia64 +++ b/gcc/config/ia64/t-ia64 @@ -46,7 +46,7 @@ LIB2ADDEH = $(srcdir)/config/ia64/unwind-ia64.c $(srcdir)/unwind-sjlj.c \ $(srcdir)/unwind-c.c ia64-c.o: $(srcdir)/config/ia64/ia64-c.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(TREE_H) $(CPPLIB_H) $(C_COMMON_H) c-pragma.h toplev.h + coretypes.h $(TM_H) $(TREE_H) $(CPPLIB_H) $(C_COMMON_H) $(C_PRAGMA_H) toplev.h $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/ia64/ia64-c.c diff --git a/gcc/config/m32c/m32c-pragma.c b/gcc/config/m32c/m32c-pragma.c index 4e30937..e2fef7e 100644 --- a/gcc/config/m32c/m32c-pragma.c +++ b/gcc/config/m32c/m32c-pragma.c @@ -26,7 +26,7 @@ #include "tree.h" #include "rtl.h" #include "toplev.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" #include "cpplib.h" #include "hard-reg-set.h" #include "output.h" diff --git a/gcc/config/mep/mep-pragma.c b/gcc/config/mep/mep-pragma.c index 3f9fc5a..1d79a3b 100644 --- a/gcc/config/mep/mep-pragma.c +++ b/gcc/config/mep/mep-pragma.c @@ -26,7 +26,7 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "rtl.h" #include "toplev.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" #include "cpplib.h" #include "hard-reg-set.h" #include "output.h" diff --git a/gcc/config/mep/t-mep b/gcc/config/mep/t-mep index 5fd7f94..9608d6c 100644 --- a/gcc/config/mep/t-mep +++ b/gcc/config/mep/t-mep @@ -33,7 +33,7 @@ CRTSTUFF_CFLAGS = -O0 $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \ TCFLAGS = -mlibrary mep-pragma.o: $(srcdir)/config/mep/mep-pragma.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(TREE_H) $(RTL_H) toplev.h c-pragma.h \ + coretypes.h $(TM_H) $(TREE_H) $(RTL_H) toplev.h $(C_PRAGMA_H) \ $(CPPLIB_H) hard-reg-set.h output.h $(srcdir)/config/mep/mep-protos.h \ function.h insn-config.h reload.h $(TARGET_H) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c index 7a197c1..20f594a 100644 --- a/gcc/config/rs6000/rs6000-c.c +++ b/gcc/config/rs6000/rs6000-c.c @@ -27,8 +27,8 @@ #include "tm.h" #include "cpplib.h" #include "tree.h" -#include "c-common.h" -#include "c-pragma.h" +#include "c-family/c-common.h" +#include "c-family/c-pragma.h" #include "toplev.h" #include "tm_p.h" #include "target.h" diff --git a/gcc/config/rs6000/t-rs6000 b/gcc/config/rs6000/t-rs6000 index 773d710..8066c89 100644 --- a/gcc/config/rs6000/t-rs6000 +++ b/gcc/config/rs6000/t-rs6000 @@ -32,7 +32,7 @@ rs6000.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ rs6000-c.o: $(srcdir)/config/rs6000/rs6000-c.c \ $(srcdir)/config/rs6000/rs6000-protos.h \ $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(CPPLIB_H) \ - $(TM_P_H) c-pragma.h errors.h coretypes.h $(TM_H) + $(TM_P_H) $(C_PRAGMA_H) errors.h coretypes.h $(TM_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/rs6000/rs6000-c.c diff --git a/gcc/config/sol2-c.c b/gcc/config/sol2-c.c index 0b322d1..f53fc32 100644 --- a/gcc/config/sol2-c.c +++ b/gcc/config/sol2-c.c @@ -26,12 +26,12 @@ along with GCC; see the file COPYING3. If not see #include "tm_p.h" #include "toplev.h" -#include "c-format.h" +#include "c-family/c-format.h" #include "intl.h" #include "cpplib.h" -#include "c-pragma.h" -#include "c-common.h" +#include "c-family/c-pragma.h" +#include "c-family/c-common.h" /* cmn_err only accepts "l" and "ll". */ static const format_length_info cmn_err_length_specs[] = diff --git a/gcc/config/spu/spu-c.c b/gcc/config/spu/spu-c.c index a4f2274..ce5f92d 100644 --- a/gcc/config/spu/spu-c.c +++ b/gcc/config/spu/spu-c.c @@ -20,8 +20,8 @@ #include "tm.h" #include "cpplib.h" #include "tree.h" -#include "c-common.h" -#include "c-pragma.h" +#include "c-family/c-common.h" +#include "c-family/c-pragma.h" #include "tm_p.h" #include "langhooks.h" diff --git a/gcc/config/t-darwin b/gcc/config/t-darwin index 4e0a00e..b538ccf 100644 --- a/gcc/config/t-darwin +++ b/gcc/config/t-darwin @@ -26,7 +26,7 @@ darwin.o: $(srcdir)/config/darwin.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(srcdir)/config/darwin.c darwin-c.o: $(srcdir)/config/darwin-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(CPPLIB_H) $(TREE_H) c-pragma.h toplev.h $(TM_P_H) \ + $(TM_H) $(CPPLIB_H) $(TREE_H) $(C_PRAGMA_H) toplev.h $(TM_P_H) \ incpath.h flags.h $(C_COMMON_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/darwin-c.c $(PREPROCESSOR_DEFINES) diff --git a/gcc/config/t-sol2 b/gcc/config/t-sol2 index 526ae40..6112f2d 100644 --- a/gcc/config/t-sol2 +++ b/gcc/config/t-sol2 @@ -18,8 +18,8 @@ # Solaris-specific format checking and pragmas sol2-c.o: $(srcdir)/config/sol2-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - tree.h c-format.h intl.h $(CPPLIB_H) c-pragma.h $(TM_H) $(TM_P_H) \ - toplev.h $(C_COMMON_H) + tree.h c-family/c-format.h $(C_PRAGMA_H) $(C_COMMON_H) $(CPPLIB_H) \ + intl.h $(TM_H) $(TM_P_H) toplev.h $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/sol2-c.c diff --git a/gcc/config/v850/t-v850 b/gcc/config/v850/t-v850 index 5c893d8..139ec5b 100644 --- a/gcc/config/v850/t-v850 +++ b/gcc/config/v850/t-v850 @@ -108,7 +108,7 @@ MULTILIB_MATCHES = mv850e=mv850e1 TCFLAGS = -mno-app-regs -msmall-sld -Wa,-mwarn-signed-overflow -Wa,-mwarn-unsigned-overflow v850-c.o: $(srcdir)/config/v850/v850-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(CPPLIB_H) $(TREE_H) c-pragma.h toplev.h $(GGC_H) $(TM_P_H) + $(TM_H) $(CPPLIB_H) $(TREE_H) $(C_PRAGMA_H) toplev.h $(GGC_H) $(TM_P_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/v850/v850-c.c diff --git a/gcc/config/v850/t-v850e b/gcc/config/v850/t-v850e index 9fcd897..f0e9c6f 100644 --- a/gcc/config/v850/t-v850e +++ b/gcc/config/v850/t-v850e @@ -106,7 +106,7 @@ INSTALL_LIBGCC = install-multilib TCFLAGS = -mno-app-regs -msmall-sld -Wa,-mwarn-signed-overflow -Wa,-mwarn-unsigned-overflow v850-c.o: $(srcdir)/config/v850/v850-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(CPPLIB_H) $(TREE_H) c-pragma.h toplev.h $(GGC_H) $(TM_P_H) + $(TM_H) $(CPPLIB_H) $(TREE_H) $(C_PRAGMA_H) toplev.h $(GGC_H) $(TM_P_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/v850/v850-c.c diff --git a/gcc/config/v850/v850-c.c b/gcc/config/v850/v850-c.c index 0d53a72..c3c3815 100644 --- a/gcc/config/v850/v850-c.c +++ b/gcc/config/v850/v850-c.c @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "cpplib.h" #include "tree.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" #include "toplev.h" #include "ggc.h" #include "tm_p.h" diff --git a/gcc/configure b/gcc/configure index ea79930..97642e8 100755 --- a/gcc/configure +++ b/gcc/configure @@ -26906,7 +26906,7 @@ case ${CONFIG_HEADERS} in echo > cstamp-h ;; esac # Make sure all the subdirs exist. -for d in $subdirs doc build +for d in $subdirs doc build c-family do test -d $d || mkdir $d done diff --git a/gcc/configure.ac b/gcc/configure.ac index 27cb45c..ebf2910 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4638,7 +4638,7 @@ case ${CONFIG_HEADERS} in echo > cstamp-h ;; esac # Make sure all the subdirs exist. -for d in $subdirs doc build +for d in $subdirs doc build c-family do test -d $d || mkdir $d done diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9c4ad0a..d75030e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,23 @@ +2010-06-05 Steven Bosscher + + * typeck.c: Update include path for moved files. + * decl.c: Likewise. + * rtti.c: Likewise. + * cp-gimplify.c: Likewise. + * cp-lang.c: Likewise. + * pt.c: Likewise. + * semantics.c: Likewise. + * cxx-pretty-print.h: Likewise. + * decl2.c: Likewise. + * parser.c: Likewise. + * cp-objcp-common.c: Likewise. + * cp-tree.h: Likewise. + * name-lookup.c: Likewise. + * lex.c: Likewise. + * name-lookup.h: Likewise. + * config-lang.in: Update paths in gtfiles for files in c-family/. + * Make-lang.in: Likewise. + 2010-06-04 Magnus Fromreide * cvt.c (cp_convert_to_pointer): Use null_ptr_cst_p. diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index d726ead..bfccd72 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -71,10 +71,8 @@ g++-cross$(exeext): g++$(exeext) # The compiler itself. # Shared with C front end: -CXX_C_OBJS = attribs.o c-common.o c-format.o c-pragma.o c-semantics.o c-lex.o \ - c-dump.o $(CXX_TARGET_OBJS) c-pretty-print.o c-opts.o c-pch.o \ - incpath.o c-ppoutput.o c-cppbuiltin.o prefix.o \ - c-gimplify.o c-omp.o c-ada-spec.o +CXX_C_OBJS = attribs.o incpath.o prefix.o \ + $(C_COMMON_OBJS) $(CXX_TARGET_OBJS) # Language-specific object files for C++ and Objective C++. CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ @@ -85,7 +83,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ cp/cp-gimplify.o tree-mudflap.o $(CXX_C_OBJS) # Language-specific object files for C++. -CXX_OBJS = cp/cp-lang.o stub-objc.o $(CXX_AND_OBJCXX_OBJS) +CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS) c++_OBJS = $(CXX_OBJS) dummy-checksum.o cc1plus-checksum.o cp/g++spec.o @@ -260,7 +258,7 @@ cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \ cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \ output.h $(EXCEPT_H) toplev.h $(C_COMMON_H) gt-cp-decl2.h $(CGRAPH_H) \ $(C_PRAGMA_H) $(TREE_DUMP_H) intl.h $(TARGET_H) $(GIMPLE_H) $(POINTER_SET_H) \ - $(SPLAY_TREE_H) c-ada-spec.h + $(SPLAY_TREE_H) c-family/c-ada-spec.h cp/cp-objcp-common.o : cp/cp-objcp-common.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TM_H) $(TREE_H) $(CXX_TREE_H) $(C_COMMON_H) toplev.h \ langhooks.h $(LANGHOOKS_DEF_H) $(DIAGNOSTIC_H) debug.h \ diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in index c6d7b38..a15c7e2 100644 --- a/gcc/cp/config-lang.in +++ b/gcc/cp/config-lang.in @@ -30,4 +30,4 @@ compilers="cc1plus\$(exeext)" target_libs="target-libstdc++-v3" -gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-lex.c \$(srcdir)/c-pragma.h \$(srcdir)/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c" +gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c" diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 2e3f11d..f45d714 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -26,7 +26,7 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "tree.h" #include "cp-tree.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "toplev.h" #include "tree-iterator.h" #include "gimple.h" diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index a08f0dd..541e9ad 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "tree.h" #include "cp-tree.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "toplev.h" #include "langhooks.h" #include "langhooks-def.h" diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 35654c5..63ce56b 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "tree.h" #include "cp-tree.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "toplev.h" #include "langhooks.h" #include "langhooks-def.h" diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6b292b6..9861946 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -42,7 +42,7 @@ c-common.h, not after. #endif #include "toplev.h" #include "diagnostic.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "name-lookup.h" diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h index a88d4c5..5a51f44 100644 --- a/gcc/cp/cxx-pretty-print.h +++ b/gcc/cp/cxx-pretty-print.h @@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_CXX_PRETTY_PRINT_H #define GCC_CXX_PRETTY_PRINT_H -#include "c-pretty-print.h" +#include "c-family/c-pretty-print.h" #undef pp_c_base #define pp_c_base(PP) (&(PP)->c_base) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index ef00a11..d534ea3 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -45,8 +45,8 @@ along with GCC; see the file COPYING3. If not see #include "hashtab.h" #include "tm_p.h" #include "target.h" -#include "c-common.h" -#include "c-pragma.h" +#include "c-family/c-common.h" +#include "c-family/c-pragma.h" #include "diagnostic.h" #include "intl.h" #include "debug.h" diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 33e0e26..070bc3e 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -42,18 +42,18 @@ along with GCC; see the file COPYING3. If not see #include "timevar.h" #include "cpplib.h" #include "target.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "tree-mudflap.h" #include "cgraph.h" #include "tree-inline.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" #include "tree-dump.h" #include "intl.h" #include "gimple.h" #include "pointer-set.h" #include "splay-tree.h" #include "langhooks.h" -#include "c-ada-spec.h" +#include "c-family/c-ada-spec.h" extern cpp_reader *parse_in; diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 041e391..1bae86f 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -32,7 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "cp-tree.h" #include "cpplib.h" #include "flags.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" #include "toplev.h" #include "output.h" #include "tm_p.h" diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 3236b64..0c759c6 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -31,7 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "toplev.h" #include "diagnostic-core.h" #include "debug.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" /* The bindings for a particular name in a particular scope. */ diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 0851481..e5190eb 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_CP_NAME_LOOKUP_H #define GCC_CP_NAME_LOOKUP_H -#include "c-common.h" +#include "c-family/c-common.h" /* The type of dictionary used to map names to types declared at a given scope. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a33330c..eb347e2 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "cp-tree.h" #include "intl.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" #include "decl.h" #include "flags.h" #include "diagnostic-core.h" @@ -35,7 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "output.h" #include "target.h" #include "cgraph.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "plugin.h" diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d7c0382..b95fdf7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -35,7 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "pointer-set.h" #include "flags.h" #include "cp-tree.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "cp-objcp-common.h" #include "tree-inline.h" #include "decl.h" diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 62aa921..12d1784 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -33,7 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "toplev.h" #include "convert.h" #include "target.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" /* C++ returns type information to the user in struct type_info objects. We also use type information to implement dynamic_cast and diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 2d02690..3e75240 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -30,7 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "tree.h" #include "cp-tree.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "tree-inline.h" #include "tree-mudflap.h" #include "except.h" diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 53e84cf..a43c432 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -39,7 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "target.h" #include "convert.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "params.h" static tree pfn_from_ptrmemfunc (tree); diff --git a/gcc/gengtype.c b/gcc/gengtype.c index 65bb8d1..90e6434 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -1657,13 +1657,21 @@ get_file_langdir (const char *f) int lang_index; const char * srcdir_relative_path = get_file_srcdir_relative_path (f); + const char * r; if (!srcdir_relative_path) return NULL; lang_index = get_prefix_langdir_index (srcdir_relative_path); + if (lang_index < 0 + && strncmp (srcdir_relative_path, "c-family", 8) == 0) + r = "c-family"; + else if (lang_index >= 0) + r = lang_dir_names [lang_index]; + else + r = NULL; - return (lang_index >= 0) ? lang_dir_names [lang_index] : NULL; + return r; } /* The gt- output file name for F. */ @@ -1743,8 +1751,10 @@ get_output_file_with_visibility (const char *input_file) (and gengtype doesn't know how to direct spewage into multiple gtype-.h headers at this time). Instead, we pair up these headers with source files (and their special purpose gt-*.h headers). */ - else if (strcmp (basename, "c-common.h") == 0) - output_name = "gt-c-common.h", for_name = "c-common.c"; + else if (strncmp (basename, "c-family", 8) == 0 + && IS_DIR_SEPARATOR (basename[8]) + && strcmp (basename + 9, "c-common.h") == 0) + output_name = "gt-c-family-c-common.h", for_name = "c-family/c-common.c"; else if (strcmp (basename, "c-lang.h") == 0) output_name = "gt-c-decl.h", for_name = "c-decl.c"; else if (strcmp (basename, "c-tree.h") == 0) diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 1a4241c..9934f24 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,9 @@ +2010-06-05 Steven Bosscher + + * objc-act.c: Update include path for moved files. + * objc-lang.c: Likewise. + * config-lang.in: Update paths in gtfiles for files in c-family/. + 2010-06-01 Nathan Froyd * objc-act.c (build_next_objc_exception_stuff): Give setjmp a diff --git a/gcc/objc/config-lang.in b/gcc/objc/config-lang.in index 760b87a..1a02b7f 100644 --- a/gcc/objc/config-lang.in +++ b/gcc/objc/config-lang.in @@ -33,4 +33,4 @@ target_libs=target-libobjc # Most of the object files for cc1obj actually come from C. lang_requires="c" -gtfiles="\$(srcdir)/objc/objc-act.h \$(srcdir)/c-parser.c \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-objc-common.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-pragma.h \$(srcdir)/c-pragma.c \$(srcdir)/objc/objc-act.c" +gtfiles="\$(srcdir)/objc/objc-act.h \$(srcdir)/c-parser.c \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/objc/objc-act.c" diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 37289a2..f10592f 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -53,8 +53,8 @@ along with GCC; see the file COPYING3. If not see #include "c-lang.h" #endif -#include "c-common.h" -#include "c-pragma.h" +#include "c-family/c-common.h" +#include "c-family/c-pragma.h" #include "flags.h" #include "langhooks.h" #include "objc-act.h" diff --git a/gcc/objc/objc-lang.c b/gcc/objc/objc-lang.c index 04cea97..fa74964 100644 --- a/gcc/objc/objc-lang.c +++ b/gcc/objc/objc-lang.c @@ -26,7 +26,7 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "tree.h" #include "c-tree.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "ggc.h" #include "objc-act.h" #include "langhooks.h" diff --git a/gcc/objcp/ChangeLog b/gcc/objcp/ChangeLog index 8623bb5..e6fbad5 100644 --- a/gcc/objcp/ChangeLog +++ b/gcc/objcp/ChangeLog @@ -1,3 +1,8 @@ +2010-06-05 Steven Bosscher + + * objcp-lang.c: Update include path for moved files. + * config-lang.in: Update paths in gtfiles for files in c-family/. + 2010-05-25 Steven Bosscher * objcp-decl.c: Do not include tm.h, rtl.h, expr.h, c-common.h, diff --git a/gcc/objcp/config-lang.in b/gcc/objcp/config-lang.in index 3d9232e..febcb63 100644 --- a/gcc/objcp/config-lang.in +++ b/gcc/objcp/config-lang.in @@ -37,4 +37,4 @@ build_by_default="no" lang_requires="objc c++" subdir_requires="objc cp" -gtfiles="\$(srcdir)/objcp/objcp-decl.c \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-act.h \$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-lex.c \$(srcdir)/c-pragma.h \$(srcdir)/c-pragma.c \$(srcdir)/cp/cp-objcp-common.c" +gtfiles="\$(srcdir)/objcp/objcp-decl.c \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-act.h \$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/cp-objcp-common.c" diff --git a/gcc/objcp/objcp-lang.c b/gcc/objcp/objcp-lang.c index 4708229..91e5c7e 100644 --- a/gcc/objcp/objcp-lang.c +++ b/gcc/objcp/objcp-lang.c @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "tree.h" #include "cp-tree.h" -#include "c-common.h" +#include "c-family/c-common.h" #include "objc-act.h" #include "langhooks.h" #include "langhooks-def.h" diff --git a/gcc/po/exgettext b/gcc/po/exgettext index a85f705..e065830 100644 --- a/gcc/po/exgettext +++ b/gcc/po/exgettext @@ -84,7 +84,7 @@ echo "scanning for keywords, %e and %n strings..." >&2 ( cd $srcdir lang_subdirs=`echo */config-lang.in */*/config-lang.in | sed -e 's|config-lang\.in||g'` - { for dir in "" config/ config/*/ $lang_subdirs + { for dir in "" c-family/ config/ config/*/ $lang_subdirs do for glob in '*.c' '*.h' '*.def' do eval echo $dir$glob done diff --git a/gcc/stub-objc.c b/gcc/stub-objc.c deleted file mode 100644 index b7748f7..0000000 --- a/gcc/stub-objc.c +++ /dev/null @@ -1,327 +0,0 @@ -/* Stub functions for Objective-C and Objective-C++ routines - that are called from within the C and C++ front-ends, - respectively. - Copyright (C) 1991, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2007, 2009 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 "tree.h" -#include "c-common.h" - -tree -objc_is_class_name (tree ARG_UNUSED (arg)) -{ - return 0; -} - -tree -objc_is_id (tree ARG_UNUSED (arg)) -{ - return 0; -} - -tree -objc_is_object_ptr (tree ARG_UNUSED (arg)) -{ - return 0; -} - -tree -objc_lookup_ivar (tree other, tree ARG_UNUSED (arg)) -{ - /* Just use whatever C/C++ found. */ - return other; -} - -void -objc_check_decl (tree ARG_UNUSED (decl)) -{ -} - -int -objc_is_reserved_word (tree ARG_UNUSED (ident)) -{ - return 0; -} - -bool -objc_compare_types (tree ARG_UNUSED (ltyp), tree ARG_UNUSED (rtyp), - int ARG_UNUSED (argno), tree ARG_UNUSED (callee)) -{ - return false; -} - -void -objc_volatilize_decl (tree ARG_UNUSED (decl)) -{ -} - -bool -objc_type_quals_match (tree ARG_UNUSED (ltyp), tree ARG_UNUSED (rtyp)) -{ - return false; -} - -tree -objc_rewrite_function_call (tree function, tree ARG_UNUSED (first_param)) -{ - return function; -} - -tree -objc_message_selector (void) -{ - return 0; -} - -void -objc_declare_alias (tree ARG_UNUSED (alias), tree ARG_UNUSED (orig)) -{ -} - -void -objc_declare_class (tree ARG_UNUSED (list)) -{ -} - -void -objc_declare_protocols (tree ARG_UNUSED (list)) -{ -} - -void -objc_start_protocol (tree ARG_UNUSED (proto), - tree ARG_UNUSED (protorefs)) -{ -} - -void -objc_start_class_interface (tree ARG_UNUSED (name), - tree ARG_UNUSED (super), - tree ARG_UNUSED (protos)) -{ -} - -void -objc_start_category_interface (tree ARG_UNUSED (name), - tree ARG_UNUSED (categ), - tree ARG_UNUSED (protos)) -{ -} - -void -objc_continue_interface (void) -{ -} - -void -objc_finish_interface (void) -{ -} - -void -objc_add_instance_variable (tree ARG_UNUSED (decl)) -{ -} - -void -objc_set_visibility (int ARG_UNUSED (vis)) -{ -} - -void -objc_set_method_type (enum tree_code ARG_UNUSED (code)) -{ -} - -void -objc_start_class_implementation (tree ARG_UNUSED (name), - tree ARG_UNUSED (super)) -{ -} - -void -objc_start_category_implementation (tree ARG_UNUSED (name), - tree ARG_UNUSED (categ)) -{ -} - -void -objc_continue_implementation (void) -{ -} - -void -objc_clear_super_receiver (void) -{ -} - -void -objc_finish_implementation (void) -{ -} - -void -objc_add_method_declaration (tree ARG_UNUSED (signature)) -{ -} - -void -objc_start_method_definition (tree ARG_UNUSED (signature)) -{ -} - -void -objc_finish_method_definition (tree ARG_UNUSED (fndecl)) -{ -} - -tree -objc_build_keyword_decl (tree ARG_UNUSED (selector), - tree ARG_UNUSED (type), - tree ARG_UNUSED (identifier)) -{ - return 0; -} - -tree -objc_build_method_signature (tree ARG_UNUSED (rettype), - tree ARG_UNUSED (selectors), - tree ARG_UNUSED (optparms), - bool ARG_UNUSED (ellipsis)) -{ - return 0; -} - -tree -objc_build_encode_expr (tree ARG_UNUSED (expr)) -{ - return 0; -} - -tree -objc_build_protocol_expr (tree ARG_UNUSED (expr)) -{ - return 0; -} - -tree -objc_build_selector_expr (location_t ARG_UNUSED (loc), tree ARG_UNUSED (expr)) -{ - return 0; -} - -tree -objc_build_message_expr (tree ARG_UNUSED (expr)) -{ - return 0; -} - -tree -objc_build_string_object (tree ARG_UNUSED (str)) -{ - return 0; -} - -tree -objc_get_class_reference (tree ARG_UNUSED (name)) -{ - return 0; -} - -tree -objc_get_protocol_qualified_type (tree ARG_UNUSED (name), - tree ARG_UNUSED (protos)) -{ - return 0; -} - -int -objc_static_init_needed_p (void) -{ - return 0; -} - -tree -objc_generate_static_init_call (tree ARG_UNUSED (ctors)) -{ - return 0; -} - -int -objc_is_public (tree ARG_UNUSED (expr), tree ARG_UNUSED (identifier)) -{ - return 1; -} - -tree -objc_get_class_ivars (tree ARG_UNUSED (name)) -{ - return 0; -} - -tree -objc_build_throw_stmt (location_t ARG_UNUSED (loc), tree ARG_UNUSED (expr)) -{ - return 0; -} - -tree -objc_build_synchronized (location_t ARG_UNUSED (start_locus), - tree ARG_UNUSED (mutex), tree ARG_UNUSED (body)) -{ - return 0; -} - -void -objc_begin_try_stmt (location_t ARG_UNUSED (try_locus), tree ARG_UNUSED (body)) -{ -} - -void -objc_begin_catch_clause (tree ARG_UNUSED (decl)) -{ -} - -void -objc_finish_catch_clause (void) -{ -} - -void -objc_build_finally_clause (location_t ARG_UNUSED (finally_locus), - tree ARG_UNUSED (body)) -{ -} - -tree -objc_finish_try_stmt (void) -{ - return 0; -} - -tree -objc_generate_write_barrier (tree ARG_UNUSED (lhs), - enum tree_code ARG_UNUSED (modifycode), - tree ARG_UNUSED (rhs)) -{ - return 0; -} -- cgit v1.1