summaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /gcc/c-family
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'gcc/c-family')
-rw-r--r--gcc/c-family/ChangeLog1066
-rw-r--r--gcc/c-family/c-ada-spec.c3330
-rw-r--r--gcc/c-family/c-ada-spec.h41
-rw-r--r--gcc/c-family/c-common.c9725
-rw-r--r--gcc/c-family/c-common.def54
-rw-r--r--gcc/c-family/c-common.h1011
-rw-r--r--gcc/c-family/c-cppbuiltin.c1155
-rw-r--r--gcc/c-family/c-dump.c61
-rw-r--r--gcc/c-family/c-format.c3061
-rw-r--r--gcc/c-family/c-format.h329
-rw-r--r--gcc/c-family/c-gimplify.c188
-rw-r--r--gcc/c-family/c-lex.c1089
-rw-r--r--gcc/c-family/c-objc.h116
-rw-r--r--gcc/c-family/c-omp.c530
-rw-r--r--gcc/c-family/c-opts.c1498
-rw-r--r--gcc/c-family/c-pch.c512
-rw-r--r--gcc/c-family/c-ppoutput.c630
-rw-r--r--gcc/c-family/c-pragma.c1324
-rw-r--r--gcc/c-family/c-pragma.h116
-rw-r--r--gcc/c-family/c-pretty-print.c2317
-rw-r--r--gcc/c-family/c-pretty-print.h214
-rw-r--r--gcc/c-family/c-semantics.c173
-rw-r--r--gcc/c-family/c.opt1243
-rw-r--r--gcc/c-family/stub-objc.c462
24 files changed, 30245 insertions, 0 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
new file mode 100644
index 000000000..14122ad06
--- /dev/null
+++ b/gcc/c-family/ChangeLog
@@ -0,0 +1,1066 @@
+2013-04-12 Release Manager
+
+ * GCC 4.6.4 released.
+
+2012-03-01 Release Manager
+
+ * GCC 4.6.3 released.
+
+2011-11-04 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR c++/50608
+ * c-common.c (c_fully_fold_internal) <ADDR_EXPR>: Call fold_offsetof_1.
+ (fold_offsetof_1): Make global. Remove STOP_REF argument and adjust.
+ <INDIRECT_REF>: Return the argument.
+ <ARRAY_REF>: Remove special code for negative offset.
+ Call fold_build_pointer_plus instead of size_binop.
+ (fold_offsetof): Remove STOP_REF argument and adjust.
+ * c-common.h (fold_offsetof_1): Declare.
+ (fold_offsetof): Remove STOP_REF argument.
+
+2011-10-26 Release Manager
+
+ * GCC 4.6.2 released.
+
+2011-09-06 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR middle-end/50266
+ * c-common.c (c_fully_fold_internal) <ADDR_EXPR>: Fold offsetof-like
+ computations.
+
+2011-06-27 Release Manager
+
+ * GCC 4.6.1 released.
+
+2011-05-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/49165
+ * c-common.c (c_common_truthvalue_conversion) <case COND_EXPR>: For
+ C++ don't call c_common_truthvalue_conversion on void type arms.
+
+2011-04-19 Richard Guenther <rguenther@suse.de>
+
+ PR preprocessor/48248
+ * c-ppoutput.c (maybe_print_line): Avoid changing -P behavior.
+
+2011-04-07 Jason Merrill <jason@redhat.com>
+
+ PR c++/48450
+ * c-common.c (c_common_truthvalue_conversion): Don't ignore
+ conversion from C++0x scoped enum.
+
+2011-03-29 Jakub Jelinek <jakub@redhat.com>
+
+ PR preprocessor/48248
+ * c-ppoutput.c (print): Add src_file field.
+ (init_pp_output): Initialize it.
+ (maybe_print_line): Don't optimize by adding up to 8 newlines
+ if map->to_file and print.src_file are different file.
+ (print_line): Update print.src_file.
+
+2011-03-29 Jason Merrill <jason@redhat.com>
+
+ * c.opt (fconstexpr-depth): New option.
+
+ * c.opt: Add -std=c++03.
+
+2011-03-25 Release Manager
+
+ * GCC 4.6.0 released.
+
+2011-03-11 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (attribute_takes_identifier_p): Add missing const.
+
+ PR c++/46803
+ * c-common.c (attribute_takes_identifier_p): Assume that an
+ unknown attribute takes an identifier.
+
+2011-03-07 Nathan Froyd <froydnj@codesourcery.com>
+
+ PR c/47786
+ * c-common.c (c_type_hash): Call list_length instead of iterating
+ through DECL_CHAIN. Rename 'i' to 'n_elements'.
+
+2011-02-19 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/47809
+ * c-common.c (c_fully_fold_internal): Handle VIEW_CONVERT_EXPR.
+
+2011-02-17 Iain Sandoe <iains@gcc.gnu.org>
+
+ * c.opt (fobjc-abi-version=) New.
+ (fobjc-nilcheck): New.
+
+2011-02-03 Nathan Froyd <froydnj@codesourcery.com>
+
+ PR c++/46890
+ * c-common.h (keyword_is_decl_specifier): Declare.
+ * c-common.c (keyword_is_decl_specifier): Define.
+ (keyword_is_function_specifier): New function.
+
+2011-01-26 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/47473
+ * c-lex.c (interpret_float): If CPP_N_IMAGINARY, ensure
+ EXCESS_PRECISION_EXPR is created with COMPLEX_TYPE instead of
+ REAL_TYPE.
+
+2011-01-26 Arnaud Charlet <charlet@adacore.com>
+
+ * c-ada-spec.c (dump_generic_ada_node): Avoid dereferencing null type.
+
+2011-01-26 Jakub Jelinek <jakub@redhat.com>
+
+ PR pch/47430
+ * c-opts.c (c_common_post_options): Call c_common_no_more_pch
+ after init_c_lex if pch_file is set.
+
+2011-01-26 Dave Korn <dave.korn.cygwin@gmail.com>
+
+ PR c++/43601
+ * c.opt (-fkeep-inline-dllexport): New switch.
+
+2011-01-12 Richard Guenther <rguenther@suse.de>
+
+ PR middle-end/32511
+ * c-common.c (handle_weak_attribute): Warn instead of error
+ on declaring an inline function weak.
+
+2011-01-05 Tom Tromey <tromey@redhat.com>
+
+ * c-common.h (lvalue_error): Update.
+ * c-common.c (lvalue_error): Add 'loc' argument. Call error_at,
+ not error.
+
+2010-12-29 Nicola Pero <nicola@nicola.brainstorm.co.uk>
+
+ PR objc/47075
+ * c-objc.h (objc_finish_message_expr): Added argument to
+ prototype.
+
+2010-12-22 Nathan Froyd <froydnj@codesourcery.com>
+
+ * c-common.c (handle_nonnull_attribute, handle_sentinel_attribute):
+ Use prototype_p.
+
+2010-12-18 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-objc.h (objc_maybe_warn_exceptions): New.
+ * stub-objc.c (objc_maybe_warn_exceptions): New.
+
+2010-12-10 Nathan Froyd <froydnj@codesourcery.com>
+
+ * c-common.h (readonly_error): Declare.
+ * c-common.c (readonly_error): Define.
+
+2010-12-09 Nathan Froyd <froydnj@codesourcery.com>
+
+ * c-common.h (invalid_indirection_error): Declare.
+ * c-common.c (invalid_indirection_error): Define.
+
+2010-12-03 Richard Guenther <rguenther@suse.de>
+
+ PR c/46745
+ * c-pretty-print.c (pp_c_postfix_expression): Handle MEM_REF.
+ (pp_c_unary_expression): Likewise.
+ (pp_c_expression): Likewise.
+
+2010-11-30 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (objc_finish_function): New.
+ (objc_non_volatilized_type): Removed.
+ (objc_type_quals_match): Removed.
+ * stub-objc.c (objc_finish_function): New.
+ (objc_non_volatilized_type): Removed.
+ (objc_type_quals_match): Removed.
+
+2010-11-30 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.h (parse_optimize_options): Declare.
+ * c-cppbuiltin.c, c-format.c, c-gimplify.c, c-lex.c, c-omp.c,
+ c-pch.c, c-pragma.c, c-semantics.c: Don't include toplev.h.
+
+2010-11-29 Joseph Myers <joseph@codesourcery.com>
+
+ * c-opts.c (check_deps_environment_vars): Use getenv instead of
+ GET_ENVIRONMENT.
+ * c-pch.c (O_BINARY): Don't define here.
+ * c-pragma.h: Include "cpplib.h" instead of <cpplib.h>.
+
+2010-11-25 Joseph Myers <joseph@codesourcery.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Pass &global_options to
+ targetm.except_unwind_info.
+
+2010-11-23 Joseph Myers <joseph@codesourcery.com>
+
+ * c-opts.c (c_common_handle_option): Pass location to
+ set_struct_debug_option.
+
+2010-11-23 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (visibility_options): Move from ../opts.c.
+ * c-common.h (struct visibility_flags, visibility_options):
+ Declare here.
+ * c-opts.c (finish_options): Rename to c_finish_options.
+ (c_common_init): Update call to finish_options.
+
+2010-11-22 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ PR objc/34033
+ * c-lex.c (lex_string): Check that each string in an Objective-C
+ string concat sequence starts with either one or zero '@', and
+ that there are no spurious '@' signs at the end.
+
+2010-11-20 Joseph Myers <joseph@codesourcery.com>
+
+ * c-pragma.c: Remove conditionals on HANDLE_PRAGMA_PACK,
+ HANDLE_PRAGMA_PACK_PUSH_POP, HANDLE_PRAGMA_WEAK and
+ HANDLE_PRAGMA_VISIBILITY.
+ * c-pragma.h (HANDLE_PRAGMA_WEAK, HANDLE_PRAGMA_PACK,
+ HANDLE_PRAGMA_VISIBILITY): Don't define.
+ (HANDLE_SYSV_PRAGMA, HANDLE_PRAGMA_PACK_PUSH_POP): Don't test.
+
+2010-11-20 Nathan Froyd <froydnj@codesourcery.com>
+
+ PR c++/16189
+ PR c++/36888
+ PR c++/45331
+ * c-common.h (keyword_begins_type_specifier): Declare.
+ (keyword_is_storage_class_specifier): Declare.
+ (keyword_is_type_qualifier): Declare.
+ * c-common.c (keyword_begins_type_specifier): New function.
+ (keyword_is_storage_class_specifier): New function.
+ (keyword_is_type_qualifier): Declare.
+
+2010-11-19 Joseph Myers <joseph@codesourcery.com>
+
+ PR c/46547
+ * c-common.c (in_late_binary_op): Define.
+ (c_common_truthvalue_conversion): Check in_late_binary_op before
+ calling c_save_expr.
+ * c-common.h (in_late_binary_op): Declare.
+
+2010-11-19 Joseph Myers <joseph@codesourcery.com>
+
+ * c-opts.c (c_common_handle_option): Update calls to
+ set_struct_debug_option.
+
+2010-11-19 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (objc_declare_protocols): Added additional argument.
+ * stub-objc.c (objc_declare_protocol): Same change.
+
+2010-11-18 Nathan Froyd <froydnj@codesourcery.com>
+
+ PR c/33193
+ * c-common.h (build_real_imag_expr): Declare.
+ * c-semantics.c (build_real_imag_expr): Define.
+
+2010-11-17 Joseph Myers <joseph@codesourcery.com>
+
+ * c-opts.c (c_common_parse_file): Take no arguments.
+ * c-common.h (c_common_parse_file): Update prototype.
+
+2010-11-16 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/46401
+ * c-common.c (warning_candidate_p): Don't track non-const calls
+ or STRING_CSTs.
+
+2010-11-15 Ian Lance Taylor <iant@google.com>
+
+ * c-lex.c (init_c_lex): Set macro debug callbacks if
+ flag_dump_go_spec is set.
+
+2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (objc_build_incr_expr_for_property_ref): New.
+ * stub-objc.c (objc_build_incr_expr_for_property_ref): New.
+
+2010-11-15 Nathan Froyd <froydnj@codesourcery.com>
+
+ PR preprocessor/45038
+ * c-cppbuiltin.c (c_cpp_builtins): Use different format for C++
+ dialects.
+
+2010-11-12 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.h (c_family_lang_mask): Declare.
+ * c-opts.c (c_family_lang_mask): Make extern.
+ * c-pragma.c (handle_pragma_diagnostic): Use
+ control_warning_option.
+
+2010-11-12 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (parse_optimize_options): Update call to
+ decode_options.
+ * c-common.h (c_common_handle_option): Update prototype.
+ * c-opts.c (c_common_handle_option): Take location_t parameter and
+ pass it to other functions.
+
+2010-11-11 Joseph Myers <joseph@codesourcery.com>
+
+ * c-opts.c (warning_as_error_callback): Remove.
+ (c_common_initialize_diagnostics): Don't call
+ register_warning_as_error_callback.
+ (c_common_handle_option): Handle -Werror=normalized= here.
+
+2010-11-10 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (handle_mode_attribute): Use %' and word "signedness"
+ in diagnostic.
+ * c-opts.c (c_common_parse_file): Start diagnostics with lowercase
+ letter.
+ * c-pragma.c (handle_pragma_target, handle_pragma_optimize):
+ Remove trailing '.' from diagnostics.
+ * c.opt (Wwrite-strings_: Avoid '`' in help text.
+
+2010-11-10 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (parse_optimize_options): Pass global_dc to
+ decode_options.
+ * c-opts.c (c_common_handle_option): Pass &global_options to
+ set_Wstrict_aliasing.
+ * c.opt (v): Don't mark Common or document here.
+
+2010-11-06 Iain Sandoe <iains@gcc.gnu.org>
+
+ PR target/44981
+ * c-format.c (format_type): New type gcc_objc_string_format_type.
+ (valid_stringptr_type_p): New.
+ (handle_format_arg_attribute): Use valid_stringptr_type_p ().
+ (check_format_string): Pass expected type, use
+ valid_stringptr_type_p (), check that the format string types are
+ consistent with the format specification.
+ (decode_format_attr): Warn if NSString is used outside objective-c.
+ (format_types_orig): Add NSString.
+ (format_name): New.
+ (format_flags): New.
+ (check_format_arg): Handle format strings requiring an external parser.
+ first_target_format_type: New variable.
+ (handle_format_attribute): Set up first_target_format_type, pass the
+ expected format arg string type to check_format_string().
+ * c-common.h (FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL): New flag.
+ * stub-objc.c (objc_string_ref_type_p): New.
+ (objc_check_format_arg): New.
+
+2010-11-04 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Fixed using the Objective-C 2.0 dot-syntax with class names.
+ * c-common.h (objc_build_class_component_ref): New.
+ * stub-objc.c (objc_build_class_component_ref): New.
+
+2010-11-03 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c.opt (Wproperty-assign-default): New option.
+
+2010-11-03 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Implemented -fobjc-std=objc1 flag.
+ * c.opt (fobjc-std=objc1): New option.
+
+2010-11-01 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Implemented format and noreturn attributes for Objective-C methods.
+ * c-common.c (handle_noreturn_attribute): Recognize 'noreturn'
+ attribute for Objective-C methods.
+
+2010-10-31 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (conversion_warning, warn_for_collisions_1): Use
+ EXPR_LOC_OR_HERE.
+
+2010-10-30 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Implemented Objective-C 2.0 @property, @synthesize and @dynamic.
+ * c-common.h (enum rid): Removed RID_COPIES and RID_IVAR.
+ (objc_add_property_declaration): Removed arguments for copies and
+ ivar.
+ (objc_build_getter_call): Renamed to
+ objc_maybe_build_component_ref.
+ (objc_build_setter_call): Renamed to objc_maybe_build_modify_expr.
+ (objc_is_property_ref): New.
+ * c-common.c (c_common_reswords): Removed copies and ivar.
+ * stub-objc.c (objc_add_property_declaration): Removed arguments
+ for copies and ivar.
+ (objc_build_getter_call): Renamed to
+ objc_maybe_build_component_ref.
+ (objc_build_setter_call): Renamed to objc_maybe_build_modify_expr.
+ (objc_is_property_ref): New.
+
+2010-10-29 Arnaud Charlet <charlet@adacore.com>
+ Matthew Gingell <gingell@adacore.com>
+
+ * c-ada-spec.c (separate_class_package): New function.
+ (pp_ada_tree_identifier): Prefix references to C++ classes with the
+ name of their enclosing package.
+ (print_ada_declaration): Use separate_class_package.
+
+2010-10-27 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (c_common_reswords): Add __is_literal_type.
+ * c-common.h (enum rid): Add RID_IS_LITERAL_TYPE.
+
+ * c-common.c (check_case_value): Remove special C++ code.
+
+2010-10-27 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (enum rid): Added RID_READWRITE, RID_ASSIGN,
+ RID_RETAIN, RID_COPY and RID_NONATOMIC. Updated RID_FIRST_PATTR
+ and RID_LAST_PATTR.
+ (objc_add_property_declaration): Added additional arguments.
+ (objc_property_attribute_kind): Removed.
+ (objc_set_property_attr): Removed.
+ * c-common.c (c_common_reswords): Added readwrite, assign, retain,
+ copy and nonatomic.
+ * stub-objc.c (objc_add_property_declaration): Added additional
+ arguments.
+ (objc_set_property_attr): Removed.
+
+2010-10-27 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (objc_add_property_variable): Renamed to
+ objc_add_property_declaration. Added location argument.
+ * stub-objc.c (objc_add_property_variable): Same change.
+
+2010-10-23 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (objc_maybe_printable_name): New.
+ * stub-objc.c (objc_maybe_printable_name): New.
+
+2010-10-22 Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
+ Andrew Pinski <pinskia@gmail.com>
+
+ * c-common.h (c_common_mark_addressable_vec): Declare.
+ * c-common.c (c_common_mark_addressable_vec): New function.
+
+2010-10-20 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (objc_set_method_type): Removed.
+ (objc_add_method_declaration): Added boolean argument.
+ (objc_start_method_definition): Same change.
+ (objc_build_method_signature): Same change.
+ * stub-objc.c (objc_set_method_type): Removed.
+ (objc_add_method_declaration): Added boolean argument.
+ (objc_start_method_definition): Same change.
+ (objc_build_method_signature): Same change.
+
+2010-10-20 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (finish_file): Removed.
+ (objc_write_global_declarations): New.
+ * c-opts.c (c_common_parse_file): Do not call finish_file.
+ * stub-objc.c (objc_write_global_declarations): New.
+
+2010-10-18 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Implemented parsing @synthesize and @dynamic for
+ Objective-C/Objective-C++.
+ * c-common.h (enum rid): Add RID_AT_SYNTHESIZE and RID_AT_DYNAMIC.
+ (objc_add_synthesize_declaration): New.
+ (objc_add_dynamic_declaration): New.
+ * c-common.c (c_common_reswords): Add synthesize and dynamic.
+ * stub-objc.c (objc_add_synthesize_declaration): New.
+ (objc_add_dynamic_declaration): New.
+
+2010-10-18 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ PR target/46041
+ * c-cppbuiltin.c (mode_has_fma): Move function here from
+ builtins.c. Don't use the fma optab, instead just use the
+ HAVE_fma* macros, so that __FP_FAST_FMA* will be defined when
+ using -save-temps.
+
+2010-10-18 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Merge from 'apple/trunk' branch on FSF servers.
+
+ 2005-11-08 Fariborz Jahanian <fjahanian@apple.com>
+
+ Radar 4330422
+ * c-common.h (objc_non_volatilized_type): New declaration
+ * stub-objc.c (objc_non_volatilized_type): New stub.
+
+2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Merge from 'apple/trunk' branch on FSF servers.
+
+ 2006-03-27 Fariborz Jahanian <fjahanian@apple.com>
+
+ Radar 4133425
+ * c-common.h (objc_diagnose_private_ivar): New decl.
+ * stub-objc.c (objc_diagnose_private_ivar): New stub.
+
+2010-10-17 Iain Sandoe <iains@gcc.gnu.org>
+
+ * c-common.c (c_common_reswords): Add package, RID_AT_PACKAGE.
+ * c-common.h (enum rid): Add RID_AT_PACKAGE.
+ (objc_ivar_visibility_kind): New enum.
+ (objc_set_visibility): Adjust prototype to use visibility enum.
+ * stub-objc.c (objc_set_visibility): Adjust stub to use
+ visibility enum.
+
+2010-10-14 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * c-cppbuiltin.c (builtin_define_float_constants): Emit
+ __FP_FAST_FMA, __FP_FAST_FMAF, and __FP_FAST_FMAL if the machine
+ has the appropriate fma builtins.
+ (c_cpp_builtins): Adjust call to builtin_define_float_constants.
+
+2010-10-14 Iain Sandoe <iains@gcc.gnu.org>
+
+ merge from FSF apple 'trunk' branch.
+ 2006 Fariborz Jahanian <fjahanian@apple.com>
+
+ Radars 4436866, 4505126, 4506903, 4517826
+ * c-common.c (c_common_resword): Define @property and its attributes.
+ * c-common.h: Define property attribute enum entries.
+ (OBJC_IS_PATTR_KEYWORD): New.
+ (objc_property_attribute_kind): New enum.
+ Declare objc_set_property_attr (), objc_add_property_variable (),
+ objc_build_getter_call () and objc_build_setter_call ().
+ * stub-objc.c (objc_set_property_attr): New stub.
+ (objc_add_property_variable): Likewise.
+ (objc_build_getter_call): Likewise.
+ (objc_build_setter_call) Likewise.
+
+2010-10-13 Iain Sandoe <iains@gcc.gnu.org>
+
+ merge from FSF apple 'trunk' branch.
+ 2006-04-26 Fariborz Jahanian <fjahanian@apple.com>
+
+ Radar 3803157 (method attributes)
+ * c-common.c (handle_deprecated_attribute): Recognize
+ objc methods as valid declarations.
+ * c-common.h: Declare objc_method_decl ().
+ * stub-objc.c (objc_method_decl): New stub.
+
+2010-10-08 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (parse_optimize_options): Call
+ decode_cmdline_options_to_array_default_mask before
+ decode_options. Update arguments to decode_options.
+ * c-common.h (c_common_init_options_struct): Declare.
+ * c-opts.c (c_common_init_options_struct): New. Split out from
+ c_common_init_options.
+
+2010-10-06 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Implemented fast enumeration for Objective-C.
+ * c-common.h (objc_finish_foreach_loop): New.
+ * stub-objc.c (objc_finish_foreach_loop): New.
+
+2010-10-05 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.h (struct diagnostic_context): Don't declare here.
+ (c_common_initialize_diagnostics): Declare using
+ diagnostic_context typedef.
+ * c-opts.c (c_common_handle_option): Pass global_dc to
+ handle_generated_option.
+
+2010-10-04 Joseph Myers <joseph@codesourcery.com>
+
+ * c-opts.c (c_common_handle_option): Pass &global_options_set to
+ handle_generated_option.
+
+2010-10-03 Ian Lance Taylor <iant@google.com>
+
+ * c.opt (-fplan9-extensions): New option.
+
+2010-10-03 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
+
+ * c-cppbuiltin.c (define__GNUC__, builtin_define_type_precision):
+ Remove.
+ (c_cpp_builtins): Call functions from cppbuiltin.c instead
+ of duplicating code.
+
+2010-09-30 Iain Sandoe <iains@gcc.gnu.org>
+
+ * c-common.c: Add two new entries for @optional
+ and @required keywords.
+
+ merge from FSF 'apple/trunk' branch.
+ 2006-01-30 Fariborz Jahanian <fjahanian@apple.com>
+
+ Radar 4386773
+ * c-common.h (RID_AT_OPTIONAL, RID_AT_REQUIRED): Two new
+ objective-c keywords.
+ (objc_set_method_opt): New declaration.
+ * stub-objc.c (objc_set_method_opt): New stub.
+
+2010-09-30 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (handle_optimize_attribute): Pass &global_options to
+ cl_optimization_save and cl_optimization_restore.
+ * c-opts.c (c_common_handle_option): Pass &global_options to
+ handle_generated_option.
+ * c-pragma.c (handle_pragma_diagnostic): Use option_flag_var.
+ (handle_pragma_pop_options, handle_pragma_reset_options): Pass
+ &global_options to cl_optimization_restore.
+
+2010-09-30 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-lex.c (c_lex_with_flags): Updated comments for CPP_AT_NAME
+ Objective-C/Objective-C++ keywords.
+
+2010-09-29 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Merge from 'apple/trunk' branch on FSF servers.
+
+ 2005-10-04 Fariborz Jahanian <fjahanian@apple.com>
+
+ Radar 4281748
+ * c-common.h (objc_check_global_decl): New declaration.
+ * stub-objc.c (objc_check_global_decl): New stub.
+
+2010-09-29 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt: Don't use VarExists.
+
+2010-09-29 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (c_cpp_error): Update names of diagnostic_context
+ members.
+ * c-cppbuiltin.c (c_cpp_builtins_optimize_pragma): Update names of
+ cl_optimization members.
+ * c-opts.c (warning_as_error_callback, c_common_handle_option,
+ sanitize_cpp_opts, finish_options): Update names of cpp_options
+ members.
+
+2010-09-29 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (OBJC_IS_CXX_KEYWORD): New macro. Updated comments.
+ (objc_is_reserved_word): Removed.
+ * c-common.c: Updated comments.
+ * c-lex.c (c_lex_with_flags): Use OBJC_IS_CXX_KEYWORD instead of
+ objc_is_reserved_word.
+ * stub-objc.c (objc_is_reserved_word): Removed.
+
+2010-09-28 Iain Sandoe <iains@gcc.gnu.org>
+
+ * c-common.h (objc_add_method_declaration): Adjust prototype to
+ include attributes.
+ (objc_start_method_definition): Likewise.
+ (objc_build_keyword_decl): Likewise.
+ * stub-objc.c:(objc_add_method_declaration): Handle attributes.
+ (objc_start_method_definition): Likewise.
+ (objc_build_keyword_decl): Likewise.
+
+2010-09-28 Iain Sandoe <iains@gcc.gnu.org>
+
+ * c-common.h (objc_start_class_interface): Adjust prototype.
+ (objc_start_category_interface): Likewise.
+ (objc_start_protocol): Likewise.
+ * stub-objc.c (objc_start_protocol): Adjust for extra argument.
+ (objc_start_class_interface): Likewise.
+ (objc_start_category_interface): Likewise.
+
+2010-09-27 Ian Lance Taylor <iant@google.com>
+
+ * c-common.c (c_common_attribute_table): Add no_split_stack.
+ (handle_no_split_stack_attribute): New static function.
+
+2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Merge from 'apple/trunk' branch on FSF servers.
+
+ 2005-12-15 Fariborz Jahanian <fjahanian@apple.com>
+
+ Radar 4229905
+ * c-common.h (objc_have_common_type): New declaration.
+ * stub-objc.c (objc_have_common_type): New stub.
+
+ 2005-06-22 Ziemowit Laski <zlaski@apple.com>
+
+ Radar 4154928
+ * c-common.h (objc_common_type): New prototype.
+ * stub-objc.c (objc_common_type): New stub.
+
+2010-09-24 Jan Hubicka <jh@suse.cz>
+
+ * c-common.c (handle_leaf_attribute): New function.
+ (struct attribute_spec c_common_att): Add leaf.
+
+2010-09-22 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt (-all-warnings, -ansi, -assert, -assert=, -comments,
+ -comments-in-macros, -define-macro, -define-macro=, -dependencies,
+ -dump, -dump=, -imacros, -imacros=, -include, -include=,
+ -include-barrier, -include-directory, -include-directory=,
+ -include-directory-after, -include-directory-after=,
+ -include-prefix, -include-prefix=, -include-with-prefix,
+ -include-with-prefix=, -include-with-prefix-after,
+ -include-with-prefix-after=, -include-with-prefix-before,
+ -include-with-prefix-before=, -no-integrated-cpp,
+ -no-line-commands, -no-standard-includes, -no-warnings, -output,
+ -output=, -pedantic, -pedantic-errors, -preprocess,
+ -print-missing-file-dependencies, -trace-includes, -traditional,
+ -traditional-cpp, -trigraphs, -undefine-macro, -undefine-macro=,
+ -user-dependencies, -verbose, -write-dependencies,
+ -write-user-dependencies, no-integrated-cpp, traditional): New.
+
+2010-09-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ PR objc/23710
+ * c-common.h (objc_start_method_definition): Return bool instead
+ of void.
+ * stub-objc.c (objc_start_method_definition): Return bool instead
+ of void.
+
+2010-09-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ PR objc/25965
+ * c-common.h (objc_get_interface_ivars): New declaration.
+ * stub-objc.c (objc_get_interface_ivars): New stub.
+
+2010-09-15 Ian Lance Taylor <iant@google.com>
+
+ * c-common.c (parse_optimize_options): Do not capitalize warning
+ messages. Remove period at end of warning message.
+
+2010-09-09 Nathan Sidwell <nathan@codesourcery.com>
+
+ * c-common.c (handle_alias_ifunc_attribute): New, broken out of ...
+ (handle_alias_attribute): ... here.
+ (handle_ifunc_attribute): New.
+
+2010-09-06 Mark Mitchell <mark@codesourcery.com>
+
+ * c-common.h (do_warn_double_promotion): Declare.
+ * c-common.c (do_warn_double_promotion): Define.
+
+2010-09-05 Mark Mitchell <mark@codesourcery.com>
+
+ * c.opt (Wdouble-promotion): New.
+
+2010-09-02 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt (falt-external-templates, fhuge-objects, fvtable-gc,
+ fvtable-thunks, fxref): Mark no longer supported in help text.
+
+2010-09-02 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt (Wimport, fall-virtual, falt-external-templates,
+ fdefault-inline, fenum-int-equiv, fexternal-templates,
+ fguiding-decls, fhonor-std, fhuge-objects, flabels-ok,
+ fname-mangling-version-, fnew-abi, fnonnull-objects,
+ foptional-diags, fsquangle, fstrict-prototype, fthis-is-variable,
+ fvtable-gc, fvtable-thunks, fxref): Mark with Ignore and Warn as
+ applicable.
+ (fhandle-exceptions): Mark with Alias and Warn.
+ * c-opts.c (c_common_handle_option): Don't handle options marked
+ as ignored.
+
+2010-09-02 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt (Wcomments, Werror-implicit-function-declaration,
+ ftemplate-depth-, std=c89, std=c9x, std=gnu89, std=gnu9x,
+ std=iso9899:1990, std=iso9899:1999, std=iso9899:199x): Mark as
+ aliases.
+ * c-common.c (option_codes): Use OPT_Wcomment instead of
+ OPT_Wcomments.
+ * c-opts.c (warning_as_error_callback, c_common_handle_option):
+ Don't handle options marked as aliases.
+
+2010-08-25 Richard Guenther <rguenther@suse.de>
+
+ * c-common.c (c_common_get_alias_set): Remove special
+ handling for pointers.
+
+2010-08-20 Nathan Froyd <froydnj@codesourcery.com>
+
+ * c-common.c: Use FOR_EACH_VEC_ELT.
+ * c-gimplify.c: Likewise.
+ * c-pragma.c: Likewise.
+
+2010-08-16 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt (MDX): Change back to MD. Mark NoDriverArg instead of
+ RejectDriver.
+ (MMDX): Change back to MMD. Mark NoDriverArg instead of
+ RejectDriver.
+ * c-opts.c (c_common_handle_option): Use OPT_MD and OPT_MMD
+ instead of OPT_MDX and OPT_MMDX.
+
+2010-08-16 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt (MDX, MMDX, lang-asm): Mark RejectDriver.
+
+2010-08-12 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt (MD, MMD): Change to MDX and MMDX.
+ * c-opts.c (c_common_handle_option): Use OPT_MMD and OPT_MMDX.
+
+2010-08-11 Joseph Myers <joseph@codesourcery.com>
+
+ * c-opts.c (c_common_handle_option): Call handle_generated_option
+ instead of handle_option.
+
+2010-08-08 Nathan Froyd <froydnj@codesourcery.com>
+
+ * c-pragma.c (add_to_renaming_pragma_list): Fix call to VEC_safe_push.
+ (maybe_apply_renaming_pragma): Delete unneeded declarations.
+
+2010-08-08 Nathan Froyd <froydnj@codesourcery.com>
+
+ * c-pragma.c (pending_redefinition): Declare. Declare a VEC of it.
+ (pending_redefine_extname): Change type to a VEC.
+ (add_to_renaming_pragma_list): Update for new type of
+ pending_redefine_extname.
+ (maybe_apply_renaming_pragma): Likewise.
+
+2010-08-04 Arnaud Charlet <charlet@adacore.com>
+
+ * c-ada-spec.c (dump_ada_template): Mark underlying instance type as
+ visited.
+ (dump_generic_ada_node): Code clean up. Use TREE_VISITED flag to
+ decide whether a type has already been declared/seen.
+ Do not go to the original type.
+ (dump_nested_types): New parameter forward.
+ Generate forward declaration if needed and mark type as visited.
+ (print_ada_declaration): Call dump_nested_types if not already done.
+ Mark types as visited.
+
+2010-08-03 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt (-print-pch-checksum): Remove option.
+ * c-opts.c (c_common_handle_option): Don't handle
+ OPT_print_pch_checksum.
+
+2010-07-27 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.h (c_common_handle_option): Update prototype and return
+ value type.
+ * c-opts.c (c_common_handle_option): Update prototype and return
+ value type. Update calls to handle_option and
+ enable_warning_as_error.
+
+2010-07-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/45079
+ * c-pretty-print.c (pp_c_expression): Handle C_MAYBE_CONST_EXPR.
+
+2010-07-27 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.h (c_common_missing_argument): Remove.
+ * c-opts.c (c_common_missing_argument): Remove.
+ * c.opt (A, D, F, I, MD, MMD, MQ, MT, U, fconstant-string-class=,
+ idirafter, imacros, include, isysroot, isystem, iquote): Add
+ MissingArgError.
+ * c-objc-common.h (LANG_HOOKS_MISSING_ARGUMENT): Remove.
+
+2010-07-27 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.h (c_common_option_lang_mask,
+ c_common_initialize_diagnostics, c_common_complain_wrong_lang_p):
+ New.
+ (c_common_init_options): Update prototype.
+ * c-opts.c (c_common_option_lang_mask): New.
+ (c_common_initialize_diagnostics): Split out of
+ c_common_init_options.
+ (accept_all_c_family_options, c_common_complain_wrong_lang_p):
+ New.
+ (c_common_init_options): Update prototype. Use decoded options in
+ search for -lang-asm.
+
+2010-07-15 Nathan Froyd <froydnj@codesourcery.com>
+
+ * c-common.c: Carefully replace TREE_CHAIN with DECL_CHAIN.
+ * c-format.c: Likewise.
+
+2010-07-08 Manuel López-Ibáñez <manu@gcc.gnu.org>
+
+ * c-common.h: Include diagnostic-core.h. Error if already
+ included.
+ * c-semantics.c: Do not define GCC_DIAG_STYLE here.
+
+2010-07-03 Manuel López-Ibáñez <manu@gcc.gnu.org>
+
+ * c-family/c-common.c (IN_GCC_FRONTEND): Do not undef.
+ Do not include expr.h
+ (vector_mode_valid_p): Move here.
+
+2010-06-21 DJ Delorie <dj@redhat.com>
+
+ * c-pragma.c (handle_pragma_diagnostic): Add push/pop,
+ allow these pragmas anywhere.
+
+2010-06-14 Jakub Jelinek <jakub@redhat.com>
+
+ PR bootstrap/44509
+ * c-cppbuiltin.c: Include gt-c-family-c-cppbuiltin.h.
+ (lazy_hex_fp_values, lazy_hex_fp_value_count): Add GTY(()) markers.
+ (lazy_hex_fp_value, builtin_define_with_hex_fp_value): Use
+ ggc_strdup instead of xstrdup.
+
+2010-06-10 Jakub Jelinek <jakub@redhat.com>
+
+ * c-cppbuiltin.c: Include cpp-id-data.h.
+ (lazy_hex_fp_values, lazy_hex_fp_value_count): New variables.
+ (lazy_hex_fp_value): New function.
+ (builtin_define_with_hex_fp_value): Provide definitions lazily.
+
+2010-06-30 Manuel López-Ibáñez <manu@gcc.gnu.org>
+
+ * c-gimplify.c: Do not include tree-flow.h
+
+2010-06-29 Joern Rennecke <joern.rennecke@embecosm.com>
+
+ PR other/44034
+ * c-common.c: Rename targetm member:
+ targetm.enum_va_list -> targetm.enum_va_list_p
+
+2010-06-28 Anatoly Sokolov <aesok@post.ru>
+
+ * c-common.c (shorten_compare): Adjust call to force_fit_type_double.
+
+2010-06-28 Steven Bosscher <steven@gcc.gnu.org>
+
+ * c-cppbuiltin.c: Do not include except.h.
+
+2010-06-24 Andi Kleen <ak@linux.intel.com>
+
+ * c-common.c (warn_for_omitted_condop): New.
+ * c-common.h (warn_for_omitted_condop): Add prototype.
+
+2010-06-21 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt (lang-objc): Remove.
+ * c-opts.c (c_common_handle_option): Don't handle OPT_lang_objc.
+
+2010-06-21 Joern Rennecke <joern.rennecke@embecosm.com>
+
+ * c-opts.c: Include "tm_p.h".
+
+2010-06-20 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (parse_optimize_options): Update call to
+ decode_options.
+
+2010-06-18 Nathan Froyd <froydnj@codesourcery.com>
+
+ * c-common.c (record_types_used_by_current_var_decl): Adjust for
+ new type of types_used_by_cur_var_decl.
+
+2010-06-17 Joern Rennecke <joern.rennecke@embecosm.com>
+
+ PR bootstrap/44512
+ * c-cppbuiltin.c (builtin_define_with_hex_fp_value): Add cast
+ for C++ standard compliance.
+
+2010-06-16 Jason Merrill <jason@redhat.com>
+
+ * c.opt: Add -Wnoexcept.
+
+2010-06-16 Richard Guenther <rguenther@suse.de>
+
+ PR c/44555
+ * c-common.c (c_common_truthvalue_conversion): Remove
+ premature and wrong optimization concering ADDR_EXPRs.
+
+2010-06-15 Arnaud Charlet <charlet@adacore.com>
+
+ * c-ada-spec.c (dump_sloc): Remove column info.
+ (is_simple_enum): New function.
+ (dump_generic_ada_node, print_ada_declaration): Map C enum types to Ada
+ enum types when relevant.
+
+2010-06-11 Manuel López-Ibáñez <manu@gcc.gnu.org>
+
+ * c-common.c (conversion_warning): Warn at expression
+ location.
+
+2010-06-10 Joseph Myers <joseph@codesourcery.com>
+
+ * c-opts.c (c_common_handle_option): Don't handle
+ OPT_fshow_column.
+
+2010-06-08 Laurynas Biveinis <laurynas.biveinis@gmail.com>
+
+ * c-pragma.c (push_alignment): Use typed GC allocation.
+ (handle_pragma_push_options): Likewise.
+
+ * c-common.c (parse_optimize_options): Likewise.
+
+ * c-common.h (struct sorted_fields_type): Add variable_size GTY
+ option.
+
+2010-06-07 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (flag_preprocess_only, flag_undef, flag_no_builtin,
+ flag_no_nonansi_builtin, flag_short_double, flag_short_wchar,
+ flag_lax_vector_conversions, flag_ms_extensions, flag_no_asm,
+ flag_signed_bitfields, warn_strict_null_sentinel,
+ flag_nil_receivers, flag_zero_link, flag_replace_objc_classes,
+ flag_gen_declaration, flag_no_gnu_keywords,
+ flag_implement_inlines, flag_implicit_templates,
+ flag_implicit_inline_templates, flag_optional_diags,
+ flag_elide_constructors, flag_default_inline, flag_rtti,
+ flag_conserve_space, flag_access_control, flag_check_new,
+ flag_new_for_scope, flag_weak, flag_working_directory,
+ flag_use_cxa_atexit, flag_use_cxa_get_exception_ptr,
+ flag_enforce_eh_specs, flag_threadsafe_statics,
+ flag_pretty_templates): Remove.
+ * c-common.h (flag_preprocess_only, flag_nil_receivers,
+ flag_objc_exceptions, flag_objc_sjlj_exceptions, flag_zero_link,
+ flag_replace_objc_classes, flag_undef, flag_no_builtin,
+ flag_no_nonansi_builtin, flag_short_double, flag_short_wchar,
+ flag_lax_vector_conversions, flag_ms_extensions, flag_no_asm,
+ flag_const_strings, flag_signed_bitfields, flag_gen_declaration,
+ flag_no_gnu_keywords, flag_implement_inlines,
+ flag_implicit_templates, flag_implicit_inline_templates,
+ flag_optional_diags, flag_elide_constructors, flag_default_inline,
+ flag_rtti, flag_conserve_space, flag_access_control,
+ flag_check_new, flag_new_for_scope, flag_weak,
+ flag_working_directory, flag_use_cxa_atexit,
+ flag_use_cxa_get_exception_ptr, flag_enforce_eh_specs,
+ flag_threadsafe_statics, flag_pretty_templates,
+ warn_strict_null_sentinel): Remove.
+ * c.opt (E, Wstrict-null-sentinel, faccess-control, fasm,
+ fbuiltin, fcheck-new, fconserve-space, felide-constructors,
+ fenforce-eh-specs, ffor-scope, fgnu-keywords, fimplement-inlines,
+ fimplicit-inline-templates, fimplicit-templates,
+ flax-vector-conversions, fms-extensions, fnil-receivers,
+ fnonansi-builtins, fpretty-templates, freplace-objc-classes,
+ frtti, fshort-double, fshort-enums, fshort-wchar,
+ fsigned-bitfields, fsigned-char, fstats, fthreadsafe-statics,
+ funsigned-bitfields, funsigned-char, fuse-cxa-atexit,
+ fuse-cxa-get-exception-ptr, fweak, fworking-directory, fzero-link,
+ gen-decls, undef): Use Var.
+ (fdefault-inline, foptional-diags): Document as doing nothing.
+ * c-opts.c (c_common_handle_option): Remove cases for options now
+ using Var. Mark ignored options as such.
+
+2010-06-05 Steven Bosscher <steven@gcc.gnu.org>
+
+ * 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 000000000..335acb0e3
--- /dev/null
+++ b/gcc/c-family/c-ada-spec.c
@@ -0,0 +1,3330 @@
+/* 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 <charlet@adacore.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#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 *);
+static bool separate_class_package (tree);
+
+#define LOCATION_COL(LOC) ((expand_location (LOC)).column)
+
+#define INDENT(SPACE) do { \
+ int i; for (i = 0; i<SPACE; i++) pp_space (buffer); } while (0)
+
+#define INDENT_INCR 3
+
+/* Given a cpp MACRO, compute the max length BUFFER_LEN of the macro, as well
+ as max length PARAM_LEN of arguments for fun_like macros, and also set
+ SUPPORTED to 0 if the macro cannot be mapped to an Ada construct. */
+
+static void
+macro_length (const cpp_macro *macro, int *supported, int *buffer_len,
+ int *param_len)
+{
+ int i;
+ unsigned j;
+
+ *supported = 1;
+ *buffer_len = 0;
+ *param_len = 0;
+
+ if (macro->fun_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 = &macro->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, &param_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 = &macro->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;
+}
+
+/* Return true if DECL refers to a C++ class type for which a
+ separate enclosing package has been or should be generated. */
+
+static bool
+separate_class_package (tree decl)
+{
+ if (decl)
+ {
+ tree type = TREE_TYPE (decl);
+ return type
+ && TREE_CODE (type) == RECORD_TYPE
+ && (TYPE_METHODS (type) || has_static_fields (type));
+ }
+ else
+ return false;
+}
+
+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 (separate_class_package (decl))
+ {
+ pp_string (buffer, "Class_");
+ pp_string (buffer, s);
+ pp_string (buffer, ".");
+ }
+
+ }
+ }
+ }
+
+ 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 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);
+ }
+}
+
+/* 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);
+
+ TREE_VISITED (get_underlying_decl (instance)) = 1;
+ 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;
+}
+
+/* Return true if NODE is a simple enum types, that can be mapped to an
+ Ada enum type directly. */
+
+static bool
+is_simple_enum (tree node)
+{
+ unsigned HOST_WIDE_INT count = 0;
+ tree value;
+
+ for (value = TYPE_VALUES (node); value; value = TREE_CHAIN (value))
+ {
+ tree int_val = TREE_VALUE (value);
+
+ if (TREE_CODE (int_val) != INTEGER_CST)
+ int_val = DECL_INITIAL (int_val);
+
+ if (!host_integerp (int_val, 0))
+ return false;
+ else if (TREE_INT_CST_LOW (int_val) != count)
+ return false;
+
+ count++;
+ }
+
+ return true;
+}
+
+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, "<vector>");
+ break;
+
+ case COMPLEX_TYPE:
+ pp_string (buffer, "<complex>");
+ break;
+
+ case ENUMERAL_TYPE:
+ if (name_only)
+ dump_generic_ada_node
+ (buffer, TYPE_NAME (node), node, cpp_check, spc, 0, true);
+ else
+ {
+ tree value = TYPE_VALUES (node);
+
+ if (is_simple_enum (node))
+ {
+ bool first = true;
+ spc += INDENT_INCR;
+ newline_and_indent (buffer, spc - 1);
+ pp_string (buffer, "(");
+ for (; value; value = TREE_CHAIN (value))
+ {
+ if (first)
+ first = false;
+ else
+ {
+ pp_string (buffer, ",");
+ newline_and_indent (buffer, spc);
+ }
+
+ pp_ada_tree_identifier
+ (buffer, TREE_PURPOSE (value), node, false);
+ }
+ pp_string (buffer, ");");
+ spc -= INDENT_INCR;
+ newline_and_indent (buffer, spc);
+ pp_string (buffer, "pragma Convention (C, ");
+ dump_generic_ada_node
+ (buffer, DECL_NAME (type) ? type : TYPE_NAME (node), type,
+ cpp_check, spc, 0, true);
+ pp_string (buffer, ")");
+ }
+ else
+ {
+ pp_string (buffer, "unsigned");
+ for (; 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, "<unnamed type decl>");
+ }
+ 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, "<unnamed type>");
+ }
+ 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, "<unnamed type>");
+ }
+ 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 type_name = 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. */
+
+ || underlying_type == NULL_TREE
+ || (!typ2
+ && !TREE_VISITED (underlying_type)
+ && !TREE_VISITED (type_name)
+ && !is_tagged_type (TREE_TYPE (node))
+ && DECL_SOURCE_FILE (underlying_type)
+ == source_file_base)
+ || (type_name && 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 != NULL_TREE)
+ dump_generic_ada_node
+ (buffer, type_name,
+ 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.
+ FORWARD indicates whether a forward declaration of T should be generated.
+ 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, bool forward,
+ 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;
+
+ if (forward)
+ {
+ pp_string (buffer, "type ");
+ dump_generic_ada_node
+ (buffer, t, t, cpp_check, spc, false, true);
+ pp_semicolon (buffer);
+ newline_and_indent (buffer, spc);
+ TREE_VISITED (t) = 1;
+ }
+
+ 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, false, 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, false, 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);
+ }
+
+ TREE_VISITED (t) = 1;
+}
+
+/* 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 stub = TYPE_STUB_DECL (orig);
+ tree typ = TREE_TYPE (stub);
+
+ 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
+ {
+ if (!TREE_VISITED (stub)
+ && DECL_SOURCE_FILE (stub) == source_file_base)
+ dump_nested_types
+ (buffer, stub, stub, true, cpp_check, spc);
+
+ 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);
+ TREE_VISITED (t) = 1;
+ return 1;
+ }
+
+ if (orig && TYPE_NAME (orig) && orig != TREE_TYPE (t))
+ pp_string (buffer, "subtype ");
+ else
+ {
+ dump_nested_types (buffer, t, t, false, cpp_check, spc);
+
+ if (separate_class_package (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;
+
+ case ENUMERAL_TYPE:
+ if ((orig && TYPE_NAME (orig) && orig != TREE_TYPE (t))
+ || !is_simple_enum (TREE_TYPE (t)))
+ pp_string (buffer, "subtype ");
+ else
+ pp_string (buffer, "type ");
+ break;
+
+ default:
+ pp_string (buffer, "subtype ");
+ }
+ TREE_VISITED (t) = 1;
+ }
+ 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;
+ }
+ }
+
+ TREE_VISITED (t) = 1;
+ 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 000000000..8aed15867
--- /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
+<http://www.gnu.org/licenses/>. */
+
+#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 000000000..eaf129340
--- /dev/null
+++ b/gcc/c-family/c-common.c
@@ -0,0 +1,9725 @@
+/* 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, 2011
+ 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
+<http://www.gnu.org/licenses/>. */
+
+#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 "c-objc.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"
+
+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 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;
+
+/* 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;
+
+/* 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. */
+
+
+/* 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 generate separate instantiation control files and
+ juggle them at link time. */
+
+int flag_use_repository;
+
+/* The C++ dialect being used. C++98 is the default. */
+
+enum cxx_dialect cxx_dialect = cxx98;
+
+/* 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 we are building a boolean conversion inside
+ convert_for_assignment, or some other late binary operation. If
+ build_binary_op is called for C (from code shared by C and C++) in
+ this case, then the operands have already been folded and the
+ result will not be folded again, so C_MAYBE_CONST_EXPR should not
+ be generated. */
+bool in_late_binary_op;
+
+/* 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},
+};
+
+/* Global visibility options. */
+struct visibility_flags visibility_options;
+
+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_leaf_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_ifunc_attribute (bool, tree *, tree, tree, bool *);
+static tree handle_ifunc_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_no_split_stack_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.
+
+ Note the complication of the D_CXX_OBJC keywords. These are
+ reserved words such as 'class'. In C++, 'class' is a reserved
+ word. In Objective-C++ it is too. In Objective-C, it is a
+ reserved word too, but only if it follows an '@' sign.
+*/
+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 },
+ { "__is_literal_type", RID_IS_LITERAL_TYPE, 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 },
+ { "optional", RID_AT_OPTIONAL, D_OBJC },
+ { "required", RID_AT_REQUIRED, D_OBJC },
+ { "property", RID_AT_PROPERTY, D_OBJC },
+ { "package", RID_AT_PACKAGE, D_OBJC },
+ { "synthesize", RID_AT_SYNTHESIZE, D_OBJC },
+ { "dynamic", RID_AT_DYNAMIC, 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 },
+ /* These are recognized inside a property attribute list */
+ { "assign", RID_ASSIGN, D_OBJC },
+ { "copy", RID_COPY, D_OBJC },
+ { "getter", RID_GETTER, D_OBJC },
+ { "nonatomic", RID_NONATOMIC, D_OBJC },
+ { "readonly", RID_READONLY, D_OBJC },
+ { "readwrite", RID_READWRITE, D_OBJC },
+ { "retain", RID_RETAIN, D_OBJC },
+ { "setter", RID_SETTER, 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 },
+ { "leaf", 0, 0, true, false, false,
+ handle_leaf_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 },
+ { "ifunc", 1, 1, true, false, false,
+ handle_ifunc_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 },
+ { "no_split_stack", 0, 0, true, false, false,
+ handle_no_split_stack_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 VIEW_CONVERT_EXPR:
+ 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);
+ /* ??? Cope with user tricks that amount to offsetof. The middle-end is
+ not prepared to deal with them if they occur in initializers. */
+ if (op0 != orig_op0
+ && code == ADDR_EXPR
+ && (op1 = get_base_address (op0)) != NULL_TREE
+ && TREE_CODE (op1) == INDIRECT_REF
+ && TREE_CONSTANT (TREE_OPERAND (op1, 0)))
+ ret = fold_convert_loc (loc, TREE_TYPE (expr), fold_offsetof_1 (op0));
+ else if (op0 != orig_op0 || in_init)
+ ret = in_init
+ ? fold_build1_initializer_loc (loc, code, TREE_TYPE (expr), op0)
+ : fold_build1_loc (loc, code, TREE_TYPE (expr), op0);
+ else
+ ret = fold (expr);
+ if (code == INDIRECT_REF
+ && ret != expr
+ && 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 %<or%>"
+ " applied to non-boolean constant");
+ else
+ warning_at (location, OPT_Wlogical_op, "logical %<and%>"
+ " 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 %<or%> "
+ "of collectively exhaustive tests is always true");
+ else
+ warning_at (location, OPT_Wlogical_op,
+ "logical %<and%> "
+ "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 %<int%>",
+ 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 %<char **%>",
+ 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 "
+ "%<char **%>", 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);
+ location_t loc = EXPR_LOC_OR_HERE (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_at (loc, 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_at (loc, OPT_Wsign_conversion, "negative integer"
+ " implicitly converted to unsigned type");
+ else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
+ warning_at (loc, 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_at (loc, 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_at (loc, 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_at (loc, 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_LOC_OR_HERE (writer),
+ 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)
+{
+ if (DECL_P (x) && DECL_ARTIFICIAL (x))
+ return 0;
+
+ /* VOID_TYPE_P (TREE_TYPE (x)) is workaround for cp/tree.c
+ (lvalue_p) crash on TRY/CATCH. */
+ if (TREE_TYPE (x) == NULL_TREE || VOID_TYPE_P (TREE_TYPE (x)))
+ return 0;
+
+ if (!lvalue_p (x))
+ return 0;
+
+ /* No point to track non-const calls, they will never satisfy
+ operand_equal_p. */
+ if (TREE_CODE (x) == CALL_EXPR && (call_expr_flags (x) & ECF_CONST) == 0)
+ return 0;
+
+ if (TREE_CODE (x) == STRING_CST)
+ return 0;
+
+ return 1;
+}
+
+/* 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;
+
+ 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);
+
+ /* If primopN is first sign-extended from primopN's precision to opN's
+ precision, then zero-extended from opN's precision to
+ *restype_ptr precision, shortenings might be invalid. */
+ if (TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (TREE_TYPE (op0))
+ && TYPE_PRECISION (TREE_TYPE (op0)) < TYPE_PRECISION (*restype_ptr)
+ && !unsignedp0
+ && TYPE_UNSIGNED (TREE_TYPE (op0)))
+ primop0 = op0;
+ if (TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (TREE_TYPE (op1))
+ && TYPE_PRECISION (TREE_TYPE (op1)) < TYPE_PRECISION (*restype_ptr)
+ && !unsignedp1
+ && TYPE_UNSIGNED (TREE_TYPE (op1)))
+ primop1 = op1;
+
+ /* 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_to_double_int (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 %<void *%> 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 %<true%>",
+ inner);
+ return truthvalue_true_node;
+ }
+ break;
+ }
+
+ 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 ())
+ {
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree op2 = TREE_OPERAND (expr, 2);
+ /* In C++ one of the arms might have void type if it is throw. */
+ if (!VOID_TYPE_P (TREE_TYPE (op1)))
+ op1 = c_common_truthvalue_conversion (location, op1);
+ if (!VOID_TYPE_P (TREE_TYPE (op2)))
+ op2 = c_common_truthvalue_conversion (location, op2);
+ expr = fold_build3_loc (location, COND_EXPR, truthvalue_type_node,
+ TREE_OPERAND (expr, 0), op1, op2);
+ 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:
+ {
+ tree totype = TREE_TYPE (expr);
+ tree fromtype = TREE_TYPE (TREE_OPERAND (expr, 0));
+
+ /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
+ since that affects how `default_conversion' will behave. */
+ if (TREE_CODE (totype) == REFERENCE_TYPE
+ || TREE_CODE (fromtype) == REFERENCE_TYPE)
+ break;
+ /* Don't strip a conversion from C++0x scoped enum, since they
+ don't implicitly convert to other types. */
+ if (TREE_CODE (fromtype) == ENUMERAL_TYPE
+ && ENUM_IS_SCOPED (fromtype))
+ break;
+ /* If this isn't narrowing the argument, we can ignore it. */
+ if (TYPE_PRECISION (totype) >= TYPE_PRECISION (fromtype))
+ 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 = (in_late_binary_op ? save_expr (expr) : 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 %<restrict%>");
+ }
+}
+
+/* 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 n_elements;
+ 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 ();
+ }
+ /* FIXME: We want to use a DECL_CHAIN iteration method here, but
+ TYPE_VALUES of ENUMERAL_TYPEs is stored as a TREE_LIST. */
+ n_elements = list_length (t2);
+ /* 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) | (n_elements << 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);
+ }
+
+ /* 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 %<sizeof%> 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_p)
+ {
+ int l;
+ const char *pname;
+ tree ptype;
+
+ for (l = 0; targetm.enum_va_list_p (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)
+{
+ const struct attribute_spec *spec = lookup_attribute_spec (attr_id);
+ if (spec == NULL)
+ /* Unknown attribute that we'll end up ignoring, return true so we
+ don't complain about an identifier argument. */
+ return true;
+ else if (!strcmp ("mode", spec->name)
+ || !strcmp ("format", spec->name)
+ || !strcmp ("cleanup", spec->name))
+ 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
+ || objc_method_decl (TREE_CODE (*node)))
+ 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 a "leaf" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_leaf_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;
+ }
+ if (!TREE_PUBLIC (*node))
+ {
+ warning (OPT_Wattributes, "%qE attribute has no effect on unit local functions", 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;
+}
+
+/* Nonzero if the mode is a valid vector mode for this architecture.
+ This returns nonzero even if there is no hardware support for the
+ vector mode, but we can emulate with narrower modes. */
+
+static int
+vector_mode_valid_p (enum machine_mode mode)
+{
+ enum mode_class mclass = GET_MODE_CLASS (mode);
+ enum machine_mode innermode;
+
+ /* Doh! What's going on? */
+ if (mclass != MODE_VECTOR_INT
+ && mclass != MODE_VECTOR_FLOAT
+ && mclass != MODE_VECTOR_FRACT
+ && mclass != MODE_VECTOR_UFRACT
+ && mclass != MODE_VECTOR_ACCUM
+ && mclass != MODE_VECTOR_UACCUM)
+ return 0;
+
+ /* Hardware support. Woo hoo! */
+ if (targetm.vector_mode_supported_p (mode))
+ return 1;
+
+ innermode = GET_MODE_INNER (mode);
+
+ /* We should probably return 1 if requesting V4DI and we have no DI,
+ but we have V2DI, but this is probably very unlikely. */
+
+ /* If we have support for the inner mode, we can safely emulate it.
+ We may not have V2DI, but me can emulate with a pair of DIs. */
+ return targetm.scalar_mode_supported_p (innermode);
+}
+
+
+/* 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 ("signedness 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))
+ {
+ warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
+ *no_add_attrs = true;
+ }
+ else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
+ {
+ error ("indirect function %q+D cannot be declared weak", *node);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ 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" or "ifunc" attribute; arguments as in
+ struct attribute_spec.handler, except that IS_ALIAS tells us
+ whether this is an alias as opposed to ifunc attribute. */
+
+static tree
+handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
+ bool *no_add_attrs)
+{
+ tree decl = *node;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL
+ && (!is_alias || 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 %qE attribute", decl, name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ else if (!is_alias
+ && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl))
+ || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))))
+ {
+ error ("weak %q+D cannot be defined %qE", decl, name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ /* 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 ("attribute %qE argument not a string", name);
+ *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;
+ }
+
+ if (!is_alias)
+ /* ifuncs are also aliases, so set that attribute too. */
+ DECL_ATTRIBUTES (decl)
+ = tree_cons (get_identifier ("alias"), args, DECL_ATTRIBUTES (decl));
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle an "alias" or "ifunc" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_ifunc_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ return handle_alias_ifunc_attribute (false, node, name, args, no_add_attrs);
+}
+
+/* Handle an "alias" or "ifunc" 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)
+{
+ return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
+}
+
+/* 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;
+ }
+
+ if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
+ {
+ error ("indirect function %q+D cannot be declared weakref", *node);
+ *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
+ || objc_method_decl (TREE_CODE (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 (!prototype_p (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 (!prototype_p (*node))
+ {
+ 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;
+ struct cl_decoded_option *decoded_options;
+ unsigned int decoded_options_count;
+ 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_atomic (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_cmdline_options_to_array_default_mask (opt_argc, opt_argv,
+ &decoded_options,
+ &decoded_options_count);
+ decode_options (&global_options, &global_options_set,
+ decoded_options, decoded_options_count,
+ input_location, global_dc);
+
+ 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, &global_options);
+
+ /* If we previously had some optimization options, use them as the
+ default. */
+ if (old_opts)
+ cl_optimization_restore (&global_options,
+ 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 (&global_options, &cur_opts);
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "no_split_stack" attribute. */
+
+static tree
+handle_no_split_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;
+ }
+
+ 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_Wcomment},
+ {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->dc_warn_system_headers;
+ bool ret;
+
+ switch (level)
+ {
+ case CPP_DL_WARNING_SYSHDR:
+ if (flag_no_output)
+ return false;
+ global_dc->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->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;
+}
+
+/* Fold an offsetof-like expression. EXPR is a nested sequence of component
+ references with an INDIRECT_REF of a constant at the bottom; much like the
+ traditional rendering of offsetof as a macro. Return the folded result. */
+
+tree
+fold_offsetof_1 (tree expr)
+{
+ tree base, off, t;
+
+ switch (TREE_CODE (expr))
+ {
+ case ERROR_MARK:
+ return expr;
+
+ case VAR_DECL:
+ error ("cannot apply %<offsetof%> to static data member %qD", expr);
+ return error_mark_node;
+
+ case CALL_EXPR:
+ case TARGET_EXPR:
+ error ("cannot apply %<offsetof%> when %<operator[]%> is overloaded");
+ return error_mark_node;
+
+ case NOP_EXPR:
+ case INDIRECT_REF:
+ if (!TREE_CONSTANT (TREE_OPERAND (expr, 0)))
+ {
+ error ("cannot apply %<offsetof%> to a non constant address");
+ return error_mark_node;
+ }
+ return TREE_OPERAND (expr, 0);
+
+ case COMPONENT_REF:
+ base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+ 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));
+ if (base == error_mark_node)
+ return base;
+
+ t = TREE_OPERAND (expr, 1);
+
+ /* Check if the offset goes beyond the upper bound of the array. */
+ if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) >= 0)
+ {
+ 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 = DECL_CHAIN (TREE_OPERAND (v, 1));
+ for (; fld_chain; fld_chain = DECL_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)));
+ }
+ }
+ }
+
+ t = convert (sizetype, t);
+ off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
+ 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);
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, off);
+}
+
+/* Likewise, but convert it to the return type of offsetof. */
+
+tree
+fold_offsetof (tree expr)
+{
+ return convert (size_type_node, fold_offsetof_1 (expr));
+}
+
+/* Warn for A ?: C expressions (with B omitted) where A is a boolean
+ expression, because B will always be true. */
+
+void
+warn_for_omitted_condop (location_t location, tree cond)
+{
+ if (truth_value_p (TREE_CODE (cond)))
+ warning_at (location, OPT_Wparentheses,
+ "the omitted middle operand in ?: will always be %<true%>, "
+ "suggest explicit middle operand");
+}
+
+/* Give an error for storing into ARG, which is 'const'. USE indicates
+ how ARG was being used. */
+
+void
+readonly_error (tree arg, enum lvalue_use use)
+{
+ gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
+ || use == lv_asm);
+ /* Using this macro rather than (for example) arrays of messages
+ ensures that all the format strings are checked at compile
+ time. */
+#define READONLY_MSG(A, I, D, AS) (use == lv_assign ? (A) \
+ : (use == lv_increment ? (I) \
+ : (use == lv_decrement ? (D) : (AS))))
+ if (TREE_CODE (arg) == COMPONENT_REF)
+ {
+ if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
+ error (READONLY_MSG (G_("assignment of member "
+ "%qD in read-only object"),
+ G_("increment of member "
+ "%qD in read-only object"),
+ G_("decrement of member "
+ "%qD in read-only object"),
+ G_("member %qD in read-only object "
+ "used as %<asm%> output")),
+ TREE_OPERAND (arg, 1));
+ else
+ error (READONLY_MSG (G_("assignment of read-only member %qD"),
+ G_("increment of read-only member %qD"),
+ G_("decrement of read-only member %qD"),
+ G_("read-only member %qD used as %<asm%> output")),
+ TREE_OPERAND (arg, 1));
+ }
+ else if (TREE_CODE (arg) == VAR_DECL)
+ error (READONLY_MSG (G_("assignment of read-only variable %qD"),
+ G_("increment of read-only variable %qD"),
+ G_("decrement of read-only variable %qD"),
+ G_("read-only variable %qD used as %<asm%> output")),
+ arg);
+ else if (TREE_CODE (arg) == PARM_DECL)
+ error (READONLY_MSG (G_("assignment of read-only parameter %qD"),
+ G_("increment of read-only parameter %qD"),
+ G_("decrement of read-only parameter %qD"),
+ G_("read-only parameter %qD use as %<asm%> output")),
+ arg);
+ else if (TREE_CODE (arg) == RESULT_DECL)
+ {
+ gcc_assert (c_dialect_cxx ());
+ error (READONLY_MSG (G_("assignment of "
+ "read-only named return value %qD"),
+ G_("increment of "
+ "read-only named return value %qD"),
+ G_("decrement of "
+ "read-only named return value %qD"),
+ G_("read-only named return value %qD "
+ "used as %<asm%>output")),
+ arg);
+ }
+ else if (TREE_CODE (arg) == FUNCTION_DECL)
+ error (READONLY_MSG (G_("assignment of function %qD"),
+ G_("increment of function %qD"),
+ G_("decrement of function %qD"),
+ G_("function %qD used as %<asm%> output")),
+ arg);
+ else
+ error (READONLY_MSG (G_("assignment of read-only location %qE"),
+ G_("increment of read-only location %qE"),
+ G_("decrement of read-only location %qE"),
+ G_("read-only location %qE used as %<asm%> output")),
+ arg);
+}
+
+/* Print an error message for an invalid lvalue. USE says
+ how the lvalue is being used and so selects the error message. LOC
+ is the location for the error. */
+
+void
+lvalue_error (location_t loc, enum lvalue_use use)
+{
+ switch (use)
+ {
+ case lv_assign:
+ error_at (loc, "lvalue required as left operand of assignment");
+ break;
+ case lv_increment:
+ error_at (loc, "lvalue required as increment operand");
+ break;
+ case lv_decrement:
+ error_at (loc, "lvalue required as decrement operand");
+ break;
+ case lv_addressof:
+ error_at (loc, "lvalue required as unary %<&%> operand");
+ break;
+ case lv_asm:
+ error_at (loc, "lvalue required in asm statement");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Print an error message for an invalid indirection of type TYPE.
+ ERRSTRING is the name of the operator for the indirection. */
+
+void
+invalid_indirection_error (location_t loc, tree type, ref_operator errstring)
+{
+ switch (errstring)
+ {
+ case RO_NULL:
+ gcc_assert (c_dialect_cxx ());
+ error_at (loc, "invalid type argument (have %qT)", type);
+ break;
+ case RO_ARRAY_INDEXING:
+ error_at (loc,
+ "invalid type argument of array indexing (have %qT)",
+ type);
+ break;
+ case RO_UNARY_STAR:
+ error_at (loc,
+ "invalid type argument of unary %<*%> (have %qT)",
+ type);
+ break;
+ case RO_ARROW:
+ error_at (loc,
+ "invalid type argument of %<->%> (have %qT)",
+ type);
+ break;
+ case RO_IMPLICIT_CONVERSION:
+ error_at (loc,
+ "invalid type argument of implicit conversion (have %qT)",
+ type);
+ 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;
+}
+
+/* Like c_mark_addressable but don't check register qualifier. */
+void
+c_common_mark_addressable_vec (tree t)
+{
+ while (handled_component_p (t))
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ return;
+ TREE_ADDRESSABLE (t) = 1;
+}
+
+
+
+/* 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 %<char%>");
+}
+
+/* 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 %<X<=Y<=Z%> 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");
+ }
+}
+
+/* RESULT_TYPE is the result of converting TYPE1 and TYPE2 to a common
+ type via c_common_type. If -Wdouble-promotion is in use, and the
+ conditions for warning have been met, issue a warning. GMSGID is
+ the warning message. It must have two %T specifiers for the type
+ that was converted (generally "float") and the type to which it was
+ converted (generally "double), respectively. LOC is the location
+ to which the awrning should refer. */
+
+void
+do_warn_double_promotion (tree result_type, tree type1, tree type2,
+ const char *gmsgid, location_t loc)
+{
+ tree source_type;
+
+ if (!warn_double_promotion)
+ return;
+ /* If the conversion will not occur at run-time, there is no need to
+ warn about it. */
+ if (c_inhibit_evaluation_warnings)
+ return;
+ if (TYPE_MAIN_VARIANT (result_type) != double_type_node
+ && TYPE_MAIN_VARIANT (result_type) != complex_double_type_node)
+ return;
+ if (TYPE_MAIN_VARIANT (type1) == float_type_node
+ || TYPE_MAIN_VARIANT (type1) == complex_float_type_node)
+ source_type = type1;
+ else if (TYPE_MAIN_VARIANT (type2) == float_type_node
+ || TYPE_MAIN_VARIANT (type2) == complex_float_type_node)
+ source_type = type2;
+ else
+ return;
+ warning_at (loc, OPT_Wdouble_promotion, gmsgid, source_type, result_type);
+}
+
+/* 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;
+ }
+}
+
+/* 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));
+
+ while (!VEC_empty (tree, types_used_by_cur_var_decl))
+ {
+ tree type = VEC_pop (tree, types_used_by_cur_var_decl);
+ types_used_by_var_decl_insert (type, decl);
+ }
+}
+
+/* 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_EACH_VEC_ELT (tree, orig, ix, t)
+ VEC_quick_push (tree, ret, t);
+ return ret;
+}
+
+/* Return true if KEYWORD starts a type specifier. */
+
+bool
+keyword_begins_type_specifier (enum rid keyword)
+{
+ switch (keyword)
+ {
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_INT128:
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_BOOL:
+ case RID_WCHAR:
+ case RID_CHAR16:
+ case RID_CHAR32:
+ case RID_SAT:
+ case RID_COMPLEX:
+ case RID_TYPEOF:
+ case RID_STRUCT:
+ case RID_CLASS:
+ case RID_UNION:
+ case RID_ENUM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Return true if KEYWORD names a type qualifier. */
+
+bool
+keyword_is_type_qualifier (enum rid keyword)
+{
+ switch (keyword)
+ {
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Return true if KEYWORD names a storage class specifier.
+
+ RID_TYPEDEF is not included in this list despite `typedef' being
+ listed in C99 6.7.1.1. 6.7.1.3 indicates that `typedef' is listed as
+ such for syntactic convenience only. */
+
+bool
+keyword_is_storage_class_specifier (enum rid keyword)
+{
+ switch (keyword)
+ {
+ case RID_STATIC:
+ case RID_EXTERN:
+ case RID_REGISTER:
+ case RID_AUTO:
+ case RID_MUTABLE:
+ case RID_THREAD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Return true if KEYWORD names a function-specifier [dcl.fct.spec]. */
+
+static bool
+keyword_is_function_specifier (enum rid keyword)
+{
+ switch (keyword)
+ {
+ case RID_INLINE:
+ case RID_VIRTUAL:
+ case RID_EXPLICIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Return true if KEYWORD names a decl-specifier [dcl.spec] or a
+ declaration-specifier (C99 6.7). */
+
+bool
+keyword_is_decl_specifier (enum rid keyword)
+{
+ if (keyword_is_storage_class_specifier (keyword)
+ || keyword_is_type_qualifier (keyword)
+ || keyword_is_function_specifier (keyword))
+ return true;
+
+ switch (keyword)
+ {
+ case RID_TYPEDEF:
+ case RID_FRIEND:
+ case RID_CONSTEXPR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#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 000000000..c7e01b693
--- /dev/null
+++ b/gcc/c-family/c-common.def
@@ -0,0 +1,54 @@
+/* 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, 2010
+ 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
+<http://www.gnu.org/licenses/>. */
+
+/* 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 000000000..456c7e582
--- /dev/null
+++ b/gcc/c-family/c-common.h
@@ -0,0 +1,1011 @@
+/* Definitions for c-common.c.
+ Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
+ 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
+<http://www.gnu.org/licenses/>. */
+
+#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
+ diagnostic-core.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++. */
+#if defined(GCC_DIAGNOSTIC_CORE_H)
+#error \
+In order for the format checking to accept the C front end diagnostic \
+framework extensions, you must include this file before diagnostic-core.h \
+never after.
+#endif
+#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 ("PQ" reserved words - they do not appear after a '@' and
+ are keywords only in specific contexts) */
+ RID_IN, RID_OUT, RID_INOUT, RID_BYCOPY, RID_BYREF, RID_ONEWAY,
+
+ /* ObjC ("PATTR" reserved words - they do not appear after a '@'
+ and are keywords only as property attributes) */
+ RID_GETTER, RID_SETTER,
+ RID_READONLY, RID_READWRITE,
+ RID_ASSIGN, RID_RETAIN, RID_COPY,
+ RID_NONATOMIC,
+
+ /* 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++ (some of these are keywords in Objective-C as well, but only
+ if they appear after a '@') */
+ 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, RID_IS_LITERAL_TYPE,
+
+ /* C++0x */
+ RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
+
+ /* Objective-C ("AT" reserved words - they are only keywords when
+ they follow '@') */
+ 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_PACKAGE,
+ RID_AT_PROTOCOL, RID_AT_SELECTOR,
+ RID_AT_THROW, RID_AT_TRY, RID_AT_CATCH,
+ RID_AT_FINALLY, RID_AT_SYNCHRONIZED,
+ RID_AT_OPTIONAL, RID_AT_REQUIRED, RID_AT_PROPERTY,
+ RID_AT_SYNTHESIZE, RID_AT_DYNAMIC,
+ 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,
+ RID_FIRST_PATTR = RID_GETTER,
+ RID_LAST_PATTR = RID_NONATOMIC
+};
+
+#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)
+
+#define OBJC_IS_PATTR_KEYWORD(rid) \
+ ((unsigned int) (rid) >= (unsigned int) RID_FIRST_PATTR && \
+ (unsigned int) (rid) <= (unsigned int) RID_LAST_PATTR)
+
+/* OBJC_IS_CXX_KEYWORD recognizes the 'CXX_OBJC' keywords (such as
+ 'class') which are shared in a subtle way between Objective-C and
+ C++. When the lexer is lexing in Objective-C/Objective-C++, if it
+ finds '@' followed by one of these identifiers (eg, '@class'), it
+ recognizes the whole as an Objective-C keyword. If the identifier
+ is found elsewhere, it follows the rules of the C/C++ language.
+ */
+#define OBJC_IS_CXX_KEYWORD(rid) \
+ (rid == RID_CLASS \
+ || rid == RID_PUBLIC || rid == RID_PROTECTED || rid == RID_PRIVATE \
+ || rid == RID_TRY || rid == RID_THROW || rid == RID_CATCH)
+
+/* 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 <stdint.h>, 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((variable_size)) 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 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;
+
+/* 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. */
+
+
+/* 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;
+
+/* Tells the compiler what is the constant string class for ObjC. */
+
+extern const char *constant_string_class_name;
+
+
+/* C++ language option variables. */
+
+
+/* Nonzero means generate separate instantiation control files and
+ juggle them at link time. */
+
+extern int flag_use_repository;
+
+/* 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;
+
+/* 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))
+
+struct visibility_flags
+{
+ unsigned inpragma : 1; /* True when in #pragma GCC visibility. */
+ unsigned inlines_hidden : 1; /* True when -finlineshidden in effect. */
+};
+
+/* Global visibility options. */
+extern struct visibility_flags visibility_options;
+
+/* 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 bool in_late_binary_op;
+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 bool c_common_handle_option (size_t, const char *, int, int, location_t,
+ const struct cl_option_handlers *);
+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);
+
+extern bool keyword_begins_type_specifier (enum rid);
+extern bool keyword_is_storage_class_specifier (enum rid);
+extern bool keyword_is_type_qualifier (enum rid);
+extern bool keyword_is_decl_specifier (enum rid);
+
+#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 const unsigned int c_family_lang_mask;
+extern unsigned int c_common_option_lang_mask (void);
+extern void c_common_initialize_diagnostics (diagnostic_context *);
+extern bool c_common_complain_wrong_lang_p (const struct cl_option *);
+extern void c_common_init_options_struct (struct gcc_options *);
+extern void c_common_init_options (unsigned int, struct cl_decoded_option *);
+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 (void);
+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);
+
+extern void warn_for_omitted_condop (location_t, tree);
+
+/* 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);
+extern tree build_real_imag_expr (location_t, enum tree_code, 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);
+
+extern bool parse_optimize_options (tree, bool);
+
+/* 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_1 (tree);
+extern tree fold_offsetof (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 readonly_error (tree, enum lvalue_use);
+extern void lvalue_error (location_t, enum lvalue_use);
+extern void invalid_indirection_error (location_t, tree, ref_operator);
+
+extern int complete_array_type (tree *, tree, bool);
+
+extern tree builtin_type_for_size (int, bool);
+
+extern void c_common_mark_addressable_vec (tree);
+
+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 do_warn_double_promotion (tree, tree, tree, const char *,
+ location_t);
+extern void set_underlying_type (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);
+
+/* 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 000000000..576074c7a
--- /dev/null
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -0,0 +1,1155 @@
+/* Define builtin-in macros for the C family front ends.
+ Copyright (C) 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
+<http://www.gnu.org/licenses/>. */
+
+#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 "debug.h" /* For dwarf2out_do_cfi_asm. */
+#include "tm_p.h" /* For TARGET_CPU_CPP_BUILTINS & friends. */
+#include "target.h"
+#include "cpp-id-data.h"
+#include "cppbuiltin.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_sizeof (const char *, tree);
+static void builtin_define_float_constants (const char *,
+ const char *,
+ const char *,
+ const char *,
+ tree);
+
+/* Return true if MODE provides a fast multiply/add (FMA) builtin function.
+ Originally this function used the fma optab, but that doesn't work with
+ -save-temps, so just rely on the HAVE_fma macros for the standard floating
+ point types. */
+
+static bool
+mode_has_fma (enum machine_mode mode)
+{
+ switch (mode)
+ {
+#ifdef HAVE_fmasf4
+ case SFmode:
+ return !!HAVE_fmasf4;
+#endif
+
+#ifdef HAVE_fmadf4
+ case DFmode:
+ return !!HAVE_fmadf4;
+#endif
+
+#ifdef HAVE_fmaxf4
+ case XFmode:
+ return !!HAVE_fmaxf4;
+#endif
+
+#ifdef HAVE_fmatf4
+ case TFmode:
+ return !!HAVE_fmatf4;
+#endif
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/* 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,
+ const char *fma_suffix,
+ 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<T>::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<T>::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<T>::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)));
+
+ /* Note whether we have fast FMA. */
+ if (mode_has_fma (TYPE_MODE (type)))
+ {
+ sprintf (name, "__FP_FAST_FMA%s", fma_suffix);
+ builtin_define_with_int_value (name, 1);
+ }
+}
+
+/* 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 macros used by <stdint.h>. */
+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->x_optimize_size && cur->x_optimize_size)
+ cpp_define (pfile, "__OPTIMIZE_SIZE__");
+ else if (prev->x_optimize_size && !cur->x_optimize_size)
+ cpp_undef (pfile, "__OPTIMIZE_SIZE__");
+
+ if (!prev->x_optimize && cur->x_optimize)
+ cpp_define (pfile, "__OPTIMIZE__");
+ else if (prev->x_optimize && !cur->x_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->x_flag_signaling_nans && cur->x_flag_signaling_nans)
+ cpp_define (pfile, "__SUPPORT_SNAN__");
+ else if (prev->x_flag_signaling_nans && !cur->x_flag_signaling_nans)
+ cpp_undef (pfile, "__SUPPORT_SNAN__");
+
+ if (!prev->x_flag_finite_math_only && cur->x_flag_finite_math_only)
+ {
+ cpp_undef (pfile, "__FINITE_MATH_ONLY__");
+ cpp_define (pfile, "__FINITE_MATH_ONLY__=1");
+ }
+ else if (!prev->x_flag_finite_math_only && cur->x_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_language_independent_builtin_macros (pfile);
+
+ if (c_dialect_cxx ())
+ {
+ int major;
+ parse_basever (&major, NULL, NULL);
+ cpp_define_formatted (pfile, "__GNUG__=%d", major);
+ }
+
+ /* 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 >= <value for version X>
+
+ 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 (targetm.except_unwind_info (&global_options) == UI_SJLJ)
+ 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);
+
+ /* stdint.h and the testsuite need to know these. */
+ builtin_define_stdint_macros ();
+
+ /* float.h needs to know this. */
+ 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", "F", 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. We use a different cast for C++ to avoid
+ problems with -Wold-style-cast. */
+ builtin_define_float_constants ("DBL", "L",
+ (c_dialect_cxx ()
+ ? "double(%s)"
+ : "((double)%s)"),
+ "", double_type_node);
+ builtin_define_float_constants ("LDBL", "L", "%s", "L",
+ 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. */
+ if (flag_gnu89_inline)
+ cpp_define (pfile, "__GNUC_GNU_INLINE__");
+ else
+ cpp_define (pfile, "__GNUC_STDC_INLINE__");
+
+ if (flag_no_inline)
+ cpp_define (pfile, "__NO_INLINE__");
+
+ 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");
+
+ if (int128_integer_type_node != NULL_TREE)
+ builtin_define_type_sizeof ("__SIZEOF_INT128__",
+ int128_integer_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);
+
+ /* 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__");
+}
+
+/* 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);
+}
+
+/* builtin_define_with_hex_fp_value is very expensive, so the following
+ array and function allows it to be done lazily when __DBL_MAX__
+ etc. is first used. */
+
+struct GTY(()) lazy_hex_fp_value_struct
+{
+ const char *hex_str;
+ cpp_macro *macro;
+ enum machine_mode mode;
+ int digits;
+ const char *fp_suffix;
+};
+static GTY(()) struct lazy_hex_fp_value_struct lazy_hex_fp_values[12];
+static GTY(()) int lazy_hex_fp_value_count;
+
+static bool
+lazy_hex_fp_value (cpp_reader *pfile ATTRIBUTE_UNUSED,
+ cpp_hashnode *node)
+{
+ REAL_VALUE_TYPE real;
+ char dec_str[64], buf1[256];
+ unsigned int idx;
+ if (node->value.builtin < BT_FIRST_USER
+ || (int) node->value.builtin >= BT_FIRST_USER + lazy_hex_fp_value_count)
+ return false;
+
+ idx = node->value.builtin - BT_FIRST_USER;
+ real_from_string (&real, lazy_hex_fp_values[idx].hex_str);
+ real_to_decimal_for_mode (dec_str, &real, sizeof (dec_str),
+ lazy_hex_fp_values[idx].digits, 0,
+ lazy_hex_fp_values[idx].mode);
+
+ sprintf (buf1, "%s%s", dec_str, lazy_hex_fp_values[idx].fp_suffix);
+ node->flags &= ~(NODE_BUILTIN | NODE_USED);
+ node->value.macro = lazy_hex_fp_values[idx].macro;
+ for (idx = 0; idx < node->value.macro->count; idx++)
+ if (node->value.macro->exp.tokens[idx].type == CPP_NUMBER)
+ break;
+ gcc_assert (idx < node->value.macro->count);
+ node->value.macro->exp.tokens[idx].val.str.len = strlen (buf1);
+ node->value.macro->exp.tokens[idx].val.str.text
+ = (const unsigned char *) ggc_strdup (buf1);
+ return true;
+}
+
+/* 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];
+
+ /* This is very expensive, so if possible expand them lazily. */
+ if (lazy_hex_fp_value_count < 12
+ && flag_dump_macros == 0
+ && !cpp_get_options (parse_in)->traditional)
+ {
+ struct cpp_hashnode *node;
+ if (lazy_hex_fp_value_count == 0)
+ cpp_get_callbacks (parse_in)->user_builtin_macro = lazy_hex_fp_value;
+ sprintf (buf2, fp_cast, "1.1");
+ sprintf (buf1, "%s=%s", macro, buf2);
+ cpp_define (parse_in, buf1);
+ node = C_CPP_HASHNODE (get_identifier (macro));
+ lazy_hex_fp_values[lazy_hex_fp_value_count].hex_str
+ = ggc_strdup (hex_str);
+ lazy_hex_fp_values[lazy_hex_fp_value_count].mode = TYPE_MODE (type);
+ lazy_hex_fp_values[lazy_hex_fp_value_count].digits = digits;
+ lazy_hex_fp_values[lazy_hex_fp_value_count].fp_suffix = fp_suffix;
+ lazy_hex_fp_values[lazy_hex_fp_value_count].macro = node->value.macro;
+ node->flags |= NODE_BUILTIN;
+ node->value.builtin
+ = (enum cpp_builtin_type) (BT_FIRST_USER + lazy_hex_fp_value_count);
+ lazy_hex_fp_value_count++;
+ return;
+ }
+
+ /* 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 <stdint.h> 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);
+ }
+}
+
+#include "gt-c-family-c-cppbuiltin.h"
diff --git a/gcc/c-family/c-dump.c b/gcc/c-family/c-dump.c
new file mode 100644
index 000000000..c698f6d18
--- /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, 2010 Free Software Foundation, Inc.
+ Written by Mark Mitchell <mark@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
+<http://www.gnu.org/licenses/>. */
+
+#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 000000000..85831eb56
--- /dev/null
+++ b/gcc/c-family/c-format.c
@@ -0,0 +1,3061 @@
+/* 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
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "c-objc.h"
+#include "intl.h"
+#include "diagnostic-core.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+#include "target.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,
+ gcc_objc_string_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,
+ int expected_format_type);
+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);
+
+static int first_target_format_type;
+static const char *format_name (int format_num);
+static int format_flags (int format_num);
+
+/* Check that we have a pointer to a string suitable for use as a format.
+ The default is to check for a char type.
+ For objective-c dialects, this is extended to include references to string
+ objects validated by objc_string_ref_type_p ().
+ Targets may also provide a string object type that can be used within c and
+ c++ and shared with their respective objective-c dialects. In this case the
+ reference to a format string is checked for validity via a hook.
+
+ The function returns true if strref points to any string type valid for the
+ language dialect and target. */
+
+static bool
+valid_stringptr_type_p (tree strref)
+{
+ return (strref != NULL
+ && TREE_CODE (strref) == POINTER_TYPE
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (strref)) == char_type_node
+ || objc_string_ref_type_p (strref)
+ || (*targetcm.string_object_ref_type_p) ((const_tree) strref)));
+}
+
+/* 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)
+ {
+ /* The format arg can be any string reference valid for the language and
+ target. We cannot be more specific in this case. */
+ if (!check_format_string (argument, format_num, flags, no_add_attrs, -1))
+ return NULL_TREE;
+ }
+
+ if (!valid_stringptr_type_p (TREE_TYPE (type)))
+ {
+ 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 reference suitable,
+ for the language dialect and target (in case the format attribute is in
+ error). When we know the specific reference type expected, this is also
+ checked. */
+static bool
+check_format_string (tree argument, unsigned HOST_WIDE_INT format_num,
+ int flags, bool *no_add_attrs, int expected_format_type)
+{
+ unsigned HOST_WIDE_INT i;
+ bool is_objc_sref, is_target_sref, is_char_ref;
+ tree ref;
+ int fmt_flags;
+
+ for (i = 1; i != format_num; i++)
+ {
+ if (argument == 0)
+ break;
+ argument = TREE_CHAIN (argument);
+ }
+
+ if (!argument
+ || !(ref = TREE_VALUE (argument))
+ || !valid_stringptr_type_p (ref))
+ {
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("format string argument is not a string type");
+ *no_add_attrs = true;
+ return false;
+ }
+
+ /* We only know that we want a suitable string reference. */
+ if (expected_format_type < 0)
+ return true;
+
+ /* Now check that the arg matches the expected type. */
+ is_char_ref =
+ (TYPE_MAIN_VARIANT (TREE_TYPE (ref)) == char_type_node);
+
+ fmt_flags = format_flags (expected_format_type);
+ is_objc_sref = is_target_sref = false;
+ if (!is_char_ref)
+ is_objc_sref = objc_string_ref_type_p (ref);
+
+ if (!(fmt_flags & FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL))
+ {
+ if (is_char_ref)
+ return true; /* OK, we expected a char and found one. */
+ else
+ {
+ /* We expected a char but found an extended string type. */
+ if (is_objc_sref)
+ error ("found a %<%s%> reference but the format argument should"
+ " be a string", format_name (gcc_objc_string_format_type));
+ else
+ error ("found a %qT but the format argument should be a string",
+ ref);
+ *no_add_attrs = true;
+ return false;
+ }
+ }
+
+ /* We expect a string object type as the format arg. */
+ if (is_char_ref)
+ {
+ error ("format argument should be a %<%s%> reference but"
+ " a string was found", format_name (expected_format_type));
+ *no_add_attrs = true;
+ return false;
+ }
+
+ /* We will assert that objective-c will support either its own string type
+ or the target-supplied variant. */
+ if (!is_objc_sref)
+ is_target_sref = (*targetcm.string_object_ref_type_p) ((const_tree) ref);
+
+ if (expected_format_type == (int) gcc_objc_string_format_type
+ && (is_objc_sref || is_target_sref))
+ return true;
+
+ /* We will allow a target string ref to match only itself. */
+ if (first_target_format_type
+ && expected_format_type >= first_target_format_type
+ && is_target_sref)
+ return true;
+ else
+ {
+ error ("format argument should be a %<%s%> reference",
+ format_name (expected_format_type));
+ *no_add_attrs = true;
+ return false;
+ }
+
+ gcc_unreachable ();
+}
+
+/* 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 (!c_dialect_objc ()
+ && info->format_type == gcc_objc_string_format_type)
+ {
+ gcc_assert (!validated_p);
+ warning (OPT_Wformat, "%qE is only allowed in Objective-C dialects",
+ format_type_id);
+ info->format_type = format_type_error;
+ return false;
+ }
+
+ 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)))
+
+/* Enum describing the kind of specifiers present in the format and
+ requiring an argument. */
+enum format_specifier_kind {
+ CF_KIND_FORMAT,
+ CF_KIND_FIELD_WIDTH,
+ CF_KIND_FIELD_PRECISION
+};
+
+static const char *kind_descriptions[] = {
+ N_("format"),
+ N_("field width specifier"),
+ N_("field precision specifier")
+};
+
+/* 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;
+ /* The kind of specifier that this type is used for. */
+ enum format_specifier_kind kind;
+ /* The starting character of the specifier. This never includes the
+ initial percent sign. */
+ const char *format_start;
+ /* The length of the specifier. */
+ int format_length;
+ /* 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
+ },
+ { "NSString", NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ FMT_FLAG_ARG_CONVERT|FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL, 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;
+
+/* Return the format name (as specified in the original table) for the format
+ type indicated by format_num. */
+static const char *
+format_name (int format_num)
+{
+ if (format_num >= 0 && format_num < n_format_types)
+ return format_types[format_num].name;
+ gcc_unreachable ();
+}
+
+/* Return the format flags (as specified in the original table) for the format
+ type indicated by format_num. */
+static int
+format_flags (int format_num)
+{
+ if (format_num >= 0 && format_num < n_format_types)
+ return format_types[format_num].flags;
+ gcc_unreachable ();
+}
+
+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 *);
+static void format_type_warning (format_wanted_type *, tree, tree);
+
+/* 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 = DECL_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 (format_types[info->format_type].flags
+ & (int) FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL)
+ {
+ bool objc_str = (info->format_type == gcc_objc_string_format_type);
+ /* We cannot examine this string here - but we can check that it is
+ a valid type. */
+ if (TREE_CODE (format_tree) != CONST_DECL
+ || !((objc_str && objc_string_ref_type_p (TREE_TYPE (format_tree)))
+ || (*targetcm.string_object_ref_type_p)
+ ((const_tree) TREE_TYPE (format_tree))))
+ {
+ res->number_non_literal++;
+ 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;
+ }
+ /* So, we have a valid literal string object and one or more params.
+ We need to use an external helper to parse the string into format
+ info. For Objective-C variants we provide the resource within the
+ objc tree, for target variants, via a hook. */
+ if (objc_str)
+ objc_check_format_arg (format_tree, params);
+ else if (targetcm.check_string_object_format_arg)
+ (*targetcm.check_string_object_format_arg) (format_tree, params);
+ /* Else we can't handle it and retire quietly. */
+ return;
+ }
+ 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 (*format_chars != 0)
+ {
+ 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;
+
+ 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,
+ &params, 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)
+ cur_param = NULL;
+ else
+ {
+ 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.kind = CF_KIND_FIELD_WIDTH;
+ width_wanted_type.format_start = format_chars - 1;
+ width_wanted_type.format_length = 1;
+ 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,
+ &params, 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)
+ cur_param = NULL;
+ else
+ {
+ 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.kind = CF_KIND_FIELD_PRECISION;
+ precision_wanted_type.param = cur_param;
+ precision_wanted_type.format_start = format_chars - 2;
+ precision_wanted_type.format_length = 2;
+ 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;
+ }
+ }
+
+ format_start = 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)
+ 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)
+ cur_param = NULL;
+ else
+ {
+ 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->kind = CF_KIND_FORMAT;
+ wanted_type_ptr->param = cur_param;
+ wanted_type_ptr->arg_num = arg_num;
+ wanted_type_ptr->format_start = format_start;
+ wanted_type_ptr->format_length = format_chars - format_start;
+ 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);
+ }
+
+ 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);
+}
+
+
+/* Check the argument types from a single format conversion (possibly
+ including width and precision arguments). */
+static void
+check_format_types (format_wanted_type *types)
+{
+ 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;
+
+ 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);
+
+ cur_param = types->param;
+ if (!cur_param)
+ {
+ format_type_warning (types, wanted_type, NULL);
+ continue;
+ }
+
+ cur_type = TREE_TYPE (cur_param);
+ if (cur_type == error_mark_node)
+ continue;
+ orig_cur_type = cur_type;
+ char_type_flag = 0;
+
+ 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, wanted_type, orig_cur_type);
+ 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, wanted_type, orig_cur_type);
+ }
+}
+
+
+/* Give a warning about a format argument of different type from that
+ expected. WANTED_TYPE is the type the argument should have, possibly
+ stripped of pointer dereferences. The description (such as "field
+ precision"), the placement in the format string, a possibly more
+ friendly name of WANTED_TYPE, and the number of pointer dereferences
+ are taken from TYPE. ARG_TYPE is the type of the actual argument,
+ or NULL if it is missing. */
+static void
+format_type_warning (format_wanted_type *type, tree wanted_type, tree arg_type)
+{
+ int kind = type->kind;
+ const char *wanted_type_name = type->wanted_type_name;
+ const char *format_start = type->format_start;
+ int format_length = type->format_length;
+ int pointer_count = type->pointer_count;
+ int arg_num = type->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
+ && arg_type
+ && 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 (arg_type)
+ warning (OPT_Wformat, "%s %<%s%.*s%> expects argument of type %<%s%s%>, "
+ "but argument %d has type %qT",
+ gettext (kind_descriptions[kind]),
+ (kind == CF_KIND_FORMAT ? "%" : ""),
+ format_length, format_start,
+ wanted_type_name, p, arg_num, arg_type);
+ else
+ warning (OPT_Wformat, "%s %<%s%.*s%> expects a matching %<%s%s%> argument",
+ gettext (kind_descriptions[kind]),
+ (kind == CF_KIND_FORMAT ? "%" : ""),
+ format_length, format_start, wanted_type_name, p);
+ }
+ else
+ {
+ if (arg_type)
+ warning (OPT_Wformat, "%s %<%s%.*s%> expects argument of type %<%T%s%>, "
+ "but argument %d has type %qT",
+ gettext (kind_descriptions[kind]),
+ (kind == CF_KIND_FORMAT ? "%" : ""),
+ format_length, format_start,
+ wanted_type, p, arg_num, arg_type);
+ else
+ warning (OPT_Wformat, "%s %<%s%.*s%> expects a matching %<%T%s%> argument",
+ gettext (kind_descriptions[kind]),
+ (kind == CF_KIND_FORMAT ? "%" : ""),
+ format_length, format_start, wanted_type, p);
+ }
+}
+
+
+/* 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 %<long%>"
+ " or %<long long%>");
+ 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 ("%<locus%> 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 ("%<location_t%> 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 ("%<tree%> is not defined as a type");
+ t = 0;
+ }
+ else if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
+ {
+ error ("%<tree%> 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 %<long%> or %<long long%>");
+ 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;
+ /* Provide a reference for the first potential external type. */
+ first_target_format_type = n_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, info.format_type))
+ 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 000000000..286219b16
--- /dev/null
+++ b/gcc/c-family/c-format.h
@@ -0,0 +1,329 @@
+/* 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, 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
+<http://www.gnu.org/licenses/>. */
+
+#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,
+ /* The format arg is an opaque object that will be parsed by an external
+ facility. */
+ FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL = 256
+ /* 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 000000000..769df7cd2
--- /dev/null
+++ b/gcc/c-family/c-gimplify.c
@@ -0,0 +1,188 @@
+/* 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 <s.pop@laposte.net>
+ Re-written to support lowering of whole function trees, documentation
+ and miscellaneous cleanups by Diego Novillo <dnovillo@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#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-inline.h"
+#include "diagnostic-core.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "flags.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_EACH_VEC_ELT (gimple, stack, i, bind)
+ 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 000000000..1ea57f1cd
--- /dev/null
+++ b/gcc/c-family/c-lex.c
@@ -0,0 +1,1089 @@
+/* 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,
+ 2011 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
+<http://www.gnu.org/licenses/>. */
+
+#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 "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 ("<top level>");
+ 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))
+ || flag_dump_go_spec != NULL)
+ {
+ 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_AT_KEYWORD (C_RID_CODE (*value))
+ || OBJC_IS_CXX_KEYWORD (C_RID_CODE (*value)))
+ {
+ type = CPP_AT_NAME;
+ /* Note the complication: if we found an OBJC_CXX
+ keyword, for example, 'class', we will be
+ returning a token of type CPP_AT_NAME and rid
+ code RID_CLASS (not RID_AT_CLASS). The language
+ parser needs to convert that to RID_AT_CLASS.
+ */
+ 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 %<unsigned long%> type"
+ : "integer constant is too large for %<long%> 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)
+ {
+ const_type = TREE_TYPE (value);
+ type = build_complex_type (type);
+ }
+ }
+
+ 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 (in that case, the strings can either
+ be ObjC strings, preceded by a single '@', or normal strings, not
+ preceded by '@'. The result will be a CPP_OBJC_STRING). 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;
+
+ /* objc_at_sign_was_seen is only used when doing Objective-C string
+ concatenation. It is 'true' if we have seen an '@' before the
+ current string, and 'false' if not. We must see exactly one or
+ zero '@' before each string. */
+ bool objc_at_sign_was_seen = false;
+
+ retry:
+ tok = cpp_get_token (parse_in);
+ switch (tok->type)
+ {
+ case CPP_PADDING:
+ goto retry;
+ case CPP_ATSIGN:
+ if (objc_string)
+ {
+ if (objc_at_sign_was_seen)
+ error ("repeated %<@%> before Objective-C string");
+
+ objc_at_sign_was_seen = 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));
+ if (objc_string)
+ objc_at_sign_was_seen = false;
+ goto retry;
+ }
+
+ /* It is an error if we saw a '@' with no following string. */
+ if (objc_at_sign_was_seen)
+ error ("stray %<@%> in program");
+
+ /* 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-objc.h b/gcc/c-family/c-objc.h
new file mode 100644
index 000000000..e67eedebd
--- /dev/null
+++ b/gcc/c-family/c-objc.h
@@ -0,0 +1,116 @@
+/* Definitions of Objective-C front-end entry points used for C and C++.
+ Copyright (C) 1987, 1993, 1994, 1995, 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
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_C_COMMON_OBJC_H
+#define GCC_C_COMMON_OBJC_H
+
+/* ObjC ivar visibility types. */
+typedef enum objc_ivar_visibility_kind {
+ OBJC_IVAR_VIS_PROTECTED = 0,
+ OBJC_IVAR_VIS_PUBLIC = 1,
+ OBJC_IVAR_VIS_PRIVATE = 2,
+ OBJC_IVAR_VIS_PACKAGE = 3
+} objc_ivar_visibility_kind;
+
+/* 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 void objc_write_global_declarations (void);
+extern tree objc_is_class_name (tree);
+extern tree objc_is_object_ptr (tree);
+extern void objc_check_decl (tree);
+extern void objc_check_global_decl (tree);
+extern tree objc_common_type (tree, tree);
+extern bool objc_compare_types (tree, tree, int, tree);
+extern bool objc_have_common_type (tree, tree, int, tree);
+extern bool objc_diagnose_private_ivar (tree);
+extern void objc_volatilize_decl (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, tree);
+extern tree objc_build_message_expr (tree);
+extern tree objc_finish_message_expr (tree, 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 tree objc_get_interface_ivars (tree);
+extern void objc_start_class_interface (tree, tree, tree, tree);
+extern void objc_start_category_interface (tree, tree, tree, tree);
+extern void objc_start_protocol (tree, 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 (objc_ivar_visibility_kind);
+extern tree objc_build_method_signature (bool, tree, tree, tree, bool);
+extern void objc_add_method_declaration (bool, tree, tree);
+extern bool objc_start_method_definition (bool, tree, tree);
+extern void objc_finish_method_definition (tree);
+extern void objc_add_instance_variable (tree);
+extern tree objc_build_keyword_decl (tree, 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);
+extern void objc_set_method_opt (bool);
+extern void objc_finish_foreach_loop (location_t, tree, tree, tree, tree, tree);
+extern bool objc_method_decl (enum tree_code);
+extern void objc_add_property_declaration (location_t, tree, bool, bool, bool,
+ bool, bool, bool, tree, tree);
+extern tree objc_maybe_build_component_ref (tree, tree);
+extern tree objc_build_class_component_ref (tree, tree);
+extern tree objc_maybe_build_modify_expr (tree, tree);
+extern tree objc_build_incr_expr_for_property_ref (location_t, enum tree_code,
+ tree, tree);
+extern void objc_add_synthesize_declaration (location_t, tree);
+extern void objc_add_dynamic_declaration (location_t, tree);
+extern const char * objc_maybe_printable_name (tree, int);
+extern bool objc_is_property_ref (tree);
+extern bool objc_string_ref_type_p (tree);
+extern void objc_check_format_arg (tree, tree);
+extern void objc_finish_function (void);
+extern void objc_maybe_warn_exceptions (location_t);
+
+/* 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 *);
+
+#endif /* ! GCC_C_COMMON_OBJC_H */
diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c
new file mode 100644
index 000000000..b9b144896
--- /dev/null
+++ b/gcc/c-family/c-omp.c
@@ -0,0 +1,530 @@
+/* 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 <rth@redhat.com>,
+ Diego Novillo <dnovillo@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "c-common.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 000000000..8d6e6e7e2
--- /dev/null
+++ b/gcc/c-family/c-opts.c
@@ -0,0 +1,1498 @@
+/* C/ObjC/C++ command line option handling.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ 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
+<http://www.gnu.org/licenses/>. */
+
+#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. */
+#include "tm_p.h" /* For C_COMMON_OVERRIDE_OPTIONS. */
+
+#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 c_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;
+
+
+extern const unsigned int
+c_family_lang_mask = (CL_C | CL_CXX | CL_ObjC | CL_ObjCXX);
+
+/* 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++;
+}
+
+/* Return language mask for option parsing. */
+unsigned int
+c_common_option_lang_mask (void)
+{
+ static const unsigned int lang_flags[] = {CL_C, CL_ObjC, CL_CXX, CL_ObjCXX};
+
+ return lang_flags[c_language];
+}
+
+/* Common diagnostics initialization. */
+void
+c_common_initialize_diagnostics (diagnostic_context *context)
+{
+ /* 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 (context) = 80;
+ /* By default, emit location information once for every
+ diagnostic message. */
+ diagnostic_prefixing_rule (context) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
+ }
+
+ context->opt_permissive = OPT_fpermissive;
+}
+
+/* Whether options from all C-family languages should be accepted
+ quietly. */
+static bool accept_all_c_family_options = false;
+
+/* Return whether to complain about a wrong-language option. */
+bool
+c_common_complain_wrong_lang_p (const struct cl_option *option)
+{
+ if (accept_all_c_family_options
+ && (option->flags & c_family_lang_mask))
+ return false;
+
+ return true;
+}
+
+/* Initialize options structure OPTS. */
+void
+c_common_init_options_struct (struct gcc_options *opts)
+{
+ opts->x_flag_exceptions = c_dialect_cxx ();
+ opts->x_warn_pointer_arith = c_dialect_cxx ();
+ opts->x_warn_write_strings = c_dialect_cxx ();
+ opts->x_flag_warn_unused_result = true;
+
+ /* By default, C99-like requirements for complex multiply and divide. */
+ opts->x_flag_complex_method = 2;
+}
+
+/* Common initialization before calling option handlers. */
+void
+c_common_init_options (unsigned int decoded_options_count,
+ struct cl_decoded_option *decoded_options)
+{
+ unsigned int i;
+ struct cpp_callbacks *cb;
+
+ 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;
+
+ deferred_opts = XNEWVEC (struct deferred_opt, decoded_options_count);
+
+ 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 < decoded_options_count; i++)
+ if (decoded_options[i].opt_index == OPT_lang_asm)
+ {
+ accept_all_c_family_options = true;
+ break;
+ }
+ }
+}
+
+/* Handle switch SCODE with argument ARG. VALUE is true, unless no-
+ form of an -f or -W option was given. Returns false if the switch was
+ invalid, true if valid. Use HANDLERS in recursive handle_option calls. */
+bool
+c_common_handle_option (size_t scode, const char *arg, int value,
+ int kind, location_t loc,
+ const struct cl_option_handlers *handlers)
+{
+ const struct cl_option *option = &cl_options[scode];
+ enum opt_code code = (enum opt_code) scode;
+ bool result = true;
+
+ /* 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 = false;
+ break;
+ }
+ result = false;
+ 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_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_U:
+ defer_opt (code, arg);
+ break;
+
+ case OPT_Wall:
+ warn_unused = value;
+ set_Wformat (value);
+ handle_generated_option (&global_options, &global_options_set,
+ OPT_Wimplicit, NULL, value,
+ c_family_lang_mask, kind, loc,
+ handlers, global_dc);
+ 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 (&global_options, 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:
+ 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->cpp_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_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_generated_option (&global_options, &global_options_set,
+ OPT_Wimplicit_int, NULL, value,
+ c_family_lang_mask, kind, loc, handlers,
+ global_dc);
+ if (warn_implicit_function_declaration == -1)
+ handle_generated_option (&global_options, &global_options_set,
+ OPT_Wimplicit_function_declaration, NULL,
+ value, c_family_lang_mask, kind, loc,
+ handlers, global_dc);
+ break;
+
+ case OPT_Winvalid_pch:
+ cpp_opts->warn_invalid_pch = value;
+ break;
+
+ case OPT_Wlong_long:
+ cpp_opts->cpp_warn_long_long = 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 (kind == DK_ERROR)
+ {
+ gcc_assert (!arg);
+ inform (input_location, "-Werror=normalized=: set -Wnormalized=nfc");
+ cpp_opts->warn_normalize = normalized_C;
+ }
+ else
+ {
+ 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_Wtraditional:
+ cpp_opts->cpp_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;
+ }
+ warning (0, "switch %qs is no longer supported", option->opt_text);
+ break;
+
+ case OPT_fbuiltin_:
+ if (value)
+ result = false;
+ 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_fconstant_string_class_:
+ constant_string_class_name = arg;
+ break;
+
+ case OPT_fextended_identifiers:
+ cpp_opts->extended_identifiers = value;
+ break;
+
+ case OPT_fgnu_runtime:
+ flag_next_runtime = !value;
+ break;
+
+ case OPT_fnext_runtime:
+ flag_next_runtime = value;
+ break;
+
+ case OPT_foperator_names:
+ cpp_opts->operator_names = 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_frepo:
+ flag_use_repository = value;
+ if (value)
+ flag_implicit_templates = 0;
+ 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_:
+ max_tinst_depth = value;
+ break;
+
+ case OPT_fvisibility_inlines_hidden:
+ visibility_options.inlines_hidden = value;
+ break;
+
+ case OPT_femit_struct_debug_baseonly:
+ set_struct_debug_option (&global_options, loc, "base");
+ break;
+
+ case OPT_femit_struct_debug_reduced:
+ set_struct_debug_option (&global_options, loc,
+ "dir:ord:sys,dir:gen:any,ind:base");
+ break;
+
+ case OPT_femit_struct_debug_detailed_:
+ set_struct_debug_option (&global_options, loc, 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_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->cpp_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_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_c90:
+ case OPT_std_iso9899_199409:
+ if (!preprocessing_asm_p)
+ set_std_c89 (code == OPT_std_iso9899_199409 /* c94 */, true /* ISO */);
+ break;
+
+ case OPT_std_gnu90:
+ if (!preprocessing_asm_p)
+ set_std_c89 (false /* c94 */, false /* ISO */);
+ break;
+
+ case OPT_std_c99:
+ if (!preprocessing_asm_p)
+ set_std_c99 (true /* ISO */);
+ break;
+
+ case OPT_std_gnu99:
+ 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_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 ();
+
+ /* When writing a PCH file, avoid reading some other PCH file,
+ because the default address space slot then can't be used
+ for the output PCH file. */
+ if (pch_file)
+ c_common_no_more_pch ();
+
+ /* 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)
+ {
+ c_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 (void)
+{
+ unsigned int i;
+
+ i = 0;
+ for (;;)
+ {
+ c_finish_options ();
+ pch_init ();
+ push_file_scope ();
+ c_parse_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;
+
+ spec = getenv ("DEPENDENCIES_OUTPUT");
+ if (spec)
+ cpp_opts->deps.style = DEPS_USER;
+ else
+ {
+ spec = getenv ("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->cpp_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
+c_finish_options (void)
+{
+ if (!cpp_opts->preprocessed)
+ {
+ size_t i;
+
+ cb_file_change (parse_in,
+ linemap_add (line_table, LC_RENAME, 0,
+ _("<built-in>"), 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->cpp_pedantic && !cpp_opts->c99);
+
+ cb_file_change (parse_in,
+ linemap_add (line_table, LC_RENAME, 0,
+ _("<command-line>"), 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 <command line>. */
+ 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 000000000..b429d9d77
--- /dev/null
+++ b/gcc/c-family/c-pch.c
@@ -0,0 +1,512 @@
+/* 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
+<http://www.gnu.org/licenses/>. */
+
+#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 "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. */
+
+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 000000000..5eca03fc0
--- /dev/null
+++ b/gcc/c-family/c-ppoutput.c
@@ -0,0 +1,630 @@
+/* Preprocess only, using cpplib.
+ Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007,
+ 2008, 2009, 2010 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
+ <http://www.gnu.org/licenses/>. */
+
+#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. */
+ const char *src_file; /* Current source file. */
+} 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;
+ print.src_file = "";
+}
+
+/* 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
+ && (flag_no_line_commands || strcmp (map->to_file, print.src_file) == 0))
+ {
+ 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);
+ print.src_file = map->to_file;
+
+ /* 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 000000000..fa8771ec0
--- /dev/null
+++ b/gcc/c-family/c-pragma.c
@@ -0,0 +1,1324 @@
+/* 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, 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
+<http://www.gnu.org/licenses/>. */
+
+#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 "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;
+
+static void handle_pragma_pack (cpp_reader *);
+
+/* If we have a "global" #pragma pack(<n>) in effect when the first
+ #pragma pack(push,<n>) 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_alloc_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(<n>) 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;
+}
+
+/* #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][, <n>])%> - 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;
+ }
+}
+
+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;
+
+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_EACH_VEC_ELT (pending_weak, pending_weaks, i, pe)
+ 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_EACH_VEC_ELT (pending_weak, pending_weaks, i, pe)
+ {
+ 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;
+ }
+}
+
+/* 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.) */
+
+typedef struct GTY(()) pending_redefinition_d {
+ tree oldname;
+ tree newname;
+} pending_redefinition;
+
+DEF_VEC_O(pending_redefinition);
+DEF_VEC_ALLOC_O(pending_redefinition,gc);
+
+static GTY(()) VEC(pending_redefinition,gc) *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)
+{
+ unsigned ix;
+ pending_redefinition *p;
+
+ FOR_EACH_VEC_ELT (pending_redefinition, pending_redefine_extname, ix, p)
+ if (oldname == p->oldname)
+ {
+ if (p->newname != newname)
+ warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to "
+ "conflict with previous #pragma redefine_extname");
+ return;
+ }
+
+ p = VEC_safe_push (pending_redefinition, gc, pending_redefine_extname, NULL);
+ p->oldname = oldname;
+ p->newname = newname;
+}
+
+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)
+{
+ unsigned ix;
+ pending_redefinition *p;
+
+ /* 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_EACH_VEC_ELT (pending_redefinition, pending_redefine_extname, ix, p)
+ if (DECL_NAME (decl) == p->oldname)
+ {
+ /* Only warn if there is a conflict. */
+ if (strcmp (IDENTIFIER_POINTER (p->newname), oldname))
+ warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to "
+ "conflict with previous rename");
+
+ VEC_unordered_remove (pending_redefinition,
+ pending_redefine_extname, ix);
+ break;
+ }
+ return 0;
+ }
+
+ /* Find out if we have a pending #pragma redefine_extname. */
+ FOR_EACH_VEC_ELT (pending_redefinition, pending_redefine_extname, ix, p)
+ if (DECL_NAME (decl) == p->oldname)
+ {
+ tree newname = p->newname;
+ VEC_unordered_remove (pending_redefinition,
+ pending_redefine_extname, ix);
+
+ /* 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;
+}
+
+
+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%>");
+}
+
+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;
+ struct cl_option_handlers handlers;
+
+ 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 if (strcmp (kind_string, "push") == 0)
+ {
+ diagnostic_push_diagnostics (global_dc, input_location);
+ return;
+ }
+ else if (strcmp (kind_string, "pop") == 0)
+ {
+ diagnostic_pop_diagnostics (global_dc, input_location);
+ return;
+ }
+ else
+ GCC_BAD ("expected [error|warning|ignored|push|pop] 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);
+ set_default_handlers (&handlers);
+ for (option_index = 0; option_index < cl_options_count; option_index++)
+ if (strcmp (cl_options[option_index].opt_text, option_string) == 0)
+ {
+ control_warning_option (option_index, (int) kind, kind != DK_IGNORED,
+ input_location, c_family_lang_mask, &handlers,
+ &global_options, &global_options_set,
+ global_dc);
+ 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_alloc_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 (&global_options,
+ 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 (&global_options,
+ 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 %<pragma %s%>, 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_WITH_EXPANSION
+ c_register_pragma_with_expansion (0, "pack", handle_pragma_pack);
+#else
+ c_register_pragma (0, "pack", handle_pragma_pack);
+#endif
+ c_register_pragma (0, "weak", handle_pragma_weak);
+ c_register_pragma ("GCC", "visibility", handle_pragma_visibility);
+
+ 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 000000000..cec9cd176
--- /dev/null
+++ b/gcc/c-family/c-pragma.h
@@ -0,0 +1,116 @@
+/* Pragma related interfaces.
+ Copyright (C) 1995, 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
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_C_PRAGMA_H
+#define GCC_C_PRAGMA_H
+
+#include "cpplib.h" /* 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;
+
+/* It's safe to always leave visibility pragma enabled as if
+ visibility is not supported on the host OS platform the
+ statements are ignored. */
+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 000000000..843e7a422
--- /dev/null
+++ b/gcc/c-family/c-pretty-print.c
@@ -0,0 +1,2317 @@
+/* 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 <gdr@integrable-solutions.net>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#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_("<type-error>"));
+ 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_("<unnamed-unsigned:")
+ : M_("<unnamed-signed:")));
+ break;
+ case REAL_TYPE:
+ pp_string (pp, M_("<unnamed-float:"));
+ break;
+ case FIXED_POINT_TYPE:
+ pp_string (pp, M_("<unnamed-fixed:"));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ pp_decimal_int (pp, prec);
+ pp_string (pp, ">");
+ }
+ }
+ break;
+
+ case TYPE_DECL:
+ if (DECL_NAME (t))
+ pp_id_expression (pp, t);
+ else
+ pp_c_ws_string (pp, M_("<typedef-error>"));
+ 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_("<tag-error>"));
+
+ if (TYPE_NAME (t))
+ pp_id_expression (pp, TYPE_NAME (t));
+ else
+ pp_c_ws_string (pp, M_("<anonymous>"));
+ 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_("<erroneous-expression>"));
+ break;
+
+ case RESULT_DECL:
+ pp_c_ws_string (pp, M_("<return-value>"));
+ 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 MEM_REF:
+ pp_c_expression (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 MEM_REF:
+ if (TREE_CODE (TREE_OPERAND (e, 0)) == ADDR_EXPR
+ && integer_zerop (TREE_OPERAND (e, 1)))
+ pp_c_expression (pp, TREE_OPERAND (TREE_OPERAND (e, 0), 0));
+ else
+ {
+ pp_c_star (pp);
+ if (!integer_zerop (TREE_OPERAND (e, 1)))
+ {
+ pp_c_left_paren (pp);
+ if (!integer_onep (TYPE_SIZE_UNIT
+ (TREE_TYPE (TREE_TYPE (TREE_OPERAND (e, 0))))))
+ pp_c_type_cast (pp, ptr_type_node);
+ }
+ pp_c_cast_expression (pp, TREE_OPERAND (e, 0));
+ if (!integer_zerop (TREE_OPERAND (e, 1)))
+ {
+ pp_plus (pp);
+ pp_c_integer_constant (pp,
+ fold_convert (ssizetype,
+ TREE_OPERAND (e, 1)));
+ pp_c_right_paren (pp);
+ }
+ }
+ 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 MEM_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;
+
+ case C_MAYBE_CONST_EXPR:
+ pp_c_expression (pp, C_MAYBE_CONST_EXPR_EXPR (e));
+ 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, "<U%4x>", ((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 000000000..f0daa4aef
--- /dev/null
+++ b/gcc/c-family/c-pretty-print.h
@@ -0,0 +1,214 @@
+/* Various declarations for the C and C++ pretty-printers.
+ Copyright (C) 2002, 2003, 2004, 2007, 2009, 2010
+ Free Software Foundation, Inc.
+ Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#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 000000000..0f9f51e06
--- /dev/null
+++ b/gcc/c-family/c-semantics.c
@@ -0,0 +1,173 @@
+/* This file contains subroutine used by the C front-end to construct GENERIC.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+ 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
+<http://www.gnu.org/licenses/>. */
+
+#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"
+#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);
+}
+
+/* Build a REALPART_EXPR or IMAGPART_EXPR, according to CODE, from ARG. */
+
+tree
+build_real_imag_expr (location_t location, enum tree_code code, tree arg)
+{
+ tree ret;
+ tree arg_type = TREE_TYPE (arg);
+
+ gcc_assert (code == REALPART_EXPR || code == IMAGPART_EXPR);
+
+ if (TREE_CODE (arg_type) == COMPLEX_TYPE)
+ {
+ ret = build1 (code, TREE_TYPE (TREE_TYPE (arg)), arg);
+ SET_EXPR_LOCATION (ret, location);
+ }
+ else if (INTEGRAL_TYPE_P (arg_type) || SCALAR_FLOAT_TYPE_P (arg_type))
+ {
+ ret = (code == REALPART_EXPR
+ ? arg
+ : omit_one_operand_loc (location, arg_type,
+ integer_zero_node, arg));
+ }
+ else
+ {
+ error_at (location, "wrong type argument to %s",
+ code == REALPART_EXPR ? "__real" : "__imag");
+ ret = error_mark_node;
+ }
+
+ return ret;
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
new file mode 100644
index 000000000..4c4727f31
--- /dev/null
+++ b/gcc/c-family/c.opt
@@ -0,0 +1,1243 @@
+; Options for the C, ObjC, C++ and ObjC++ front ends.
+; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+; 2011 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
+; <http://www.gnu.org/licenses/>.
+
+; 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++
+
+-all-warnings
+C ObjC C++ ObjC++ Warning Alias(Wall)
+
+-ansi
+C ObjC C++ ObjC++ Alias(ansi)
+
+-assert
+C ObjC C++ ObjC++ Separate Alias(A) MissingArgError(assertion missing after %qs)
+
+-assert=
+C ObjC C++ ObjC++ Joined Alias(A) MissingArgError(assertion missing after %qs)
+
+-comments
+C ObjC C++ ObjC++ Alias(C)
+
+-comments-in-macros
+C ObjC C++ ObjC++ Alias(CC)
+
+-define-macro
+C ObjC C++ ObjC++ Separate Alias(D) MissingArgError(macro name missing after %qs)
+
+-define-macro=
+C ObjC C++ ObjC++ Joined Alias(D) MissingArgError(macro name missing after %qs)
+
+-dependencies
+C ObjC C++ ObjC++ Alias(M)
+
+-dump
+C ObjC C++ ObjC++ Separate Alias(d)
+
+-dump=
+C ObjC C++ ObjC++ Joined Alias(d)
+
+-imacros
+C ObjC C++ ObjC++ Separate Alias(imacros) MissingArgError(missing filename after %qs)
+
+-imacros=
+C ObjC C++ ObjC++ Joined Alias(imacros) MissingArgError(missing filename after %qs)
+
+-include
+C ObjC C++ ObjC++ Separate Alias(include) MissingArgError(missing filename after %qs)
+
+-include=
+C ObjC C++ ObjC++ Joined Alias(include) MissingArgError(missing filename after %qs)
+
+-include-barrier
+C ObjC C++ ObjC++ Alias(I, -)
+
+-include-directory
+C ObjC C++ ObjC++ Separate Alias(I) MissingArgError(missing path after %qs)
+
+-include-directory=
+C ObjC C++ ObjC++ Joined Alias(I) MissingArgError(missing path after %qs)
+
+-include-directory-after
+C ObjC C++ ObjC++ Separate Alias(idirafter) MissingArgError(missing path after %qs)
+
+-include-directory-after=
+C ObjC C++ ObjC++ Joined Alias(idirafter) MissingArgError(missing path after %qs)
+
+-include-prefix
+C ObjC C++ ObjC++ Separate Alias(iprefix)
+
+-include-prefix=
+C ObjC C++ ObjC++ JoinedOrMissing Alias(iprefix)
+
+-include-with-prefix
+C ObjC C++ ObjC++ Separate Alias(iwithprefix)
+
+-include-with-prefix=
+C ObjC C++ ObjC++ JoinedOrMissing Alias(iwithprefix)
+
+-include-with-prefix-after
+C ObjC C++ ObjC++ Separate Alias(iwithprefix)
+
+-include-with-prefix-after=
+C ObjC C++ ObjC++ JoinedOrMissing Alias(iwithprefix)
+
+-include-with-prefix-before
+C ObjC C++ ObjC++ Separate Alias(iwithprefixbefore)
+
+-include-with-prefix-before=
+C ObjC C++ ObjC++ JoinedOrMissing Alias(iwithprefixbefore)
+
+-no-integrated-cpp
+Driver Alias(no-integrated-cpp)
+
+-no-line-commands
+C ObjC C++ ObjC++ Alias(P)
+
+-no-standard-includes
+C ObjC C++ ObjC++ Alias(nostdinc)
+
+-no-warnings
+C ObjC C++ ObjC++ Alias(w)
+
+-output
+C ObjC C++ ObjC++ Separate Alias(o)
+
+-output=
+C ObjC C++ ObjC++ Joined Alias(o)
+
+-output-pch=
+C ObjC C++ ObjC++ Joined Separate
+
+-pedantic
+C ObjC C++ ObjC++ Alias(pedantic)
+
+-pedantic-errors
+C ObjC C++ ObjC++ Alias(pedantic-errors)
+
+-preprocess
+C ObjC C++ ObjC++ Undocumented Alias(E)
+
+-print-missing-file-dependencies
+C ObjC C++ ObjC++ Alias(MG)
+
+-trace-includes
+C ObjC C++ ObjC++ Alias(H)
+
+-traditional
+Driver Alias(traditional)
+
+-traditional-cpp
+C ObjC C++ ObjC++ Alias(traditional-cpp)
+
+-trigraphs
+C ObjC C++ ObjC++ Alias(trigraphs)
+
+-undefine-macro
+C ObjC C++ ObjC++ Separate Alias(U) MissingArgError(macro name missing after %qs)
+
+-undefine-macro=
+C ObjC C++ ObjC++ Joined Alias(U) MissingArgError(macro name missing after %qs)
+
+-user-dependencies
+C ObjC C++ ObjC++ Alias(MM)
+
+-verbose
+Common C ObjC C++ ObjC++ Alias(v)
+
+-write-dependencies
+C ObjC C++ ObjC++ NoDriverArg Separate Alias(MD) MissingArgError(missing filename after %qs)
+
+-write-user-dependencies
+C ObjC C++ ObjC++ NoDriverArg Separate Alias(MMD) MissingArgError(missing filename after %qs)
+
+A
+C ObjC C++ ObjC++ Joined Separate MissingArgError(assertion missing after %qs)
+-A<question>=<answer> Assert the <answer> to <question>. Putting '-' before <question> disables the <answer> to <question>
+
+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 MissingArgError(macro name missing after %qs)
+-D<macro>[=<val>] Define a <macro> with <val> as its value. If just <macro> is given, <val> is taken to be 1
+
+E
+C ObjC C++ ObjC++ Undocumented Var(flag_preprocess_only)
+
+F
+C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs)
+-F <dir> Add <dir> 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 MissingArgError(missing path after %qs)
+-I <dir> Add <dir> to the end of the main include path
+
+M
+C ObjC C++ ObjC++
+Generate make dependencies
+
+MD
+C ObjC C++ ObjC++ NoDriverArg Separate MissingArgError(missing filename after %qs)
+Generate make dependencies and compile
+
+MF
+C ObjC C++ ObjC++ Joined Separate MissingArgError(missing filename after %qs)
+-MF <file> 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++ NoDriverArg Separate MissingArgError(missing filename after %qs)
+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 MissingArgError(missing makefile target after %qs)
+-MQ <target> Add a MAKE-quoted target
+
+MT
+C ObjC C++ ObjC++ Joined Separate MissingArgError(missing makefile target after %qs)
+-MT <target> Add an unquoted target
+
+P
+C ObjC C++ ObjC++
+Do not generate #line directives
+
+U
+C ObjC C++ ObjC++ Joined Separate MissingArgError(macro name missing after %qs)
+-U<macro> Undefine <macro>
+
+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 Alias(Wcomment)
+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 Alias(Werror=, implicit-function-declaration)
+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
+
+Wdouble-promotion
+C ObjC C++ ObjC++ Var(warn_double_promotion) Warning
+Warn about implicit conversions from \"float\" to \"double\"
+
+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 Ignore
+
+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
+
+Wnoexcept
+C++ ObjC++ Var(warn_noexcept) Warning
+Warn when a noexcept expression evaluates to false even though the expression can't actually throw
+
+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=<id|nfc|nfkc> 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
+
+Wproperty-assign-default
+ObjC ObjC++ Var(warn_property_assign_default) Init(1) Warning
+Warn if a property for an Objective-C object has no assign semantics specified
+
+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 Var(warn_strict_null_sentinel)
+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++ Var(flag_access_control) Init(1)
+Enforce class member access control semantics
+
+fall-virtual
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+
+falt-external-templates
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+No longer supported
+
+fasm
+C ObjC C++ ObjC++ Var(flag_no_asm, 0)
+Recognize the \"asm\" keyword
+
+fbuiltin
+C ObjC C++ ObjC++ Var(flag_no_builtin, 0)
+Recognize built-in functions
+
+fbuiltin-
+C ObjC C++ ObjC++ Joined
+
+fcheck-new
+C++ ObjC++ Var(flag_check_new)
+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++ Var(flag_conserve_space)
+Reduce the size of object files
+
+fconstant-string-class=
+ObjC ObjC++ Joined MissingArgError(no class name specified with %qs)
+-fconst-string-class=<name> Use class <name> for constant strings
+
+fconstexpr-depth=
+C++ ObjC++ Joined RejectNegative UInteger Var(max_constexpr_depth) Init(512)
+-fconstexpr-depth=<number> Specify maximum constexpr recursion depth
+
+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++ Ignore
+Does nothing. Preserved for backward compatibility.
+
+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++ Var(flag_elide_constructors) Init(1)
+
+fenforce-eh-specs
+C++ ObjC++ Var(flag_enforce_eh_specs) Init(1)
+Generate code to check exception specifications
+
+fenum-int-equiv
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+
+fexec-charset=
+C ObjC C++ ObjC++ Joined RejectNegative
+-fexec-charset=<cset> Convert all strings and character constants to character set <cset>
+
+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=<cset> Specify the default character set for source files
+
+
+fexternal-templates
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+
+ffor-scope
+C++ ObjC++ Var(flag_new_for_scope) Init(1)
+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++ Var(flag_no_gnu_keywords, 0)
+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++ Ignore Warn(switch %qs is no longer supported)
+
+fhandle-exceptions
+C++ ObjC++ Optimization Alias(fexceptions) Warn({-fhandle-exceptions has been renamed -fexceptions (and is now on by default)})
+
+fhonor-std
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+
+fhosted
+C ObjC
+Assume normal C execution environment
+
+fhuge-objects
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+No longer supported
+
+fimplement-inlines
+C++ ObjC++ Var(flag_implement_inlines) Init(1)
+Export functions even if they can be inlined
+
+fimplicit-inline-templates
+C++ ObjC++ Var(flag_implicit_inline_templates) Init(1)
+Emit implicit instantiations of inline templates
+
+fimplicit-templates
+C++ ObjC++ Var(flag_implicit_templates) Init(1)
+Emit implicit instantiations of templates
+
+ffriend-injection
+C++ ObjC++ Var(flag_friend_injection)
+Inject friend functions into enclosing namespace
+
+fkeep-inline-dllexport
+C C++ ObjC ObjC++ Var(flag_keep_inline_dllexport) Init(1) Report Condition(TARGET_DLLIMPORT_DECL_ATTRIBUTES)
+Don't emit dllexported inline functions unless needed
+
+flabels-ok
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+
+flax-vector-conversions
+C ObjC C++ ObjC++ Var(flag_lax_vector_conversions)
+Allow implicit conversions between vectors with differing numbers of subparts and/or differing element types.
+
+fms-extensions
+C ObjC C++ ObjC++ Var(flag_ms_extensions)
+Don't warn about uses of Microsoft extensions
+
+fname-mangling-version-
+C++ ObjC++ Joined Ignore Warn(switch %qs is no longer supported)
+
+fnew-abi
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+
+fnext-runtime
+ObjC ObjC++
+Generate code for NeXT (Apple Mac OS X) runtime environment
+
+fnil-receivers
+ObjC ObjC++ Var(flag_nil_receivers) Init(1)
+Assume that receivers of Objective-C messages may be nil
+
+fnonansi-builtins
+C++ ObjC++ Var(flag_no_nonansi_builtin, 0)
+
+fnonnull-objects
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+
+fnothrow-opt
+C++ ObjC++ Optimization Var(flag_nothrow_opt)
+Treat a throw() exception specification as noexcept to improve code size
+
+fobjc-abi-version=
+ObjC ObjC++ Joined Report RejectNegative UInteger Var(flag_objc_abi)
+Specify which ABI to use for Objective-C family code and meta-data generation.
+
+; 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
+
+fobjc-nilcheck
+ObjC ObjC++ Var(flag_objc_nilcheck,1)
+Enable inline checks for nil receivers with the NeXT runtime and ABI version 2.
+
+; 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
+
+fobjc-std=objc1
+ObjC ObjC++ Var(flag_objc1_only)
+Conform to the Objective-C 1.0 language as implemented in GCC 4.0
+
+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++ Ignore
+Does nothing. Preserved for backward compatibility.
+
+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
+
+fplan9-extensions
+C ObjC Var(flag_plan9_extensions)
+Enable Plan 9 language extensions
+
+fpreprocessed
+C ObjC C++ ObjC++
+Treat the input file as already preprocessed
+
+fpretty-templates
+C++ ObjC++ Var(flag_pretty_templates) Init(1)
+-fno-pretty-templates Do not pretty-print template specializations as the template signature followed by the arguments
+
+freplace-objc-classes
+ObjC ObjC++ Var(flag_replace_objc_classes)
+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 Var(flag_rtti) Init(1)
+Generate run time type descriptor information
+
+fshort-double
+C ObjC C++ ObjC++ Optimization Var(flag_short_double)
+Use the same size for double as for float
+
+fshort-enums
+C ObjC C++ ObjC++ Optimization Var(flag_short_enums)
+Use the narrowest integer type possible for enumeration types
+
+fshort-wchar
+C ObjC C++ ObjC++ Optimization Var(flag_short_wchar)
+Force the underlying type for \"wchar_t\" to be \"unsigned short\"
+
+fsigned-bitfields
+C ObjC C++ ObjC++ Var(flag_signed_bitfields) Init(1)
+When \"signed\" or \"unsigned\" is not given make the bitfield signed
+
+fsigned-char
+C ObjC C++ ObjC++ LTO Var(flag_signed_char)
+Make \"char\" signed by default
+
+fsquangle
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+
+fstats
+C++ ObjC++ Var(flag_detailed_statistics)
+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++ Ignore Warn(switch %qs is no longer supported)
+
+ftabstop=
+C ObjC C++ ObjC++ Joined RejectNegative UInteger
+-ftabstop=<number> Distance between tab stops for column reporting
+
+ftemplate-depth-
+C++ ObjC++ Joined RejectNegative Undocumented Alias(ftemplate-depth=)
+
+ftemplate-depth=
+C++ ObjC++ Joined RejectNegative UInteger
+-ftemplate-depth=<number> Specify maximum template instantiation depth
+
+fthis-is-variable
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+
+fthreadsafe-statics
+C++ ObjC++ Optimization Var(flag_threadsafe_statics) Init(1)
+-fno-threadsafe-statics Do not generate thread-safe code for initializing local statics
+
+funsigned-bitfields
+C ObjC C++ ObjC++ Var(flag_signed_bitfields, 0)
+When \"signed\" or \"unsigned\" is not given make the bitfield unsigned
+
+funsigned-char
+C ObjC C++ ObjC++ LTO Var(flag_signed_char, 0)
+Make \"char\" unsigned by default
+
+fuse-cxa-atexit
+C++ ObjC++ Var(flag_use_cxa_atexit) Init(DEFAULT_USE_CXA_ATEXIT)
+Use __cxa_atexit to register destructors
+
+fuse-cxa-get-exception-ptr
+C++ ObjC++ Var(flag_use_cxa_get_exception_ptr) Init(2)
+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++ Ignore Warn(switch %qs is no longer supported)
+No longer supported
+
+fvtable-thunks
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+No longer supported
+
+fweak
+C++ ObjC++ Var(flag_weak) Init(1)
+Emit common-like symbols as weak symbols
+
+fwide-exec-charset=
+C ObjC C++ ObjC++ Joined RejectNegative
+-fwide-exec-charset=<cset> Convert all wide strings and character constants to character set <cset>
+
+fworking-directory
+C ObjC C++ ObjC++ Var(flag_working_directory) Init(-1)
+Generate a #line directive pointing at the current working directory
+
+fxref
+C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+No longer supported
+
+fzero-link
+ObjC ObjC++ Var(flag_zero_link)
+Generate lazy class lookup (via objc_getClass()) for use in Zero-Link mode
+
+gen-decls
+ObjC ObjC++ Var(flag_gen_declaration)
+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=<spec-list> Detailed reduced debug info for structs
+
+idirafter
+C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs)
+-idirafter <dir> Add <dir> to the end of the system include path
+
+imacros
+C ObjC C++ ObjC++ Joined Separate MissingArgError(missing filename after %qs)
+-imacros <file> Accept definition of macros in <file>
+
+imultilib
+C ObjC C++ ObjC++ Joined Separate
+-imultilib <dir> Set <dir> to be the multilib include subdirectory
+
+include
+C ObjC C++ ObjC++ Joined Separate MissingArgError(missing filename after %qs)
+-include <file> Include the contents of <file> before other files
+
+iprefix
+C ObjC C++ ObjC++ Joined Separate
+-iprefix <path> Specify <path> as a prefix for next two options
+
+isysroot
+C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs)
+-isysroot <dir> Set <dir> to be the system root directory
+
+isystem
+C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs)
+-isystem <dir> Add <dir> to the start of the system include path
+
+iquote
+C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs)
+-iquote <dir> Add <dir> to the end of the quote include path
+
+iwithprefix
+C ObjC C++ ObjC++ Joined Separate
+-iwithprefix <dir> Add <dir> to the end of the system include path
+
+iwithprefixbefore
+C ObjC C++ ObjC++ Joined Separate
+-iwithprefixbefore <dir> Add <dir> to the end of the main include path
+
+lang-asm
+C Undocumented RejectDriver
+
+no-integrated-cpp
+Driver
+
+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
+
+remap
+C ObjC C++ ObjC++
+Remap file names when including files
+
+std=c++98
+C++ ObjC++
+Conform to the ISO 1998 C++ standard revised by the 2003 technical corrigendum
+
+std=c++03
+C++ ObjC++ Alias(std=c++98)
+Conform to the ISO 1998 C++ standard revised by the 2003 technical corrigendum
+
+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 Alias(std=c90)
+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 Alias(std=c99)
+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 Alias(std=gnu90)
+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 Alias(std=gnu99)
+Deprecated in favor of -std=gnu99
+
+std=iso9899:1990
+C ObjC Alias(std=c90)
+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 Alias(std=c99)
+Conform to the ISO 1999 C standard
+
+std=iso9899:199x
+C ObjC Alias(std=c99)
+Deprecated in favor of -std=iso9899:1999
+
+traditional
+Driver
+
+traditional-cpp
+C ObjC C++ ObjC++
+Enable traditional preprocessing
+
+trigraphs
+C ObjC C++ ObjC++
+-trigraphs Support ISO C trigraphs
+
+undef
+C ObjC C++ ObjC++ Var(flag_undef)
+Do not predefine system-specific and GCC-specific macros
+
+v
+C ObjC C++ ObjC++
+; Documented in common.opt
+
+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 000000000..e3aa98d26
--- /dev/null
+++ b/gcc/c-family/stub-objc.c
@@ -0,0 +1,462 @@
+/* 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, 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
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "c-common.h"
+#include "c-objc.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;
+}
+
+bool objc_diagnose_private_ivar (tree ARG_UNUSED (arg))
+{
+ return false;
+}
+
+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))
+{
+}
+
+void
+objc_check_global_decl (tree ARG_UNUSED (decl))
+{
+}
+
+tree
+objc_common_type (tree ARG_UNUSED (type1), tree ARG_UNUSED (type2))
+{
+ return 0;
+}
+
+bool
+objc_compare_types (tree ARG_UNUSED (ltyp), tree ARG_UNUSED (rtyp),
+ int ARG_UNUSED (argno), tree ARG_UNUSED (callee))
+{
+ return false;
+}
+
+bool
+objc_have_common_type (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))
+{
+}
+
+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), tree ARG_UNUSED (attributes))
+{
+}
+
+void
+objc_start_protocol (tree ARG_UNUSED (proto),
+ tree ARG_UNUSED (protorefs),
+ tree ARG_UNUSED (attribs))
+{
+}
+
+void
+objc_set_method_opt (bool ARG_UNUSED (optional))
+{
+}
+
+void
+objc_start_class_interface (tree ARG_UNUSED (name),
+ tree ARG_UNUSED (super),
+ tree ARG_UNUSED (protos),
+ tree ARG_UNUSED (attribs))
+{
+}
+
+void
+objc_start_category_interface (tree ARG_UNUSED (name),
+ tree ARG_UNUSED (categ),
+ tree ARG_UNUSED (protos),
+ tree ARG_UNUSED (attribs))
+{
+}
+
+void
+objc_continue_interface (void)
+{
+}
+
+void
+objc_finish_interface (void)
+{
+}
+
+void
+objc_add_instance_variable (tree ARG_UNUSED (decl))
+{
+}
+
+void
+objc_set_visibility (objc_ivar_visibility_kind ARG_UNUSED (vis))
+{
+}
+
+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 (bool ARG_UNUSED (is_class_method),
+ tree ARG_UNUSED (signature),
+ tree ARG_UNUSED (attributes))
+{
+}
+
+bool
+objc_start_method_definition (bool ARG_UNUSED (is_class_method),
+ tree ARG_UNUSED (signature),
+ tree ARG_UNUSED (attributes))
+{
+ return true;
+}
+
+void
+objc_finish_method_definition (tree ARG_UNUSED (fndecl))
+{
+}
+
+bool
+objc_method_decl (enum tree_code ARG_UNUSED(opcode))
+{
+ return false;
+}
+
+tree
+objc_build_keyword_decl (tree ARG_UNUSED (selector),
+ tree ARG_UNUSED (type),
+ tree ARG_UNUSED (identifier),
+ tree ARG_UNUSED (attributes))
+{
+ return 0;
+}
+
+tree
+objc_build_method_signature (bool ARG_UNUSED (is_class_method),
+ 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_interface_ivars (tree ARG_UNUSED (fieldlist))
+{
+ 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;
+}
+
+void
+objc_add_property_declaration (location_t ARG_UNUSED (location),
+ tree ARG_UNUSED (decl),
+ bool ARG_UNUSED (parsed_property_readonly),
+ bool ARG_UNUSED (parsed_property_readwrite),
+ bool ARG_UNUSED (parsed_property_assign),
+ bool ARG_UNUSED (parsed_property_retain),
+ bool ARG_UNUSED (parsed_property_copy),
+ bool ARG_UNUSED (parsed_property_nonatomic),
+ tree ARG_UNUSED (parsed_property_getter_ident),
+ tree ARG_UNUSED (parsed_property_setter_ident))
+{
+}
+
+bool
+objc_is_property_ref (tree ARG_UNUSED (node))
+{
+ return 0;
+}
+
+tree
+objc_maybe_build_component_ref (tree ARG_UNUSED (datum), tree ARG_UNUSED (component))
+{
+ return 0;
+}
+
+tree
+objc_build_class_component_ref (tree ARG_UNUSED (datum), tree ARG_UNUSED (component))
+{
+ return 0;
+}
+
+tree
+objc_maybe_build_modify_expr (tree ARG_UNUSED (lhs), tree ARG_UNUSED (rhs))
+{
+ return 0;
+}
+
+tree
+objc_build_incr_expr_for_property_ref (location_t ARG_UNUSED (location),
+ enum tree_code ARG_UNUSED (code),
+ tree ARG_UNUSED (argument),
+ tree ARG_UNUSED (increment))
+{
+ return 0;
+}
+
+void
+objc_add_synthesize_declaration (location_t ARG_UNUSED (start_locus),
+ tree ARG_UNUSED (property_and_ivar_list))
+{
+}
+
+void
+objc_add_dynamic_declaration (location_t ARG_UNUSED (start_locus),
+ tree ARG_UNUSED (property_list))
+{
+}
+
+const char *
+objc_maybe_printable_name (tree ARG_UNUSED (decl),
+ int ARG_UNUSED (v))
+{
+ return NULL;
+}
+
+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;
+}
+
+void
+objc_finish_foreach_loop (location_t ARG_UNUSED (location), tree ARG_UNUSED (object_expression),
+ tree ARG_UNUSED (collection_expression), tree ARG_UNUSED (for_body),
+ tree ARG_UNUSED (break_label), tree ARG_UNUSED (continue_label))
+{
+ return;
+}
+
+void
+objc_write_global_declarations (void)
+{
+}
+
+bool
+objc_string_ref_type_p (tree ARG_UNUSED (strp))
+{
+ return false;
+}
+
+void
+objc_check_format_arg (tree ARG_UNUSED (format_arg),
+ tree ARG_UNUSED (args_list))
+{
+}
+
+void
+objc_finish_function (void)
+{
+}
+
+void
+objc_maybe_warn_exceptions (location_t ARG_UNUSED (loc))
+{
+}