diff options
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/ChangeLog | 1066 | ||||
-rw-r--r-- | gcc/c-family/c-ada-spec.c | 3330 | ||||
-rw-r--r-- | gcc/c-family/c-ada-spec.h | 41 | ||||
-rw-r--r-- | gcc/c-family/c-common.c | 9725 | ||||
-rw-r--r-- | gcc/c-family/c-common.def | 54 | ||||
-rw-r--r-- | gcc/c-family/c-common.h | 1011 | ||||
-rw-r--r-- | gcc/c-family/c-cppbuiltin.c | 1155 | ||||
-rw-r--r-- | gcc/c-family/c-dump.c | 61 | ||||
-rw-r--r-- | gcc/c-family/c-format.c | 3061 | ||||
-rw-r--r-- | gcc/c-family/c-format.h | 329 | ||||
-rw-r--r-- | gcc/c-family/c-gimplify.c | 188 | ||||
-rw-r--r-- | gcc/c-family/c-lex.c | 1089 | ||||
-rw-r--r-- | gcc/c-family/c-objc.h | 116 | ||||
-rw-r--r-- | gcc/c-family/c-omp.c | 530 | ||||
-rw-r--r-- | gcc/c-family/c-opts.c | 1498 | ||||
-rw-r--r-- | gcc/c-family/c-pch.c | 512 | ||||
-rw-r--r-- | gcc/c-family/c-ppoutput.c | 630 | ||||
-rw-r--r-- | gcc/c-family/c-pragma.c | 1324 | ||||
-rw-r--r-- | gcc/c-family/c-pragma.h | 116 | ||||
-rw-r--r-- | gcc/c-family/c-pretty-print.c | 2317 | ||||
-rw-r--r-- | gcc/c-family/c-pretty-print.h | 214 | ||||
-rw-r--r-- | gcc/c-family/c-semantics.c | 173 | ||||
-rw-r--r-- | gcc/c-family/c.opt | 1243 | ||||
-rw-r--r-- | gcc/c-family/stub-objc.c | 462 |
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 = ¯o->exp.tokens[j]; + + if (token->flags & PREV_WHITE) + (*buffer_len)++; + + if (token->flags & STRINGIFY_ARG || token->flags & PASTE_LEFT) + { + *supported = 0; + return; + } + + if (token->type == CPP_MACRO_ARG) + *buffer_len += + NODE_LEN (macro->params[token->val.macro_arg.arg_no - 1]); + else + /* Include enough extra space to handle e.g. special characters. */ + *buffer_len += (cpp_token_len (token) + 1) * 8; + } + + (*buffer_len)++; +} + +/* Dump into PP a set of MAX_ADA_MACROS MACROS (C/C++) as Ada constants when + possible. */ + +static void +print_ada_macros (pretty_printer *pp, cpp_hashnode **macros, int max_ada_macros) +{ + int j, num_macros = 0, prev_line = -1; + + for (j = 0; j < max_ada_macros; j++) + { + cpp_hashnode *node = macros [j]; + const cpp_macro *macro = node->value.macro; + unsigned i; + int supported = 1, prev_is_one = 0, buffer_len, param_len; + int is_string = 0, is_char = 0; + char *ada_name; + unsigned char *s, *params, *buffer, *buf_param, *char_one = NULL; + + macro_length (macro, &supported, &buffer_len, ¶m_len); + s = buffer = XALLOCAVEC (unsigned char, buffer_len); + params = buf_param = XALLOCAVEC (unsigned char, param_len); + + if (supported) + { + if (macro->fun_like) + { + *buf_param++ = '('; + for (i = 0; i < macro->paramc; i++) + { + cpp_hashnode *param = macro->params[i]; + + memcpy (buf_param, NODE_NAME (param), NODE_LEN (param)); + buf_param += NODE_LEN (param); + + if (i + 1 < macro->paramc) + { + *buf_param++ = ','; + *buf_param++ = ' '; + } + else if (macro->variadic) + { + supported = 0; + break; + } + } + *buf_param++ = ')'; + *buf_param = '\0'; + } + + for (i = 0; supported && i < macro->count; i++) + { + cpp_token *token = ¯o->exp.tokens[i]; + int is_one = 0; + + if (token->flags & PREV_WHITE) + *buffer++ = ' '; + + if (token->flags & STRINGIFY_ARG || token->flags & PASTE_LEFT) + { + supported = 0; + break; + } + + switch (token->type) + { + case CPP_MACRO_ARG: + { + cpp_hashnode *param = + macro->params[token->val.macro_arg.arg_no - 1]; + memcpy (buffer, NODE_NAME (param), NODE_LEN (param)); + buffer += NODE_LEN (param); + } + break; + + case CPP_EQ_EQ: *buffer++ = '='; break; + case CPP_GREATER: *buffer++ = '>'; break; + case CPP_LESS: *buffer++ = '<'; break; + case CPP_PLUS: *buffer++ = '+'; break; + case CPP_MINUS: *buffer++ = '-'; break; + case CPP_MULT: *buffer++ = '*'; break; + case CPP_DIV: *buffer++ = '/'; break; + case CPP_COMMA: *buffer++ = ','; break; + case CPP_OPEN_SQUARE: + case CPP_OPEN_PAREN: *buffer++ = '('; break; + case CPP_CLOSE_SQUARE: /* fallthrough */ + case CPP_CLOSE_PAREN: *buffer++ = ')'; break; + case CPP_DEREF: /* fallthrough */ + case CPP_SCOPE: /* fallthrough */ + case CPP_DOT: *buffer++ = '.'; break; + + case CPP_EQ: *buffer++ = ':'; *buffer++ = '='; break; + case CPP_NOT_EQ: *buffer++ = '/'; *buffer++ = '='; break; + case CPP_GREATER_EQ: *buffer++ = '>'; *buffer++ = '='; break; + case CPP_LESS_EQ: *buffer++ = '<'; *buffer++ = '='; break; + + case CPP_NOT: + *buffer++ = 'n'; *buffer++ = 'o'; *buffer++ = 't'; break; + case CPP_MOD: + *buffer++ = 'm'; *buffer++ = 'o'; *buffer++ = 'd'; break; + case CPP_AND: + *buffer++ = 'a'; *buffer++ = 'n'; *buffer++ = 'd'; break; + case CPP_OR: + *buffer++ = 'o'; *buffer++ = 'r'; break; + case CPP_XOR: + *buffer++ = 'x'; *buffer++ = 'o'; *buffer++ = 'r'; break; + case CPP_AND_AND: + strcpy ((char *) buffer, " and then "); + buffer += 10; + break; + case CPP_OR_OR: + strcpy ((char *) buffer, " or else "); + buffer += 9; + break; + + case CPP_PADDING: + *buffer++ = ' '; + is_one = prev_is_one; + break; + + case CPP_COMMENT: break; + + case CPP_WSTRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_UTF8STRING: + case CPP_WCHAR: + case CPP_CHAR16: + case CPP_CHAR32: + case CPP_NAME: + case CPP_STRING: + case CPP_NUMBER: + if (!macro->fun_like) + supported = 0; + else + buffer = cpp_spell_token (parse_in, token, buffer, false); + break; + + case CPP_CHAR: + is_char = 1; + { + unsigned chars_seen; + int ignored; + cppchar_t c; + + c = cpp_interpret_charconst (parse_in, token, + &chars_seen, &ignored); + if (c >= 32 && c <= 126) + { + *buffer++ = '\''; + *buffer++ = (char) c; + *buffer++ = '\''; + } + else + { + chars_seen = sprintf + ((char *) buffer, "Character'Val (%d)", (int) c); + buffer += chars_seen; + } + } + break; + + case CPP_LSHIFT: + if (prev_is_one) + { + /* Replace "1 << N" by "2 ** N" */ + *char_one = '2'; + *buffer++ = '*'; + *buffer++ = '*'; + break; + } + /* fallthrough */ + + case CPP_RSHIFT: + case CPP_COMPL: + case CPP_QUERY: + case CPP_EOF: + case CPP_PLUS_EQ: + case CPP_MINUS_EQ: + case CPP_MULT_EQ: + case CPP_DIV_EQ: + case CPP_MOD_EQ: + case CPP_AND_EQ: + case CPP_OR_EQ: + case CPP_XOR_EQ: + case CPP_RSHIFT_EQ: + case CPP_LSHIFT_EQ: + case CPP_PRAGMA: + case CPP_PRAGMA_EOL: + case CPP_HASH: + case CPP_PASTE: + case CPP_OPEN_BRACE: + case CPP_CLOSE_BRACE: + case CPP_SEMICOLON: + case CPP_ELLIPSIS: + case CPP_PLUS_PLUS: + case CPP_MINUS_MINUS: + case CPP_DEREF_STAR: + case CPP_DOT_STAR: + case CPP_ATSIGN: + case CPP_HEADER_NAME: + case CPP_AT_NAME: + case CPP_OTHER: + case CPP_OBJC_STRING: + default: + if (!macro->fun_like) + supported = 0; + else + buffer = cpp_spell_token (parse_in, token, buffer, false); + break; + } + + prev_is_one = is_one; + } + + if (supported) + *buffer = '\0'; + } + + if (macro->fun_like && supported) + { + char *start = (char *) s; + int is_function = 0; + + pp_string (pp, " -- arg-macro: "); + + if (*start == '(' && buffer [-1] == ')') + { + start++; + buffer [-1] = '\0'; + is_function = 1; + pp_string (pp, "function "); + } + else + { + pp_string (pp, "procedure "); + } + + pp_string (pp, (const char *) NODE_NAME (node)); + pp_space (pp); + pp_string (pp, (char *) params); + pp_newline (pp); + pp_string (pp, " -- "); + + if (is_function) + { + pp_string (pp, "return "); + pp_string (pp, start); + pp_semicolon (pp); + } + else + pp_string (pp, start); + + pp_newline (pp); + } + else if (supported) + { + expanded_location sloc = expand_location (macro->line); + + if (sloc.line != prev_line + 1) + pp_newline (pp); + + num_macros++; + prev_line = sloc.line; + + pp_string (pp, " "); + ada_name = to_ada_name ((const char *) NODE_NAME (node), NULL); + pp_string (pp, ada_name); + free (ada_name); + pp_string (pp, " : "); + + if (is_string) + pp_string (pp, "aliased constant String"); + else if (is_char) + pp_string (pp, "aliased constant Character"); + else + pp_string (pp, "constant"); + + pp_string (pp, " := "); + pp_string (pp, (char *) s); + + if (is_string) + pp_string (pp, " & ASCII.NUL"); + + pp_string (pp, "; -- "); + pp_string (pp, sloc.file); + pp_character (pp, ':'); + pp_scalar (pp, "%d", sloc.line); + pp_newline (pp); + } + else + { + pp_string (pp, " -- unsupported macro: "); + pp_string (pp, (const char *) cpp_macro_definition (parse_in, node)); + pp_newline (pp); + } + } + + if (num_macros > 0) + pp_newline (pp); +} + +static const char *source_file; +static int max_ada_macros; + +/* Callback used to count the number of relevant macros from + cpp_forall_identifiers. PFILE and V are not used. NODE is the current macro + to consider. */ + +static int +count_ada_macro (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *node, + void *v ATTRIBUTE_UNUSED) +{ + const cpp_macro *macro = node->value.macro; + + if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN) + && macro->count + && *NODE_NAME (node) != '_' + && LOCATION_FILE (macro->line) == source_file) + max_ada_macros++; + + return 1; +} + +static int store_ada_macro_index; + +/* Callback used to store relevant macros from cpp_forall_identifiers. + PFILE is not used. NODE is the current macro to store if relevant. + MACROS is an array of cpp_hashnode* used to store NODE. */ + +static int +store_ada_macro (cpp_reader *pfile ATTRIBUTE_UNUSED, + cpp_hashnode *node, void *macros) +{ + const cpp_macro *macro = node->value.macro; + + if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN) + && macro->count + && *NODE_NAME (node) != '_' + && LOCATION_FILE (macro->line) == source_file) + ((cpp_hashnode **) macros)[store_ada_macro_index++] = node; + + return 1; +} + +/* Callback used to compare (during qsort) macros. NODE1 and NODE2 are the + two macro nodes to compare. */ + +static int +compare_macro (const void *node1, const void *node2) +{ + typedef const cpp_hashnode *const_hnode; + + const_hnode n1 = *(const const_hnode *) node1; + const_hnode n2 = *(const const_hnode *) node2; + + return n1->value.macro->line - n2->value.macro->line; +} + +/* Dump in PP all relevant macros appearing in FILE. */ + +static void +dump_ada_macros (pretty_printer *pp, const char* file) +{ + cpp_hashnode **macros; + + /* Initialize file-scope variables. */ + max_ada_macros = 0; + store_ada_macro_index = 0; + source_file = file; + + /* Count all potentially relevant macros, and then sort them by sloc. */ + cpp_forall_identifiers (parse_in, count_ada_macro, NULL); + macros = XALLOCAVEC (cpp_hashnode *, max_ada_macros); + cpp_forall_identifiers (parse_in, store_ada_macro, macros); + qsort (macros, max_ada_macros, sizeof (cpp_hashnode *), compare_macro); + + print_ada_macros (pp, macros, max_ada_macros); +} + +/* Current source file being handled. */ + +static const char *source_file_base; + +/* Compare the declaration (DECL) of struct-like types based on the sloc of + their last field (if LAST is true), so that more nested types collate before + less nested ones. + If ORIG_TYPE is true, also consider struct with a DECL_ORIGINAL_TYPE. */ + +static location_t +decl_sloc_common (const_tree decl, bool last, bool orig_type) +{ + tree type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == TYPE_DECL + && (orig_type || !DECL_ORIGINAL_TYPE (decl)) + && RECORD_OR_UNION_TYPE_P (type) + && TYPE_FIELDS (type)) + { + tree f = TYPE_FIELDS (type); + + if (last) + while (TREE_CHAIN (f)) + f = TREE_CHAIN (f); + + return DECL_SOURCE_LOCATION (f); + } + else + return DECL_SOURCE_LOCATION (decl); +} + +/* Return sloc of DECL, using sloc of last field if LAST is true. */ + +location_t +decl_sloc (const_tree decl, bool last) +{ + return decl_sloc_common (decl, last, false); +} + +/* Compare two declarations (LP and RP) by their source location. */ + +static int +compare_node (const void *lp, const void *rp) +{ + const_tree lhs = *((const tree *) lp); + const_tree rhs = *((const tree *) rp); + + return decl_sloc (lhs, true) - decl_sloc (rhs, true); +} + +/* Compare two comments (LP and RP) by their source location. */ + +static int +compare_comment (const void *lp, const void *rp) +{ + const cpp_comment *lhs = (const cpp_comment *) lp; + const cpp_comment *rhs = (const cpp_comment *) rp; + + if (LOCATION_FILE (lhs->sloc) != LOCATION_FILE (rhs->sloc)) + return strcmp (LOCATION_FILE (lhs->sloc), LOCATION_FILE (rhs->sloc)); + + if (LOCATION_LINE (lhs->sloc) != LOCATION_LINE (rhs->sloc)) + return LOCATION_LINE (lhs->sloc) - LOCATION_LINE (rhs->sloc); + + if (LOCATION_COL (lhs->sloc) != LOCATION_COL (rhs->sloc)) + return LOCATION_COL (lhs->sloc) - LOCATION_COL (rhs->sloc); + + return 0; +} + +static tree *to_dump = NULL; +static int to_dump_count = 0; + +/* Collect a list of declarations from T relevant to SOURCE_FILE to be dumped + by a subsequent call to dump_ada_nodes. */ + +void +collect_ada_nodes (tree t, const char *source_file) +{ + tree n; + int i = to_dump_count; + + /* Count the likely relevant nodes. */ + for (n = t; n; n = TREE_CHAIN (n)) + if (!DECL_IS_BUILTIN (n) + && LOCATION_FILE (decl_sloc (n, false)) == source_file) + to_dump_count++; + + /* Allocate sufficient storage for all nodes. */ + to_dump = XRESIZEVEC (tree, to_dump, to_dump_count); + + /* Store the relevant nodes. */ + for (n = t; n; n = TREE_CHAIN (n)) + if (!DECL_IS_BUILTIN (n) + && LOCATION_FILE (decl_sloc (n, false)) == source_file) + to_dump [i++] = n; +} + +/* Call back for walk_tree to clear the TREE_VISITED flag of TP. */ + +static tree +unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + if (TREE_VISITED (*tp)) + TREE_VISITED (*tp) = 0; + else + *walk_subtrees = 0; + + return NULL_TREE; +} + +/* Dump nodes into PP relevant to SOURCE_FILE, as collected by previous calls + to collect_ada_nodes. CPP_CHECK is used to perform C++ queries on nodes. */ + +static void +dump_ada_nodes (pretty_printer *pp, const char *source_file, + int (*cpp_check)(tree, cpp_operation)) +{ + int i, j; + cpp_comment_table *comments; + + /* Sort the table of declarations to dump by sloc. */ + qsort (to_dump, to_dump_count, sizeof (tree), compare_node); + + /* Fetch the table of comments. */ + comments = cpp_get_comments (parse_in); + + /* Sort the comments table by sloc. */ + qsort (comments->entries, comments->count, sizeof (cpp_comment), + compare_comment); + + /* Interleave comments and declarations in line number order. */ + i = j = 0; + do + { + /* Advance j until comment j is in this file. */ + while (j != comments->count + && LOCATION_FILE (comments->entries[j].sloc) != source_file) + j++; + + /* Advance j until comment j is not a duplicate. */ + while (j < comments->count - 1 + && !compare_comment (&comments->entries[j], + &comments->entries[j + 1])) + j++; + + /* Write decls until decl i collates after comment j. */ + while (i != to_dump_count) + { + if (j == comments->count + || LOCATION_LINE (decl_sloc (to_dump[i], false)) + < LOCATION_LINE (comments->entries[j].sloc)) + print_generic_ada_decl (pp, to_dump[i++], cpp_check, source_file); + else + break; + } + + /* Write comment j, if there is one. */ + if (j != comments->count) + print_comment (pp, comments->entries[j++].comment); + + } while (i != to_dump_count || j != comments->count); + + /* Clear the TREE_VISITED flag over each subtree we've dumped. */ + for (i = 0; i < to_dump_count; i++) + walk_tree (&to_dump[i], unmark_visited_r, NULL, NULL); + + /* Finalize the to_dump table. */ + if (to_dump) + { + free (to_dump); + to_dump = NULL; + to_dump_count = 0; + } +} + +/* Print a COMMENT to the output stream PP. */ + +static void +print_comment (pretty_printer *pp, const char *comment) +{ + int len = strlen (comment); + char *str = XALLOCAVEC (char, len + 1); + char *tok; + bool extra_newline = false; + + memcpy (str, comment, len + 1); + + /* Trim C/C++ comment indicators. */ + if (str[len - 2] == '*' && str[len - 1] == '/') + { + str[len - 2] = ' '; + str[len - 1] = '\0'; + } + str += 2; + + tok = strtok (str, "\n"); + while (tok) { + pp_string (pp, " --"); + pp_string (pp, tok); + pp_newline (pp); + tok = strtok (NULL, "\n"); + + /* Leave a blank line after multi-line comments. */ + if (tok) + extra_newline = true; + } + + if (extra_newline) + pp_newline (pp); +} + +/* Prints declaration DECL to PP in Ada syntax. The current source file being + handled is SOURCE_FILE, and CPP_CHECK is used to perform C++ queries on + nodes. */ + +static void +print_generic_ada_decl (pretty_printer *pp, tree decl, + int (*cpp_check)(tree, cpp_operation), + const char* source_file) +{ + source_file_base = source_file; + + if (print_ada_declaration (pp, decl, 0, cpp_check, INDENT_INCR)) + { + pp_newline (pp); + pp_newline (pp); + } +} + +/* Dump a newline and indent BUFFER by SPC chars. */ + +static void +newline_and_indent (pretty_printer *buffer, int spc) +{ + pp_newline (buffer); + INDENT (spc); +} + +struct with { char *s; const char *in_file; int limited; }; +static struct with *withs = NULL; +static int withs_max = 4096; +static int with_len = 0; + +/* Record a "with" clause on package S (a limited with if LIMITED_ACCESS is + true), if not already done. */ + +static void +append_withs (const char *s, int limited_access) +{ + int i; + + if (withs == NULL) + withs = XNEWVEC (struct with, withs_max); + + if (with_len == withs_max) + { + withs_max *= 2; + withs = XRESIZEVEC (struct with, withs, withs_max); + } + + for (i = 0; i < with_len; i++) + if (!strcmp (s, withs [i].s) + && source_file_base == withs [i].in_file) + { + withs [i].limited &= limited_access; + return; + } + + withs [with_len].s = xstrdup (s); + withs [with_len].in_file = source_file_base; + withs [with_len].limited = limited_access; + with_len++; +} + +/* Reset "with" clauses. */ + +static void +reset_ada_withs (void) +{ + int i; + + if (!withs) + return; + + for (i = 0; i < with_len; i++) + free (withs [i].s); + free (withs); + withs = NULL; + withs_max = 4096; + with_len = 0; +} + +/* Dump "with" clauses in F. */ + +static void +dump_ada_withs (FILE *f) +{ + int i; + + fprintf (f, "with Interfaces.C; use Interfaces.C;\n"); + + for (i = 0; i < with_len; i++) + fprintf + (f, "%swith %s;\n", withs [i].limited ? "limited " : "", withs [i].s); +} + +/* Return suitable Ada package name from FILE. */ + +static char * +get_ada_package (const char *file) +{ + const char *base; + char *res; + const char *s; + int i; + + s = strstr (file, "/include/"); + if (s) + base = s + 9; + else + base = lbasename (file); + res = XNEWVEC (char, strlen (base) + 1); + + for (i = 0; *base; base++, i++) + switch (*base) + { + case '+': + res [i] = 'p'; + break; + + case '.': + case '-': + case '_': + case '/': + case '\\': + res [i] = (i == 0 || res [i - 1] == '_') ? 'u' : '_'; + break; + + default: + res [i] = *base; + break; + } + res [i] = '\0'; + + return res; +} + +static const char *ada_reserved[] = { + "abort", "abs", "abstract", "accept", "access", "aliased", "all", "and", + "array", "at", "begin", "body", "case", "constant", "declare", "delay", + "delta", "digits", "do", "else", "elsif", "end", "entry", "exception", + "exit", "for", "function", "generic", "goto", "if", "in", "interface", "is", + "limited", "loop", "mod", "new", "not", "null", "others", "out", "of", "or", + "overriding", "package", "pragma", "private", "procedure", "protected", + "raise", "range", "record", "rem", "renames", "requeue", "return", "reverse", + "select", "separate", "subtype", "synchronized", "tagged", "task", + "terminate", "then", "type", "until", "use", "when", "while", "with", "xor", + NULL}; + +/* ??? would be nice to specify this list via a config file, so that users + can create their own dictionary of conflicts. */ +static const char *c_duplicates[] = { + /* system will cause troubles with System.Address. */ + "system", + + /* The following values have other definitions with same name/other + casing. */ + "funmap", + "rl_vi_fWord", + "rl_vi_bWord", + "rl_vi_eWord", + "rl_readline_version", + "_Vx_ushort", + "USHORT", + "XLookupKeysym", + NULL}; + +/* Return a declaration tree corresponding to TYPE. */ + +static tree +get_underlying_decl (tree type) +{ + tree decl = NULL_TREE; + + if (type == NULL_TREE) + return NULL_TREE; + + /* type is a declaration. */ + if (DECL_P (type)) + decl = type; + + /* type is a typedef. */ + if (TYPE_P (type) && TYPE_NAME (type) && DECL_P (TYPE_NAME (type))) + decl = TYPE_NAME (type); + + /* TYPE_STUB_DECL has been set for type. */ + if (TYPE_P (type) && TYPE_STUB_DECL (type) && + DECL_P (TYPE_STUB_DECL (type))) + decl = TYPE_STUB_DECL (type); + + return decl; +} + +/* Return whether TYPE has static fields. */ + +static int +has_static_fields (const_tree type) +{ + tree tmp; + + for (tmp = TYPE_FIELDS (type); tmp; tmp = TREE_CHAIN (tmp)) + { + if (DECL_NAME (tmp) && TREE_STATIC (tmp)) + return true; + } + return false; +} + +/* Return whether TYPE corresponds to an Ada tagged type (has a dispatch + table). */ + +static int +is_tagged_type (const_tree type) +{ + tree tmp; + + if (!type || !RECORD_OR_UNION_TYPE_P (type)) + return false; + + for (tmp = TYPE_METHODS (type); tmp; tmp = TREE_CHAIN (tmp)) + if (DECL_VINDEX (tmp)) + return true; + + return false; +} + +/* Generate a legal Ada name from a C NAME, returning a malloc'd string. + SPACE_FOUND, if not NULL, is used to indicate whether a space was found in + NAME. */ + +static char * +to_ada_name (const char *name, int *space_found) +{ + const char **names; + int len = strlen (name); + int j, len2 = 0; + int found = false; + char *s = XNEWVEC (char, len * 2 + 5); + char c; + + if (space_found) + *space_found = false; + + /* Add trailing "c_" if name is an Ada reserved word. */ + for (names = ada_reserved; *names; names++) + if (!strcasecmp (name, *names)) + { + s [len2++] = 'c'; + s [len2++] = '_'; + found = true; + break; + } + + if (!found) + /* Add trailing "c_" if name is an potential case sensitive duplicate. */ + for (names = c_duplicates; *names; names++) + if (!strcmp (name, *names)) + { + s [len2++] = 'c'; + s [len2++] = '_'; + found = true; + break; + } + + for (j = 0; name [j] == '_'; j++) + s [len2++] = 'u'; + + if (j > 0) + s [len2++] = '_'; + else if (*name == '.' || *name == '$') + { + s [0] = 'a'; + s [1] = 'n'; + s [2] = 'o'; + s [3] = 'n'; + len2 = 4; + j++; + } + + /* Replace unsuitable characters for Ada identifiers. */ + + for (; j < len; j++) + switch (name [j]) + { + case ' ': + if (space_found) + *space_found = true; + s [len2++] = '_'; + break; + + /* ??? missing some C++ operators. */ + case '=': + s [len2++] = '_'; + + if (name [j + 1] == '=') + { + j++; + s [len2++] = 'e'; + s [len2++] = 'q'; + } + else + { + s [len2++] = 'a'; + s [len2++] = 's'; + } + break; + + case '!': + s [len2++] = '_'; + if (name [j + 1] == '=') + { + j++; + s [len2++] = 'n'; + s [len2++] = 'e'; + } + break; + + case '~': + s [len2++] = '_'; + s [len2++] = 't'; + s [len2++] = 'i'; + break; + + case '&': + case '|': + case '^': + s [len2++] = '_'; + s [len2++] = name [j] == '&' ? 'a' : name [j] == '|' ? 'o' : 'x'; + + if (name [j + 1] == '=') + { + j++; + s [len2++] = 'e'; + } + break; + + case '+': + case '-': + case '*': + case '/': + case '(': + case '[': + if (s [len2 - 1] != '_') + s [len2++] = '_'; + + switch (name [j + 1]) { + case '\0': + j++; + switch (name [j - 1]) { + case '+': s [len2++] = 'p'; break; /* + */ + case '-': s [len2++] = 'm'; break; /* - */ + case '*': s [len2++] = 't'; break; /* * */ + case '/': s [len2++] = 'd'; break; /* / */ + } + break; + + case '=': + j++; + switch (name [j - 1]) { + case '+': s [len2++] = 'p'; break; /* += */ + case '-': s [len2++] = 'm'; break; /* -= */ + case '*': s [len2++] = 't'; break; /* *= */ + case '/': s [len2++] = 'd'; break; /* /= */ + } + s [len2++] = 'a'; + break; + + case '-': /* -- */ + j++; + s [len2++] = 'm'; + s [len2++] = 'm'; + break; + + case '+': /* ++ */ + j++; + s [len2++] = 'p'; + s [len2++] = 'p'; + break; + + case ')': /* () */ + j++; + s [len2++] = 'o'; + s [len2++] = 'p'; + break; + + case ']': /* [] */ + j++; + s [len2++] = 'o'; + s [len2++] = 'b'; + break; + } + + break; + + case '<': + case '>': + c = name [j] == '<' ? 'l' : 'g'; + s [len2++] = '_'; + + switch (name [j + 1]) { + case '\0': + s [len2++] = c; + s [len2++] = 't'; + break; + case '=': + j++; + s [len2++] = c; + s [len2++] = 'e'; + break; + case '>': + j++; + s [len2++] = 's'; + s [len2++] = 'r'; + break; + case '<': + j++; + s [len2++] = 's'; + s [len2++] = 'l'; + break; + default: + break; + } + break; + + case '_': + if (len2 && s [len2 - 1] == '_') + s [len2++] = 'u'; + /* fall through */ + + default: + s [len2++] = name [j]; + } + + if (s [len2 - 1] == '_') + s [len2++] = 'u'; + + s [len2] = '\0'; + + return s; +} + +/* 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, + ¶ms, fki); + if (opnum == -1) + return; + else if (opnum > 0) + { + has_operand_number = 1; + arg_num = opnum + info->first_arg_num - 1; + } + else + has_operand_number = 0; + } + else + { + if (avoid_dollar_number (format_chars)) + return; + } + if (info->first_arg_num != 0) + { + if (params == 0) + 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, + ¶ms, fki); + if (opnum == -1) + return; + else if (opnum > 0) + { + has_operand_number = 1; + arg_num = opnum + info->first_arg_num - 1; + } + else + has_operand_number = 0; + } + else + { + if (avoid_dollar_number (format_chars)) + return; + } + if (info->first_arg_num != 0) + { + if (params == 0) + 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)) +{ +} |